<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Alejandro Roca</title>
    <description>The latest articles on DEV Community by Alejandro Roca (@alekssro).</description>
    <link>https://dev.to/alekssro</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F781238%2Fe97adc60-f33d-4c22-aa1a-f55c544f91ff.jpeg</url>
      <title>DEV Community: Alejandro Roca</title>
      <link>https://dev.to/alekssro</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/alekssro"/>
    <language>en</language>
    <item>
      <title>Cutting RDS costs in half</title>
      <dc:creator>Alejandro Roca</dc:creator>
      <pubDate>Tue, 25 Jan 2022 12:36:59 +0000</pubDate>
      <link>https://dev.to/alekssro/cutting-rds-costs-in-half-4bk8</link>
      <guid>https://dev.to/alekssro/cutting-rds-costs-in-half-4bk8</guid>
      <description>&lt;p&gt;During our AWS cost reduction efforts at BYHOURS, one story has been particularly relevant and we want to share it with anyone who might find it helpful.&lt;/p&gt;

&lt;p&gt;Our database solution of choice is &lt;a href="https://aws.amazon.com/rds/"&gt;Relational Database Service (RDS)&lt;/a&gt;, one of the oldest and best-known AWS services. It allows for rapid growth without having to worry about database scaling, as well as providing standardized configuration and ease of upgrading.&lt;/p&gt;

&lt;p&gt;However, RDS and its pricing model can be cumbersome and costly if not well optimized. Thus, RDS was our most expensive bill a month ago.&lt;/p&gt;

&lt;p&gt;The story begins, &lt;a href="https://aws.amazon.com/about-aws/whats-new/2020/10/achieve-up-to-52-percent-better-price-performance-with-amazon-rds-using-new-graviton2-instances/"&gt;prompted by AWS itself&lt;/a&gt;, we are about to switch our database instances to instances with Graviton2 processors, as it brings &lt;em&gt;"up to 52% better price/performance"&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;I will now go on to explain each of the steps we took to make this and other cost-optimizing actions, along with links to the corresponding documentation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--n4_Kx0KK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/noxc6y7dnufu5sc6sf6o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--n4_Kx0KK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/noxc6y7dnufu5sc6sf6o.png" alt="RDS cost evolution" width="380" height="291"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Upgrading MySQL 5.7 to 8.0
&lt;/h2&gt;

&lt;p&gt;Having MySQL as database engine, at least version 8.0.17 is needed to get Graviton2 instances support. So, coming from version 5.7, we had to perform a major upgrade which, as of today, is to version 8.0.23. The AWS documentation indicates the &lt;a href="https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_UpgradeDBInstance.Upgrading.html"&gt;steps to perform the upgrade&lt;/a&gt;, as well as the &lt;a href="https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_UpgradeDBInstance.MySQL.html"&gt;considerations&lt;/a&gt; to take into account. The process can take up to 1 hour and produce a &lt;strong&gt;downtime of 10-20 minutes&lt;/strong&gt;, depending on the database size. Nevertheless, there is a way to &lt;a href="https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_UpgradeDBInstance.MySQL.html#USER_UpgradeDBInstance.MySQL.ReducedDowntime"&gt;minimize the downtime&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Some documentation highlights on the process:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Minor version upgrades &lt;a href="https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_UpgradeDBInstance.MySQL.html#USER_UpgradeDBInstance.MySQL.Minor"&gt;can be set to automatic&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Major version upgrades will require an &lt;a href="https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_UpgradeDBInstance.Maintenance.html#USER_UpgradeDBInstance.OSUpgrades"&gt;OS update&lt;/a&gt; of the DB instances, if available.&lt;/li&gt;
&lt;li&gt;The upgrade process generates 2 snapshots: before and after the upgrade.&lt;/li&gt;
&lt;li&gt;To reduce the &lt;a href="https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_UpgradeDBInstance.MySQL.html#USER_UpgradeDBInstance.MySQL.ReducedDowntime"&gt;downtime in production&lt;/a&gt;, the upgrade can be done in a read replica of the production instance and when everything is ready, promote the read replica to a standalone DB instance.&lt;/li&gt;
&lt;li&gt;RDS will &lt;a href="https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_UpgradeDBInstance.MySQL.html#USER_UpgradeDBInstance.MySQL.57to80Prechecks"&gt;automatically run prechecks&lt;/a&gt; before applying a DB major engine upgrade.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After the MySQL upgrade in the staging environment, &lt;strong&gt;we identified an error that brought down the system&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SQLSTATE[HY000] [2054] Server sent charset unknown to the client. Please, report to the developers
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This error seems to be related to a &lt;a href="https://bugs.php.net/bug.php?id=74461"&gt;PHP bug&lt;/a&gt; which has been fixed in versions 7.0.19, 7.1.5 and 7.2.0 onwards, but not in version 5.6 which we use for compatibility. The bug is caused by a change in the MySQL 8.0 defaults in the &lt;code&gt;character_set_*&lt;/code&gt; parameters.&lt;/p&gt;

&lt;p&gt;The solution we found was to associate a new &lt;a href="https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_WorkingWithParamGroups.html"&gt;RDS parameter group&lt;/a&gt; changing the &lt;code&gt;character_set_server&lt;/code&gt; and &lt;code&gt;character_set_database&lt;/code&gt; parameters back to &lt;code&gt;utf8&lt;/code&gt;. Props to &lt;a class="mentioned-user" href="https://dev.to/kmoberg"&gt;@kmoberg&lt;/a&gt; : &lt;/p&gt;
&lt;div class="ltag__link"&gt;
  &lt;a href="/aws-builders" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__org__pic"&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5zuWf912--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--Z-NQNKRG--/c_fill%2Cf_auto%2Cfl_progressive%2Ch_150%2Cq_auto%2Cw_150/https://dev-to-uploads.s3.amazonaws.com/uploads/organization/profile_image/2794/88da75b6-aadd-4ea1-8083-ae2dfca8be94.png" alt="AWS Community Builders " width="150" height="150"&gt;
      &lt;div class="ltag__link__user__pic"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--syRrPzmx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--2NP8lgEa--/c_fill%2Cf_auto%2Cfl_progressive%2Ch_150%2Cq_auto%2Cw_150/https://dev-to-uploads.s3.amazonaws.com/uploads/user/profile_image/561262/0b05a9fb-4ce1-4597-8ec3-6be326f61459.png" alt="" width="150" height="150"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/aws-builders/mysql-charset-255-unknown-to-the-client-in-mysql-and-aws-rds-36fi" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;MySQL charset (255) unknown to the client in MySQL and AWS RDS&lt;/h2&gt;
      &lt;h3&gt;Karl Mathias Moberg for AWS Community Builders  ・ Mar 20 '21 ・ 2 min read&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#aws&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#mysql&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#rds&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;



&lt;h2&gt;
  
  
  Migrating to Graviton2 based DB instances
&lt;/h2&gt;

&lt;p&gt;Once we have the correct MySQL version, we can easily modify the instance type to an arm based Graviton2 instance. Steps are again described in the &lt;a href="https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Overview.DBInstance.Modifying.html"&gt;documentation&lt;/a&gt; of the process, which causes a downtime of about 2-3 minutes.&lt;/p&gt;

&lt;p&gt;At this point, we could compare the price/performance for the DB instances before and after the change.&lt;/p&gt;

&lt;p&gt;In our case, just changing the M5 instances we were using to their M6g corresponding instances let us &lt;strong&gt;save 11.2% in price per hour costs&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In terms of performance, we analized the &lt;code&gt;CPUUtilization&lt;/code&gt; metric for a day, normalized by Input/Output operations Per Second (IOPS), finding an &lt;strong&gt;average improvement of 9.14% in mean CPU usage&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If you want to see a detailed comparison between Intel and Graviton2 based instances, I hardly recommend the &lt;a href="https://svenbayer.blog/2021/02/08/benchmarking-amazon-rds-graviton2/"&gt;benchmark done by Sven Bayer&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In short, under normal conditions you should expect a price/performance improvement of around 20%, far from the 52% maximum identified by AWS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Downsizing overprovisioned instance types
&lt;/h2&gt;

&lt;p&gt;These results left us cold, since we expected to obtain a higher optimization. However, they opened the door to continue reviewing the configuration of the database instances.&lt;/p&gt;

&lt;p&gt;This is how, thanks to the performance gains and a better distribution of reporting and cron jobs, we could change de DB instance for one with a lower size. This has a special impact on Multi-AZ instances. &lt;/p&gt;

&lt;p&gt;Another important change we made is the use of &lt;a href="https://aws.amazon.com/about-aws/whats-new/2021/09/amazon-rds-t4g-mysql-mariadb-postgresql/"&gt;T4g instances&lt;/a&gt; in the staging environment databases. For this, we had to &lt;a href="https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_UpgradeDBInstance.Upgrading.html#USER_UpgradeDBInstance.Upgrading.Manual"&gt;upgrade the MySQL version&lt;/a&gt; from 8.0.23 to 8.0.25.&lt;/p&gt;

&lt;h2&gt;
  
  
  Storage configuration changes
&lt;/h2&gt;

&lt;p&gt;The choice of storage type is something to consider when configuring database instances. In our case, all databases had a "Provisioned IOPS" storage type. This is a storage type that ensures a series of IOPS on a continuous basis, indicated for databases that have a real usage load, i.e. for databases in the production environment. However, this requires paying for the number of IOPS provisioned and having a minimum number of IOPS determined by the disk space allocated to the instance.&lt;/p&gt;

&lt;p&gt;Therefore, we changed the storage type to "General Purpose SSD" for staging environment databases. In addition, we reduced the number of provisioned IOPS to the production databases, after analyzing their metrics.&lt;/p&gt;

&lt;p&gt;Finally, the assigned storage for staging instances was oversized. The storage costs in RDS are minimal, but taking advantage of the inertia we were carrying, we &lt;a href="https://aws.amazon.com/premiumsupport/knowledge-center/rds-db-storage-size/"&gt;reduced the storage&lt;/a&gt; for these instances. To do this, we did the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a new instance with the desired storage.&lt;/li&gt;
&lt;li&gt;Rename the old instance to a different name.&lt;/li&gt;
&lt;li&gt;Rename the new instance to the original name of the old instance.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Recap
&lt;/h2&gt;

&lt;p&gt;As a reward for getting this far, I am including a summary of the changes made and the impact each of them had on the RDS bill:&lt;/p&gt;

&lt;h3&gt;
  
  
  DB staging (-86.58%):
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;MySQL version: 5.7.33 → 8.0.25&lt;/li&gt;
&lt;li&gt;Instance type: db.t2.large → db.t4g.medium&lt;/li&gt;
&lt;li&gt;Storage:

&lt;ul&gt;
&lt;li&gt;type: Provisioned IOPS → General Purpose SSD Storage &lt;/li&gt;
&lt;li&gt;size: 500 GiB → 20 GiB&lt;/li&gt;
&lt;li&gt;Provisioned IOPS: 2000 → 0&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  DB staging read replica (-86.58%):
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;MySQL version: 5.7.33 → 8.0.25&lt;/li&gt;
&lt;li&gt;Instance type: db.t2.large → db.t4g.medium&lt;/li&gt;
&lt;li&gt;Storage:

&lt;ul&gt;
&lt;li&gt;type: Provisioned IOPS → General Purpose SSD Storage &lt;/li&gt;
&lt;li&gt;size: 500 GiB → 20 GiB&lt;/li&gt;
&lt;li&gt;Provisioned IOPS: 2000 → 0&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  DB production (Multi-AZ) (-45.31%):
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;MySQL version: 5.7.33 → 8.0.25&lt;/li&gt;
&lt;li&gt;Instance type: db.m5.2xlarge → db.m6g.xlarge&lt;/li&gt;
&lt;li&gt;Storage:

&lt;ul&gt;
&lt;li&gt;Provisioned IOPS: 2000 → 1500&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  DB production read replica (-16.25%):
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;MySQL version: 5.7.33 → 8.0.25&lt;/li&gt;
&lt;li&gt;Instance type: db.m5.xlarge → db.m6g.xlarge&lt;/li&gt;
&lt;li&gt;Storage:

&lt;ul&gt;
&lt;li&gt;Provisioned IOPS: 2000 → 1500&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The final cost reduction of our RDS bill is 51.28%, so you might find some of these tips useful for your use case.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cloud</category>
      <category>database</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
