<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[ovais.tariq - tech and leadership]]></title><description><![CDATA[Rumblings on technology focused around building scalable and reliable infrastructure. Thoughts on how to excel in leadership in a technological world.]]></description><link>https://www.ovaistariq.net/</link><image><url>https://www.ovaistariq.net/favicon.png</url><title>ovais.tariq - tech and leadership</title><link>https://www.ovaistariq.net/</link></image><generator>Ghost 6.45</generator><lastBuildDate>Wed, 10 Jun 2026 16:00:36 GMT</lastBuildDate><atom:link href="https://www.ovaistariq.net/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Monitoring ProxySQL using Datadog]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>ProxySQL is a high performance proxy for MySQL and its forks. One of the key features is its ability to handle hundreds of thousands of connections with very low overhead. Datadog is a monitoring service for cloud-scale applications, bringing together data from servers, databases, tools, and services to present</p>]]></description><link>https://www.ovaistariq.net/proxysql-monitoring-datadog/</link><guid isPermaLink="false">5edd869c66eb31003900f12f</guid><category><![CDATA[Metrics & Monitoring]]></category><dc:creator><![CDATA[Ovais Tariq]]></dc:creator><pubDate>Thu, 19 Jan 2017 15:34:20 GMT</pubDate><media:content url="https://storage.ghost.io/c/00/a4/00a40f0c-d250-4246-8eb2-4f2d00979d58/content/images/wordpress/2017/01/proxysql_dashboard_screenshot.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://storage.ghost.io/c/00/a4/00a40f0c-d250-4246-8eb2-4f2d00979d58/content/images/wordpress/2017/01/proxysql_dashboard_screenshot.png" alt="Monitoring ProxySQL using Datadog"><p>ProxySQL is a high performance proxy for MySQL and its forks. One of the key features is its ability to handle hundreds of thousands of connections with very low overhead. Datadog is a monitoring service for cloud-scale applications, bringing together data from servers, databases, tools, and services to present a unified view of an entire stack.</p>
<p>Datadog does not yet provide an integration for ProxySQL. So I decided to write an integration by <a href="https://github.com/twindb/dd-agent?ref=ovaistariq.net">forking the Datadog agent</a>. Read my <a href="https://twindb.com/proxysql-monitoring-datadog/?ref=ovaistariq.net">detailed blog post on TwinDB Blog</a> to learn how to use the ProxySQL-Datadog integration.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Slides of my talk on Monitoring MySQL at Scale]]></title><description><![CDATA[<p>The slides of my talk on best practices to monitor large scale MySQL deployments, are now available for download. This slide was presented during Percona Live 2016.</p><!--kg-card-begin: html--><iframe src="//www.slideshare.net/slideshow/embed_code/key/gHeJ77DVys8Yp0" width="595" height="485" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" style="border:1px solid #CCC; border-width:1px; margin-bottom:5px; max-width: 100%;" allowfullscreen> </iframe> <div style="margin-bottom:5px"> <strong> <a href="//www.slideshare.net/ovaistariq/monitoring-mysql-at-scale" title="Monitoring MySQL at scale" target="_blank">Monitoring MySQL at scale</a> </strong> from <strong><a href="https://www.slideshare.net/ovaistariq?ref=ovaistariq.net" target="_blank">Ovais Tariq</a></strong> </div><!--kg-card-end: html-->]]></description><link>https://www.ovaistariq.net/slides-monitoring-mysql-scale/</link><guid isPermaLink="false">5edde7f166eb31003900f5a0</guid><category><![CDATA[Metrics & Monitoring]]></category><category><![CDATA[MySQL]]></category><category><![CDATA[Talks]]></category><dc:creator><![CDATA[Ovais Tariq]]></dc:creator><pubDate>Wed, 08 Jun 2016 07:00:00 GMT</pubDate><content:encoded><![CDATA[<p>The slides of my talk on best practices to monitor large scale MySQL deployments, are now available for download. This slide was presented during Percona Live 2016.</p><!--kg-card-begin: html--><iframe src="//www.slideshare.net/slideshow/embed_code/key/gHeJ77DVys8Yp0" width="595" height="485" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" style="border:1px solid #CCC; border-width:1px; margin-bottom:5px; max-width: 100%;" allowfullscreen> </iframe> <div style="margin-bottom:5px"> <strong> <a href="//www.slideshare.net/ovaistariq/monitoring-mysql-at-scale" title="Monitoring MySQL at scale" target="_blank">Monitoring MySQL at scale</a> </strong> from <strong><a href="https://www.slideshare.net/ovaistariq?ref=ovaistariq.net" target="_blank">Ovais Tariq</a></strong> </div><!--kg-card-end: html-->]]></content:encoded></item><item><title><![CDATA[Extend MySQL Master HA (MHA) capabilities with MHA Helper]]></title><description><![CDATA[<!--kg-card-begin: html--><p>I have used many tools starting with MMM to be able to manage MySQL replication clusters. Some of the tools need more tools and complex HA solutions such as Pacemaker and Corosync, or Zookeeper. While other tools do not do the failover well which leaves the slaves in an inconsistent</p>]]></description><link>https://www.ovaistariq.net/extend-mysql-master-ha-mha-capabilities-with-mha-helper/</link><guid isPermaLink="false">5edd869c66eb31003900f12e</guid><category><![CDATA[MySQL]]></category><category><![CDATA[High Availability]]></category><dc:creator><![CDATA[Ovais Tariq]]></dc:creator><pubDate>Mon, 01 Feb 2016 13:58:10 GMT</pubDate><media:content url="https://storage.ghost.io/c/00/a4/00a40f0c-d250-4246-8eb2-4f2d00979d58/content/images/wordpress/2016/02/app_mysql_master_vip_mha_helper.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: html--><img src="https://storage.ghost.io/c/00/a4/00a40f0c-d250-4246-8eb2-4f2d00979d58/content/images/wordpress/2016/02/app_mysql_master_vip_mha_helper.png" alt="Extend MySQL Master HA (MHA) capabilities with MHA Helper"><p>I have used many tools starting with MMM to be able to manage MySQL replication clusters. Some of the tools need more tools and complex HA solutions such as Pacemaker and Corosync, or Zookeeper. While other tools do not do the failover well which leaves the slaves in an inconsistent state, MMM would be an example.<br>
And I must say that of all the tools I love MySQL Master HA (MHA) the most. MHA is a great tool to manage MySQL replication clusters for the purpose of HA. The most important thing about MHA is that it tries to take all the necessary steps to do a MySQL master failover in a way that provides as much data consistency as possible. The slave promotion also tends to be very quick, on average I have seen it take 10 to 15 seconds. It is also very easy to deploy unlike some of the other complex HA solutions.</p>
<p>I would highly recommend reading about the architecture of MHA on its wiki: <a href="https://code.google.com/p/mysql-master-ha/wiki/Architecture?ref=ovaistariq.net" target="_blank">https://code.google.com/p/mysql-master-ha/wiki/Architecture</a></p>
<h3>Why MHA Helper?</h3>
<p>MHA does one job and it does it well. It handles slave promotion in the best possible way. However, slave promotion in case of a master failure or in case of planned maintenance is only a step in the process. Typically a lot more is involved after a slave promotion has happened. For example, the application needs to be notified that the master has changed and that it needs to write to a new master. Then there may be some other operational tasks that need to be performed, such as notifying the monitoring service that the master has changed, or notifying the configuration management service so that it writes the correct configuration for a master. There can be a host of other operations that may need to be performed, I have just given a few examples that are most likely to be needed in majority of the cases.<br>
That&#x2019;s where <a href="https://github.com/ovaistariq/mha-helper?ref=ovaistariq.net" target="_blank">MHA Helper</a> comes in. <a href="https://github.com/ovaistariq/mha-helper?ref=ovaistariq.net" target="_blank">MHA Helper</a> provides a pluggable interface that extends MHA such that additional tasks may be performed in case of a MySQL failover.</p>
<h3>Virtual IP management using MHA Helper</h3>
<p>Currently <a href="https://github.com/ovaistariq/mha-helper?ref=ovaistariq.net" target="_blank">MHA Helper</a> provides virtual IP management for MySQL replication clusters. Virtual IP based HA solution is the most common implementation I have seen across a large number of MySQL users. Below is a simple illustration that shows a Virtual IP being used by the app to connect to MySQL.</p>
<p><img class="alignnone wp-image-914 size-full" src="https://storage.ghost.io/c/00/a4/00a40f0c-d250-4246-8eb2-4f2d00979d58/content/images/wordpress/2016/02/app_mysql_master_vip-e1454310394467.png" alt="Extend MySQL Master HA (MHA) capabilities with MHA Helper" width="456" height="496" srcset="https://storage.ghost.io/c/00/a4/00a40f0c-d250-4246-8eb2-4f2d00979d58/content/images/wordpress/2016/02/app_mysql_master_vip-e1454310394467.png 456w, https://storage.ghost.io/c/00/a4/00a40f0c-d250-4246-8eb2-4f2d00979d58/content/images/wordpress/2016/02/app_mysql_master_vip-e1454310394467-276x300.png 276w" sizes="(max-width: 456px) 100vw, 456px"></p>
<p>Now when a failover happens the Virtual IP gets moved to the promoted master and the apps disconnect and reconnect using the same Virtual IP.</p>
<p><img class="alignnone wp-image-916 size-full" src="https://storage.ghost.io/c/00/a4/00a40f0c-d250-4246-8eb2-4f2d00979d58/content/images/wordpress/2016/02/app_mysql_master_vip_failover.png" alt="Extend MySQL Master HA (MHA) capabilities with MHA Helper" width="456" height="496" srcset="https://storage.ghost.io/c/00/a4/00a40f0c-d250-4246-8eb2-4f2d00979d58/content/images/wordpress/2016/02/app_mysql_master_vip_failover.png 456w, https://storage.ghost.io/c/00/a4/00a40f0c-d250-4246-8eb2-4f2d00979d58/content/images/wordpress/2016/02/app_mysql_master_vip_failover-276x300.png 276w" sizes="(max-width: 456px) 100vw, 456px"></p>
<p>Now where does <a href="https://github.com/ovaistariq/mha-helper?ref=ovaistariq.net" target="_blank">MHA Helper</a> fit in here? <a href="https://github.com/ovaistariq/mha-helper?ref=ovaistariq.net" target="_blank">MHA Helper</a> acts as an external plugin that MHA invokes during various stages of the failover and <a href="https://github.com/ovaistariq/mha-helper?ref=ovaistariq.net" target="_blank">MHA Helper</a> then takes care of&#xA0;the necessary pre and post failover steps depending on the type of the failover.</p>
<ol>
<li>MySQL read_only flag handling. This also&#xA0;includes&#xA0;supporting the <a href="https://www.percona.com/doc/percona-server/5.6/management/super_read_only.html?ref=ovaistariq.net" target="_blank">super_read_only</a> flag that is available in&#xA0;Percona Server and other variants of MySQL</li>
<li>Handling of Virtual IP failover</li>
<li>Handling MySQL connections termination to make failover fast</li>
</ol>
<p><img class="alignnone wp-image-917 size-full" src="https://storage.ghost.io/c/00/a4/00a40f0c-d250-4246-8eb2-4f2d00979d58/content/images/wordpress/2016/02/app_mysql_master_vip_mha_helper.png" alt="Extend MySQL Master HA (MHA) capabilities with MHA Helper" width="643" height="497" srcset="https://storage.ghost.io/c/00/a4/00a40f0c-d250-4246-8eb2-4f2d00979d58/content/images/wordpress/2016/02/app_mysql_master_vip_mha_helper.png 643w, https://storage.ghost.io/c/00/a4/00a40f0c-d250-4246-8eb2-4f2d00979d58/content/images/wordpress/2016/02/app_mysql_master_vip_mha_helper-300x232.png 300w, https://storage.ghost.io/c/00/a4/00a40f0c-d250-4246-8eb2-4f2d00979d58/content/images/wordpress/2016/02/app_mysql_master_vip_mha_helper-600x464.png 600w" sizes="(max-width: 643px) 100vw, 643px"></p>
<h3>Pluggable and Extensible Architecture of MHA Helper</h3>
<p><a href="https://github.com/ovaistariq/mha-helper?ref=ovaistariq.net" target="_blank">MHA Helper</a> has been designed to be pluggable and extensible. It is configured through ini-style configuration files, with one file per MySQL replication cluster, meaning that different replication clusters can have totally different configuration setup without effecting each other. A complete list of configuration options with examples can be seen on the Github page&#xA0;<a href="https://github.com/ovaistariq/mha-helper?ref=ovaistariq.net#configuration" target="_blank">https://github.com/ovaistariq/mha-helper#configuration</a></p>
<p><a href="https://github.com/ovaistariq/mha-helper?ref=ovaistariq.net" target="_blank">MHA Helper</a> currently only has the Virtual IP based failover implementation, however it supports adding different implementations, for example a different implementation for MySQL instances running in AWS, or other types of clouds. Because of the pluggable architecture of <a href="https://github.com/ovaistariq/mha-helper?ref=ovaistariq.net" target="_blank">MHA Helper</a>, it is easy to add more integrations to it. For example, currently <a href="https://www.datadoghq.com/product/?ref=ovaistariq.net" target="_blank">Datadog</a> and <a href="https://www.chef.io/?ref=ovaistariq.net" target="_blank">Chef</a> integrations are in the works. The idea with Datadog integration is to send an event to Datadog whenever failover is performed as well as set appropriate tags on the new master to keep the metrics collection up to date.</p>
<p>If you have any more integration ideas, I would highly suggest that you file a bug&#xA0;<a href="https://github.com/ovaistariq/mha-helper/issues?ref=ovaistariq.net" target="_blank">https://github.com/ovaistariq/mha-helper/issues</a></p>
<h3>Installation</h3>
<p>The installation of <a href="https://github.com/ovaistariq/mha-helper?ref=ovaistariq.net" target="_blank">MHA Helper</a> is extremely easy. All you need to do is install the yum repository</p>
<pre>curl -s https://packagecloud.io/install/repositories/twindb/main/script.rpm.sh | sudo bash</pre>
<p>And install the packages</p>
<pre>yum install mha4mysql-manager mha4mysql-node python-mha_helper</pre>
<p>And that&#x2019;s it!</p>
<p><em><strong>For detailed instructions on configuration and installation visit the repository page on Github&#xA0;<a href="https://github.com/ovaistariq/mha-helper?ref=ovaistariq.net" target="_blank">https://github.com/ovaistariq/mha-helper</a>&#xA0;And don&#x2019;t forget to file bugs or feature requests.</strong></em></p>
<!--kg-card-end: html-->]]></content:encoded></item><item><title><![CDATA[Chef multipath cookbook version 0.0.9 now available]]></title><description><![CDATA[<!--kg-card-begin: html--><p>I have released version 0.0.9 of <a href="https://supermarket.chef.io/cookbooks/multipath?ref=ovaistariq.net">Chef multipath cookbook</a>. The cookbook now supports Pure Storage SAN among a bunch of other improvements.</p>
<p>Below is the list of changes and improvements in version 0.0.9 of Chef multipath cookbook:</p>
<ul>
<li>Added support for Pure Storage SAN</li>
<li>Added test-kitchen</li></ul>]]></description><link>https://www.ovaistariq.net/chef-multipath-cookbook-version-0-0-9-now-available/</link><guid isPermaLink="false">5edd869c66eb31003900f12d</guid><category><![CDATA[Infrastructure]]></category><dc:creator><![CDATA[Ovais Tariq]]></dc:creator><pubDate>Mon, 01 Jun 2015 16:17:57 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: html--><p>I have released version 0.0.9 of <a href="https://supermarket.chef.io/cookbooks/multipath?ref=ovaistariq.net">Chef multipath cookbook</a>. The cookbook now supports Pure Storage SAN among a bunch of other improvements.</p>
<p>Below is the list of changes and improvements in version 0.0.9 of Chef multipath cookbook:</p>
<ul>
<li>Added support for Pure Storage SAN</li>
<li>Added test-kitchen tests</li>
<li>Reimplemented the chefspec tests</li>
<li>Fixed the issues reported by foodcritic</li>
</ul>
<p>The cookbook is now tested to work with Chef 12.</p>
<p>To configure multipath for Pure Storage LUNs, all you need to do is set the following attribute:<br>
<code>node[&quot;multipath&quot;][&quot;storage_type&quot;] = &quot;purestorage&quot;</code></p>
<p>Feel free to contribute in the form of pull requests and bug reports. The repository is available at <a title="ovaistariq/cookbook-multipath" href="https://github.com/ovaistariq/cookbook-multipath?ref=ovaistariq.net">https://github.com/ovaistariq/cookbook-multipath</a></p>
<!--kg-card-end: html-->]]></content:encoded></item><item><title><![CDATA[Beware of MySQL BLOB Corruption in Older Versions]]></title><description><![CDATA[<!--kg-card-begin: html--><p>Does your dataset consist of InnoDB tables with large BLOB data such that the data is stored in external BLOB pages? Was the dataset created in MySQL version 5.1 and below and without using the InnoDB plugin, or with InnoDB plugin but with MySQL version earlier than 5.1.</p>]]></description><link>https://www.ovaistariq.net/beware-mysql-blob-corruption-older-versions/</link><guid isPermaLink="false">5edd869c66eb31003900f12c</guid><category><![CDATA[MySQL]]></category><dc:creator><![CDATA[Ovais Tariq]]></dc:creator><pubDate>Wed, 24 Dec 2014 12:06:41 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: html--><p>Does your dataset consist of InnoDB tables with large BLOB data such that the data is stored in external BLOB pages? Was the dataset created in MySQL version 5.1 and below and without using the InnoDB plugin, or with InnoDB plugin but with MySQL version earlier than 5.1.55? If the answer to both the questions are &#x201C;YES&#x201D; then it could very well be that you have a hidden corruption lying around in your dataset. The only way you would be able to find out about the corruption is when you have a crash with InnoDB assertion messages similar to the following:<br>
<code><br>
InnoDB: Serious error! InnoDB is trying to free page 4<br>
InnoDB: though it is already marked as free in the tablespace!<br>
InnoDB: The tablespace free space info is corrupt.<br>
</code></p>
<p>
In this post I will summarize what the bug is and how it corrupts the dataset. If you want more details of why and how the corruption manifests itself then you can additionally read the following bug reports:<br>
<a href="http://bugs.mysql.com/bug.php?id=55543&amp;ref=ovaistariq.net" target="_blank">http://bugs.mysql.com/bug.php?id=55543</a><br>
<a href="http://bugs.mysql.com/bug.php?id=55284&amp;ref=ovaistariq.net" target="_blank">http://bugs.mysql.com/bug.php?id=55284</a><br>
<a href="http://bugs.mysql.com/bug.php?id=55981&amp;ref=ovaistariq.net" target="_blank">http://bugs.mysql.com/bug.php?id=55981</a>
</p>
<h3>MySQL BLOB Corruption</h3>
<p>
The bug involves records that contain BLOBs that are stored off page on external pages. When are BLOBs stored off-page depends on the size of the blob and the row format and sometimes also depends on the size of the rows. Since we are mainly talking about older MySQL versions, so we would only be dealing with COMPACT and REDUNDANT row formats. Basically, InnoDB tries to store the entire BLOB on the same InnoDB page, but if the row size is large such that at least two rows cannot be stored on the page, then InnoDB will store the first 768 bytes from the BLOB on the page where the row is stored and the rest of the BLOB data is stored on external page. The page that contains the row then contains the pointer to the external page so that when InnoDB is reading the row it can lookup the BLOB by following the pointer.
</p>
<p>
Now coming back to the bug. The bug is caused by certain parts of the InnoDB code that cause the external page holding the BLOB data to get orphaned.<br>
One way the page gets orphaned is when the PRIMARY key column is being updated, but the update is rolled back for some reason. Now as you know that updating the PRIMARY key column would require a delete of the old row and a creation of a new row with the new data. It would also require moving the pointer data pointing to the external BLOB page from the old row to the new row. This moving of the association between the row and the external page from old row to new row was not being done in a consistent and transaction safe way which would cause the association to get lost in case of a transaction rollback.</p>
<p>What was really happening can be seen as a sequence of the below events:</p>
<ul>
<li>a. A transaction modifies the PRIMARY key column</li>
<li>b. Modification of PRIMARY key column causes the creation of a new row with the new data and old row being delete-marked</li>
<li>c. The association between the old row and the external BLOB page is changed, such that the external BLOB page is now associated with the new row.</li>
<li>d. The transaction is rolled back. The rollback undoes the changes, but does not change the association of the external BLOB page back to the old row.</li>
</ul>
<p>Hence, a transaction rollback would cause the BLOB page to get orphaned and freed. Once the page is freed it can be reused by InnoDB for storing BLOB data for other rows. The important thing to note here is that the original row that we tried to modify (but rolled back the changes) still contains a pointer to the external BLOB page. The thing that is lost is the association from InnoDB&#x2019;s perspective and that is why it considers the page free to be reused.
</p>
<p>
Now, this issue does not immediately cause any crashes. So you would never really know. A crash would only happen when the row above that we tried to modify (but rolled back the change) is deleted. Marko summarizes when this bug would cause a crash as follows:<br>
<em>&#x201C;Furthermore, if your tablespace has been created and modified with an old (buggy) version of InnoDB, a BLOB page could be freed and reused for something else. InnoDB would read and deliver the overwritten contents of the BLOB page to queries. The problem would not be detected until you actually delete the row and both the original BLOB page and the reused BLOB page have been freed.&#x201D;</em>
</p>
<p>
Is there any other way to test for this kind of corruption? No, there is no way possible. Neither &#x201C;CHECK TABLE&#x201D; nor innochecksum validate pointers to BLOB pages in any way.<br>
Below is an excerpt from the <a href="http://dev.mysql.com/doc/refman/5.6/en/check-table.html?ref=ovaistariq.net" target="_blank">MySQL manual</a>:<br>
&#x201C;CHECK TABLE surveys the index page structure, then surveys each key entry. It does not validate the key pointer to a clustered record or follow the path for BLOB pointers.&#x201D;
</p>
<h3>Mitigation</h3>
<p>
So what is the safest path then? The safest thing to do is to rebuild the dataset by means of dump and reload. We mostly have slaves and secondary masters created using some form of filesystem copy, either a direct copy or such as using <a href="http://www.percona.com/software/percona-xtrabackup?ref=ovaistariq.net" target="_blank">XtraBackup</a>. So if a crash does happen due to this bug, since it would most likely happen after a DELETE gets executed, the crash would replicate to the slaves as well, which if created using some form of filesystem copy would crash as well. A crash of the replication hierarchy would be a disaster.
</p>
<p>
Another thing to be careful about is when running tools that would DELETE rows containing large BLOB values. For example, if you run <a href="http://www.percona.com/doc/percona-toolkit/2.2/pt-table-sync.html?ref=ovaistariq.net" target="_blank">pt-table-sync</a> on a table with hidden corruption and <a href="http://www.percona.com/doc/percona-toolkit/2.2/pt-table-sync.html?ref=ovaistariq.net" target="_blank">pt-table-sync</a> has to sync records then there is a chance that could cause a crash. This is because by default <a href="http://www.percona.com/doc/percona-toolkit/2.2/pt-table-sync.html?ref=ovaistariq.net" target="_blank">pt-table-sync</a> executes REPLACE statements which are internally mapped to DELETE+UPDATE.
</p>
<h3>Conclusion</h3>
<p>So to summarize, if your dataset was created such that it meets either of the following conditions:<br>
a. Dataset created under MySQL version <= 5.1 without using innodb plugin, or b. dataset created under mysql version < 5.1.55 and plugin then it is a very good idea to rebuild the dump reload. bugs were only fixed in above for plugin. p>
<!--kg-card-end: html--></=></p>]]></content:encoded></item><item><title><![CDATA[Nasty MySQL Replication Bugs that Affect Upgrade to 5.6]]></title><description><![CDATA[<!--kg-card-begin: html--><p>There were two nasty MySQL replication bugs in two different 5.6 releases that would make it difficult to upgrade slaves to MySQL 5.6 while still connected to MySQL 5.5 master. </p>
<p>The first of those bugs is <a href="http://bugs.mysql.com/bug.php?id=72610&amp;ref=ovaistariq.net" target="_blank">MySQL bug 72610</a> which affects 5.6.19. Essentially this bug</p>]]></description><link>https://www.ovaistariq.net/mysql-replication-bugs-affect-upgrade-5-6/</link><guid isPermaLink="false">5edd869c66eb31003900f12b</guid><category><![CDATA[MySQL]]></category><dc:creator><![CDATA[Ovais Tariq]]></dc:creator><pubDate>Tue, 25 Nov 2014 13:52:51 GMT</pubDate><media:content url="https://storage.ghost.io/c/00/a4/00a40f0c-d250-4246-8eb2-4f2d00979d58/content/images/wordpress/2014/11/tanguy-sauvin-3122-optimized.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: html--><img src="https://storage.ghost.io/c/00/a4/00a40f0c-d250-4246-8eb2-4f2d00979d58/content/images/wordpress/2014/11/tanguy-sauvin-3122-optimized.jpg" alt="Nasty MySQL Replication Bugs that Affect Upgrade to 5.6"><p>There were two nasty MySQL replication bugs in two different 5.6 releases that would make it difficult to upgrade slaves to MySQL 5.6 while still connected to MySQL 5.5 master. </p>
<p>The first of those bugs is <a href="http://bugs.mysql.com/bug.php?id=72610&amp;ref=ovaistariq.net" target="_blank">MySQL bug 72610</a> which affects 5.6.19. Essentially this bug is triggered when the table structure on the slave is different from the table structure on the master which leads to unnecessarily large amount of RAM usage while replicating events that affect that table. The amount of RAM used would generally be more noticeable when the replicated transaction consists of thousands of RBR events. </p>
<p>The most common way this affects how we upgrade a replication hierarchy, is when we have the master running MySQL 5.5 and the slave running MySQL 5.6 and we have transactions involving DATETIME column(s). Tables with DATETIME columns will have different underlying structure when created on MySQL 5.5 versus when created on MySQL 5.6. Ideally you would avoid creating a new table with temporal columns while you still have master and slave on different MySQL major versions. Ideally you would also want to avoid running statements that would ALTER the structure of the table with temporal columns, such as running a NOOP ALTER TABLE or adding a new column to a table with temporal column(s). As any such operation will end up creating a new table with a new underlying structure.</p>
<p>Coming back to the bug itself, this bug was fixed in MySQL 5.6.21 which fixed excessive memory usage issue. However, the fix introduced a crashing bug details of which are reported in a <a href="https://bugs.launchpad.net/percona-server/+bug/1380010?ref=ovaistariq.net" target="_blank">Percona Server bug 1380010</a>. This isn&#x2019;t specifically a Percona Server bug, but rather a MySQL server bug. The crashing bug again affects MySQL upgrades badly. The bug, again, comes into play when you have master and slave with table(s) that have different underlying structure. Which is, again, something that you will likely see when you are upgrading a replication hierarchy, where for sometime you will have MySQL 5.5 master replicating to MySQL 5.6 slaves.</p>
<p>The good news is that <a href="http://www.percona.com/doc/percona-server/5.6/release-notes/Percona-Server-5.6.21-70.1.html?ref=ovaistariq.net" target="_blank">Percona Server 5.6.21-70.1 released on 24 November</a>, 2014 fixes the crashing bug. So its safe again to upgrade to Percona Server 5.6.21-70.1 from an older MySQL or Percona Server version. I would love to see this fix in the upstream MySQL server as well.</p>
<!--kg-card-end: html-->]]></content:encoded></item><item><title><![CDATA[Speedup Test Kitchen Vagrant Infrastructure Code Testing]]></title><description><![CDATA[<!--kg-card-begin: html--><p>
<a href="http://kitchen.ci/?ref=ovaistariq.net" target="_blank">Test Kitchen</a> together with <a href="https://docs.vagrantup.com/v2/getting-started/index.html?ref=ovaistariq.net" target="_blank">Vagrant</a> is a wonderful way to test out your infrastructure deployment and orchestration code. It makes test-driven development especially easy by allowing you to test locally using virtual machines. However, those of you who do a lot of testing with Test Kitchen and Vagrant would</p>]]></description><link>https://www.ovaistariq.net/speedup-test-kitchen-vagrant-testing/</link><guid isPermaLink="false">5edd869c66eb31003900f12a</guid><category><![CDATA[Infrastructure]]></category><dc:creator><![CDATA[Ovais Tariq]]></dc:creator><pubDate>Sat, 15 Nov 2014 01:18:46 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: html--><p>
<a href="http://kitchen.ci/?ref=ovaistariq.net" target="_blank">Test Kitchen</a> together with <a href="https://docs.vagrantup.com/v2/getting-started/index.html?ref=ovaistariq.net" target="_blank">Vagrant</a> is a wonderful way to test out your infrastructure deployment and orchestration code. It makes test-driven development especially easy by allowing you to test locally using virtual machines. However, those of you who do a lot of testing with Test Kitchen and Vagrant would know that waiting for tests to complete can be painfully long. This is especially true when with every test run the same packages have to be downloaded over and over again. Or when Vagrant decides to update the Virtual Box Guest Addition plugin every time you run your test suites.
</p>
<p><a href="http://en.gravatar.com/christinemdraper?ref=ovaistariq.net" target="_blank">Christine Draper</a> has an excellent <a href="http://christinemdraper.wordpress.com/2014/09/13/spend-less-time-waiting-more-time-cheffing/?ref=ovaistariq.net" target="_blank">post</a> which allows one to remove much of the waiting and make test runs instant. These basically involve installing two Vagrant plugins vagrant-cachier and vagrant-omnibus and disabling automatic Virtual Box Guest Addition plugin updates. </p>
<p>I would not detail why and how here, as details are already present in Christine&#x2019;s post which I have referenced. I would rather provide you with a Vagrantfile template that can be used with Test Kitchen so that we can make it use the two plugins and disable Virtual Box Guest Addition plugin updates.</p>
<p>Below is the content which you will need to write to a file named Vagrantfile.erb</p>
<pre>
Vagrant.configure(&quot;2&quot;) do |c|
  c.vm.box = &quot;<%= config[:box] %>&quot;
  c.vm.box_url = &quot;<%= config[:box_url] %>&quot;

  if Vagrant.has_plugin?(&quot;vagrant-cachier&quot;)
    c.cache.auto_detect = true
    c.cache.scope = :box
  end

  if Vagrant.has_plugin?(&quot;vagrant-omnibus&quot;)
    c.omnibus.cache_packages = true
    c.omnibus.chef_version = &quot;11.16.4&quot;
  end

  c.vbguest.auto_update = false

<% if config[:vm_hostname] %>
  c.vm.hostname = &quot;<%= config[:vm_hostname] %>&quot;
<% end %>
<% if config[:guest] %>
  c.vm.guest = <%= config[:guest] %>
<% end %>
<% if config[:username] %>
  c.ssh.username = &quot;<%= config[:username] %>&quot;
<% end %>
<% if config[:ssh_key] %>
  c.ssh.private_key_path = &quot;<%= config[:ssh_key] %>&quot;
<% end %>

<% array(config[:network]).each do |opts| %>
  c.vm.network(:<%= opts[0] %>, <%= opts[1..-1].join(", ") %>)
<% end %>

  c.vm.synced_folder &quot;.&quot;, &quot;/vagrant&quot;, disabled: true
<% config[:synced_folders].each do |source, destination, options| %>
  c.vm.synced_folder &quot;<%= source %>&quot;, &quot;<%= destination %>&quot;, <%= options %>
<% end %>

  c.vm.provider :<%= config[:provider] %> do |p|
<% config[:customize].each do |key, value| %>
  <% case config[:provider] when "virtualbox" %>
    p.customize [&quot;modifyvm&quot;, :id, &quot;--<%= key %>&quot;, &quot;<%= value %>&quot;]
  <% when "rackspace", "softlayer" %>
    p.<%= key %> = &quot;<%= value%>&quot;
  <% when ^vmware_ %>
    <% if key="=" :memory %>
      <% unless config[:customize].include?(:memsize) %>
    p.vmx[&quot;memsize&quot;] = &quot;<%= value %>&quot;
      <% end %>
    <% else %>
    p.vmx[&quot;<%= key %>&quot;] = &quot;<%= value %>&quot;
    <% end %>
  <% end %>
<% end %>
  end

end
</%></%></%></%=></%=></%></%></%=></%></%></%></%=></%=></%></%=></%=></%></%></%=></%></%=></%=></%=></%></%></%=></%=></%></%></%=></%></%></%=></%></%></%=></%></%></%=></%></%=></%=></pre>
<p>The file Vagrantfile.erb can be in the same directory as the .kitchen.yml file and can be referenced in .kitchen.yml in the &#x201C;platforms&#x201D; section as follows:</p>
<pre>
platforms:
  - name: centos-6.4
    driver:
      vagrantfile_erb: Vagrantfile.erb
</pre>
<p>That&#x2019;s about it. Next time you test your infrastructure code, don&#x2019;t forget to use the Vagrantfile.erb template. You will be pleased to see how quickly the tests finish.</p>
<!--kg-card-end: html-->]]></content:encoded></item><item><title><![CDATA[Percona XtraDB Cluster - A Drop-in-place Clustering Solution for MySQL]]></title><description><![CDATA[<!--kg-card-begin: html--><p>Emphasis on clustering solutions comes up quite a lot when talking to customers about High Availability. The reason is because clustering is supposed to provide an easier solution for maintaining high availability and so that you do not have to rely on other tools and techniques outside of the database</p>]]></description><link>https://www.ovaistariq.net/percona-xtradb-cluster-a-drop-in-place-clustering-solution-for-mysql/</link><guid isPermaLink="false">5edd869c66eb31003900f129</guid><category><![CDATA[MySQL]]></category><category><![CDATA[High Availability]]></category><dc:creator><![CDATA[Ovais Tariq]]></dc:creator><pubDate>Thu, 31 Oct 2013 14:06:28 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: html--><p>Emphasis on clustering solutions comes up quite a lot when talking to customers about High Availability. The reason is because clustering is supposed to provide an easier solution for maintaining high availability and so that you do not have to rely on other tools and techniques outside of the database server. </p>
<p>I thought it would be good to share the gist of many of my discussions around clustering, in the form of a blog post.</p>
<p>People usually tend to compare MySQL NDB Cluster and Percona XtraDB Cluster but both of them really are very different solutions. </p>
<p>For one NDB Cluster would mean a complete rethink of how data is accessed by the application. You also get to have to deal with a storage engine that works and behaves differently from InnoDB storage engine. The key point with NDB Cluster is data partitioning between different nodes. Not all applications are built with partitioning in mind specifically. And such you would have to adapt the application to make sure that it is aware of that and can distribute the workload effectively. This may mean partitioning in such a way that a single application request does not imply having to go to each partition to fetch data. I have typically seen a lot of effort put into applications when moving from traditional InnoDB based solution to NDB based solution. Moving to NDB Cluster is a major major change and as such implies that you would probably need to rewrite parts of the application to make it work effectively. </p>
<p><strong>To summarize: MySQL NDB Cluster is not a drop-in-place clustering solution.</strong></p>
<p>However, Percona XtraDB Cluster, which is Galera-based clustering solution, is a drop-in-place clustering solution and it truly is. You might have to do minute changes in the application, but you can even live with not having to do any. If you are already using InnoDB storage engine, then you do not need to make any changes to the application, except may be for the fact that deadlocks happen a bit differently. Percona XtraDB Cluster provides a clustering layer over traditional MySQL server with InnoDB storage engine, such that everything is exactly the same except how replication is performed. XtraDB Cluster is a synchronous replication cluster, meaning that every transaction COMMIT implies that the transaction is replicated to every node in the cluster where a process known as certification is performed to validate the transaction that is committed and perform conflict resolution. And you get other benefits with it:</p>
<ul>
<li>High Availability: You can read/write to any node, when a node goes down, you can start reading/writing from a different node</li>
<li>Data Consistency: You do not have to worry about data consistency in the same way as you do with regular MySQL master-slave pair</li>
<li>Parallel Replication: You get true parallel replication without the restrictions that are present in MySQL 5.6</li>
<li>Partitioning Protection: Partitioning protection is built inside this clustering solution</li>
</ul>
<p>What I really like about this solution, other then the fact that this is a true drop-in-place solution, is that you do not have to rely on other pieces of software to get high availability or partitioning protection. These things are already taken care of and as such this greatly reduces the complexity of this clustering solution. Otherwise with a typical MySQL master-slave setup you have to rely on other solutions such as Pacemaker to get high availability and other related things. The other difference of course when compared to MySQL NDB Cluster is that data is not partitioned in any way, all the data is present on every node in a XtraDB Cluster.</p>
<p><strong>To summarize: Percona XtraDB Cluster is a drop-in-place clustering solution.</strong></p>
<p>I would suggest that you read more about Percona XtraDB Cluster <a href="http://www.percona.com/doc/percona-xtradb-cluster/intro.html?ref=ovaistariq.net">here</a> and give it a try when the next time you want to move to a clustering solution.</p>
<!--kg-card-end: html-->]]></content:encoded></item><item><title><![CDATA[InnoDB scalability issues due to tables without primary keys]]></title><description><![CDATA[<!--kg-card-begin: html--><p>Each day there is probably work done to improve performance of the InnoDB storage engine and remove bottlenecks and scalability issues. Hence there was another one I wanted to highlight: Scalability issues due to tables without primary keys. This scalability issue is caused by the usage of tables without primary</p>]]></description><link>https://www.ovaistariq.net/innodb-scalability-issues-due-to-tables-without-primary-keys/</link><guid isPermaLink="false">5edd869c66eb31003900f128</guid><category><![CDATA[MySQL]]></category><dc:creator><![CDATA[Ovais Tariq]]></dc:creator><pubDate>Fri, 18 Oct 2013 23:50:20 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: html--><p>Each day there is probably work done to improve performance of the InnoDB storage engine and remove bottlenecks and scalability issues. Hence there was another one I wanted to highlight: Scalability issues due to tables without primary keys. This scalability issue is caused by the usage of tables without primary keys. This issue typically shows itself as contention on the InnoDB dict_sys mutex. Now the dict_sys mutex controls access to the data dictionary. This mutex is used at various important places throughout the InnoDB code and as such any contention on the dict_sys mutex is going to have a InnoDB system-wide negative affect. You can read the rest of the post <a href="http://www.mysqlperformanceblog.com/2013/10/18/innodb-scalability-issues-tables-without-primary-keys/?ref=ovaistariq.net">here</a>.</p>
<!--kg-card-end: html-->]]></content:encoded></item><item><title><![CDATA[Implications of Metadata Locking Changes in MySQL 5.5]]></title><description><![CDATA[<!--kg-card-begin: html--><p>While most of the talk recently has mostly been around the new changes in MySQL 5.6 (and that is understandable), I have had lately some very interesting cases to deal with, with respect to the Metadata Locking related changes that were introduced in MySQL 5.5.3. It appears</p>]]></description><link>https://www.ovaistariq.net/implications-of-metadata-locking-changes-in-mysql-5-5/</link><guid isPermaLink="false">5edd869c66eb31003900f127</guid><category><![CDATA[MySQL]]></category><dc:creator><![CDATA[Ovais Tariq]]></dc:creator><pubDate>Sat, 09 Feb 2013 22:52:48 GMT</pubDate><media:content url="https://storage.ghost.io/c/00/a4/00a40f0c-d250-4246-8eb2-4f2d00979d58/content/images/wordpress/2013/02/antonina-bukowska-142087-optimized.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: html--><img src="https://storage.ghost.io/c/00/a4/00a40f0c-d250-4246-8eb2-4f2d00979d58/content/images/wordpress/2013/02/antonina-bukowska-142087-optimized.jpg" alt="Implications of Metadata Locking Changes in MySQL 5.5"><p>While most of the talk recently has mostly been around the new changes in MySQL 5.6 (and that is understandable), I have had lately some very interesting cases to deal with, with respect to the Metadata Locking related changes that were introduced in MySQL 5.5.3. It appears that the implications of Metadata Locking have not been covered well, and since there are still a large number of MySQL 5.0 and 5.1 installations that would upgrade or are in the process of upgrading to MySQL 5.5, I thought it necessary to discuss what these implications exactly are. You can read the rest of the post <a href="http://www.mysqlperformanceblog.com/2013/02/01/implications-of-metadata-locking-changes-in-mysql-5-5/?ref=ovaistariq.net">here</a>.</p>
<!--kg-card-end: html-->]]></content:encoded></item><item><title><![CDATA[On SSDs - Lifespans, Health Measurement and RAID]]></title><description><![CDATA[<!--kg-card-begin: html--><p>Solid State Drive (SSD) have made it big and have made their way not only in desktop computing but also in mission-critical servers. SSDs have proved to be a break-through in IO performance and leave HDD far far behind in terms of Random IO performance. Random IO is</p>]]></description><link>https://www.ovaistariq.net/on-ssds-lifespans-health-measurement-and-raid/</link><guid isPermaLink="false">5edd869c66eb31003900f126</guid><category><![CDATA[SSD]]></category><category><![CDATA[Infrastructure]]></category><dc:creator><![CDATA[Ovais Tariq]]></dc:creator><pubDate>Thu, 11 Oct 2012 17:54:57 GMT</pubDate><media:content url="https://storage.ghost.io/c/00/a4/00a40f0c-d250-4246-8eb2-4f2d00979d58/content/images/wordpress/2012/10/jp-valery-200305-optimized.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: html--><img src="https://storage.ghost.io/c/00/a4/00a40f0c-d250-4246-8eb2-4f2d00979d58/content/images/wordpress/2012/10/jp-valery-200305-optimized.jpg" alt="On SSDs - Lifespans, Health Measurement and RAID"><p>Solid State Drive (SSD) have made it big and have made their way not only in desktop computing but also in mission-critical servers. SSDs have proved to be a break-through in IO performance and leave HDD far far behind in terms of Random IO performance. Random IO is what most of the database administrators would be concerned about as that is 90% of the IO pattern visible on database servers like MySQL. I have found Intel 520-series and Intel 910-series to be quite popular and they do give very good numbers in terms of Random IOPS. However, its not just performance that you should be concerned about, failure predictions and health gauges are also very important, as loss of data is a big NO-NO. There is a great deal of misconception about the endurance level of SSD, as its mostly compared to rotating disks even when measuring endurance levels, however, there is a big difference in how both SSD and HDD work, and that has a direct impact on the endurance level of SSD. </p>
<p>I will mostly be taling about MLC SSD, now let&#x2019;s start off with a SSD primer.</p>
<h3>SSD Primer</h3>
<p>The smallest unit of SSD storage that can be read or written to is a page which is typically 4KB or 8KB in size. These pages are typically organized into blocks which are between 256KB or 1MB in size. SSDs have no mechanical parts and no heads or anything and their is no seeks needed as in conventional rotating disks. Reads involve reading pages from the SSD, however its the writes that are more tricky. Once you write to a page on SSD, you cannot simply overwrite (if you want to write new data) it in the same way you do with a HDD. Instead, you must erase the contents and then write again. However, a SSD can only do erasures at the block level and not the page level. What this means is that the SSD must relocate any valid data in the block to be erased, before the block can be erased and have new data written to it. To summarize, writes mean erase+write. Nowadays, SSD controllers are intelligent and do erasures in the background, so that the latency of the write operation is not affected. These background erasures are typically done within a process known garbage collection. You can imagine if these erasures were not done in the background, then writes would be too slow.</p>
<p>Of course every SSD has a lifespan after which it can be seen as unusable, let&#x2019;s see what factors matter here.</p>
<h3>SSD Lifespans</h3>
<p>The lifespan of blocks that make up a SSD is really the number of times erasures and writes can be performed on those blocks. The lifespan is measure in terms of erase/write cycles. Typically enterprise grade MLC SSDs have a lifespan of about 30000 erase/write cycles, while consumer grade MLC SSD have a life span of 5000 to 10000 erase/write cycles. This fact makes it clear that the lifespan of a SSD depends on how much time it is written to. If you have a write-intensive workload then you should expect the SSD to fail much more quickly, in comparison to a read-heavy workload. This is by design.<br>
To offset this behaviour of writes reducing the life of a SSD, engineers use two techniques, wear-levelling and over-provisioning. Wear-levelling works by making sure that all the blocks in a SSD are erased and written to in a evenly distributed fashion, this makes sure that some blocks do not die quickly then other blocks. Over-provisioning SSD capacity is one another technique that increases SSD endurance. This is accomplished by having a large population of blocks to distribute erases and writes over time (bigger capacity SSD), and by providing a large spare area. Many SSD models over provision the space, for example a 80GB SSD could have 10GB of over-provisioned space, so that while it is actually 90GB in size it is reported as a 80GB SSD. While this over-provisioning is done by the SSD manufacturers, this can also be done by not utilising the entire SSD, for example partitioning the SSD in such a way that you only partition about 75% to 80% of the SSD and leave the rest as RAW space that is not visible to the OS/filesystem. So while over-provisioning takes away some part of the disk capacity, it gives back in terms of increased endurance and performance.</p>
<p>Now comes the important part of the post that I would like to discuss.</p>
<h3>Health Measurement and failure predictability</h3>
<p>As you may have noticed after reading the above part of this post, its all the more important to be able to predict when a SSD would fail and to be able to see health related information about the SSD. Yet I haven&#x2019;t found much written about how to gauge the health of a SSD. RAID controllers employed with SSD tend to be very limited in terms of the amount of information that they provide about an SSD that could allow predicting when a SSD could fail. However, most of the SSD provide a lot of information via S.M.A.R.T. and this can be leveraged to good affect.<br>
Let&#x2019;s consider the example of Intel SSD, these SSD have to S.M.A.R.T. attributes that can be leveraged to predict when the SSD would fail. These attributes are:</p>
<ul>
<li>Available_Reservd_Space: This attribute reports the number of reserve blocks remaining. The value of the attribute starts at 100, which means that the reserved space is 100 percent available. The threshold value for this attribute is 10 which means 10 percent availability, which indicates that the drive is close to its end of life.</li>
<li>Media_Wearout_Indicator: This attribute reports the number of erase/write cycles the NAND media has performed. The value of the attribute decreases from 100 to 1, as the average erase cycle count increases from 0 to the maximum rated cycles. Once the value of this attribute reaches 1, the number will not decrease, although it is likely that significant additional wear can be put on the device. A value of 1 should be thought of as the threshold value for this attribute.</li>
</ul>
<p>Using the <a href="http://smartmontools.sourceforge.net/man/smartctl.8.html?ref=ovaistariq.net">smartctl</a> tool (part of the smartmontools package) we can very easily read the values of these attributes and then use it to predict failures. For example for SATA SSD drives attached to a LSI Megaraid controller, we could very easily read the values of those attributes using the following bash snippet:</p>
<pre class="mysql">
Available_Reservd_Space_current=$(smartctl -d sat+megaraid,${device_id} -a /dev/sda | grep &quot;Available_Reservd_Space&quot; | awk &apos;{print $4}&apos;)
Media_Wearout_Indicator_current=$(smartctl -d sat+megaraid,${device_id} -a /dev/sda | grep &quot;Media_Wearout_Indicator&quot; | awk &apos;{print $4}&apos;) 
</pre>
<p>Then the above information can be used in different fashions, we could raise an alert if its nearing the threshold value, or measure how quickly the values decrease and then use the rate of decrease to estimate when the drive could fail.</p>
<h3>SSDs and RAID levels</h3>
<p> RAID have been typically with HDD used for data protection via redundancy and for increased performance, and they have found their use with SSD as well. Its common to see RAID level 5 or 6 being used with SSD on mixed read/write workloads, because the write penalty visible by using these level with rotating disks, is not of that extent when talking about SSD because there is no disk seek involved, so the read-modify-write cycle typically involved with parity based RAID levels does not cause a lot of performance hit. On the other hand striping and mirroring does improve the read performance of the SSD a lot and redundant arrays using SSD deliver far better performance as compared to HDD arrays.<br>
But what about data protection? Do the parity-based RAID levels and mirroring provide the same level of data protection for SSDs as they are thought of? I am skeptical about that, because as I have mentioned above the endurance of a SSD depends a lot on how much it has been written to. In parity-based RAID configurations, a lot of extra writes are generated because of parity changes and they of course decrease the lifespan of the SSD, similarly in the case of mirroring, I am not sure it can provide any benefit in case of wearing out of SSD, if both the SSD in the mirror configuration have the same age, why? Because in mirroring both the SSDs in the array would be receiving the same amount of writes and hence the lifespan would decrease at the same amount of time.<br>
I would think that there is some drastic changes that are needed to the thought process when thinking of data protection and RAID levels, because for me parity-based configuration or mirroring configuration are not going to provide any extra data protection in cases where the SSD used are of similar ages. It might actually be a good idea to periodically replace drives with younger ones so as to make sure that all the drives do not age together.</p>
<p>I would like to know what my readers think!</p>
<!--kg-card-end: html-->]]></content:encoded></item><item><title><![CDATA[Join Optimizations in MySQL 5.6 and MariaDB 5.5]]></title><description><![CDATA[<!--kg-card-begin: html--><p>This is the third blog post in the series of blog posts leading up to the talk comparing the optimizer enhancements in MySQL 5.6 and MariaDB 5.5. This blog post is targeted at the join related optimizations introduced in the optimizer. These optimizations are available in both MySQL</p>]]></description><link>https://www.ovaistariq.net/join-optimizations-in-mysql-5-6-and-mariadb-5-5/</link><guid isPermaLink="false">5edd869c66eb31003900f125</guid><category><![CDATA[MySQL]]></category><dc:creator><![CDATA[Ovais Tariq]]></dc:creator><pubDate>Thu, 31 May 2012 17:24:42 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: html--><p>This is the third blog post in the series of blog posts leading up to the talk comparing the optimizer enhancements in MySQL 5.6 and MariaDB 5.5. This blog post is targeted at the join related optimizations introduced in the optimizer. These optimizations are available in both MySQL 5.6 and MariaDB 5.5, and MariaDB 5.5 has introduced some additional optimizations which we will also look at, in this post. You can read the rest of the post <a href="http://www.mysqlperformanceblog.com/2012/04/04/join-optimizations-in-mysql-5-6-and-mariadb-5-5/?ref=ovaistariq.net">here</a>.</p>
<!--kg-card-end: html-->]]></content:encoded></item><item><title><![CDATA[Multi Range Read (MRR) in MySQL 5.6 and MariaDB 5.5]]></title><description><![CDATA[<!--kg-card-begin: html--><p>I have written a second blog post in the series of blog posts leading up to the <a href="http://www.percona.com/live/mysql-conference-2012/sessions/mysql-optimizer-standoff-mysql-56-and-mariadb-53?ref=ovaistariq.net">talk comparing the optimizer enhancements in MySQL 5.6 and MariaDB 5.5</a>. This blog post is aimed at the optimizer enhancement Multi Range Read (MRR). Its available in both MySQL 5.6</p>]]></description><link>https://www.ovaistariq.net/multi-range-read-mrr-in-mysql-5-6-and-mariadb-5-5/</link><guid isPermaLink="false">5edd869c66eb31003900f124</guid><category><![CDATA[MySQL]]></category><dc:creator><![CDATA[Ovais Tariq]]></dc:creator><pubDate>Wed, 21 Mar 2012 20:30:45 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: html--><p>I have written a second blog post in the series of blog posts leading up to the <a href="http://www.percona.com/live/mysql-conference-2012/sessions/mysql-optimizer-standoff-mysql-56-and-mariadb-53?ref=ovaistariq.net">talk comparing the optimizer enhancements in MySQL 5.6 and MariaDB 5.5</a>. This blog post is aimed at the optimizer enhancement Multi Range Read (MRR). Its available in both MySQL 5.6 and MariaDB 5.5</p>
<p>You can read the entire blog post <a href="http://www.mysqlperformanceblog.com/2012/03/21/multi-range-read-mrr-in-mysql-5-6-and-mariadb-5-5/?ref=ovaistariq.net">here</a>.</p>
<!--kg-card-end: html-->]]></content:encoded></item><item><title><![CDATA[Index Condition Pushdown in MySQL 5.6 and MariaDB 5.5 and its performance impact]]></title><description><![CDATA[<!--kg-card-begin: html--><p>I have been working with Peter in preparation for the talk comparing the optimizer enhancements in MySQL 5.6 and MariaDB 5.5. We are taking a look at and benchmarking optimizer enhancements one by one. So in the same way this blog post is aimed at a new optimizer</p>]]></description><link>https://www.ovaistariq.net/index-condition-pushdown-in-mysql-5-6-and-mariadb-5-5-and-its-performance-impact/</link><guid isPermaLink="false">5edd869c66eb31003900f123</guid><category><![CDATA[MySQL]]></category><dc:creator><![CDATA[Ovais Tariq]]></dc:creator><pubDate>Tue, 13 Mar 2012 13:37:59 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: html--><p>I have been working with Peter in preparation for the talk comparing the optimizer enhancements in MySQL 5.6 and MariaDB 5.5. We are taking a look at and benchmarking optimizer enhancements one by one. So in the same way this blog post is aimed at a new optimizer enhancement Index Condition Pushdown (ICP). Its available in both MySQL 5.6 and MariaDB 5.5 You can read more about this at MySQL Performance Blog <a href="http://www.mysqlperformanceblog.com/2012/03/12/index-condition-pushdown-in-mysql-5-6-and-mariadb-5-5-and-its-performance-impact/?ref=ovaistariq.net">here</a>.</p>
<!--kg-card-end: html-->]]></content:encoded></item><item><title><![CDATA[Profiling your slow queries using pt-query-digest and some love from Percona Server]]></title><description><![CDATA[<!--kg-card-begin: html--><h3>Overview</h3>
<p>Profiling, analyzing and then fixing slow queries is likely the most oft-repeated part of a job of a DBA. And there are not too many tools out there that can make your life easy by providing analysis of queries with such data points that allow you to attack</p>]]></description><link>https://www.ovaistariq.net/profiling-your-slow-queries-using-pt-query-digest-and-some-love-from-percona-server/</link><guid isPermaLink="false">5edd869c66eb31003900f122</guid><category><![CDATA[MySQL]]></category><dc:creator><![CDATA[Ovais Tariq]]></dc:creator><pubDate>Wed, 28 Dec 2011 17:23:13 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: html--><h3>Overview</h3>
<p>Profiling, analyzing and then fixing slow queries is likely the most oft-repeated part of a job of a DBA. And there are not too many tools out there that can make your life easy by providing analysis of queries with such data points that allow you to attack the right queries in the right way. One such tool that I have always found myself using is <strong>pt-query-digest</strong>(formerly known as mk-query-digest). </p>
<p>Now let us go through using this very nice tool. </p>
<h3>Before We Start!</h3>
<p>But before we start, make sure you have enabled <a href="http://dev.mysql.com/doc/refman/5.1/en/slow-query-log.html?ref=ovaistariq.net">slow query logging</a> and set a low enough <a href="http://dev.mysql.com/doc/refman/5.1/en/server-system-variables.html?ref=ovaistariq.net#sysvar_long_query_time">long_query_time</a>. The correct value of <code>long_query_time</code> depends on your application requirements, a <code>long_query_time</code> of 1 second or 2 seconds might be sufficient for most of the users. Its also typical to see in many cases that you set the <code>long_query_time</code> to 0 for a small period of time to log all the queries. </p>
<p class="note">Note that logging all queries in this fashion as opposed to the general query log, enables us to have the statistics available after the query is actually executed, while no such statistics are available for queries that are logged using the general query log.</p>
<p>And there might be other cases when you want to log queries taking less than 1 second of time(micro-seconds), for that you can specify a value in fractions, for example, you can specify <code>long_query_time=0.5</code> to log queries taking greater than half-a-second.</p>
<p class="note">Note that logging queries taking fraction of a second is not possible for versions of MySQL &lt; 5.1, unless you use the <em><a href="http://www.mysqlperformanceblog.com/2007/06/06/microslow-patch-for-5037/?ref=ovaistariq.net">microslow</a></em> patch developed by Percona. You can follow the guide <a href="http://www.mysqlperformanceblog.com/2008/04/20/updated-msl-microslow-patch-installation-walk-through/?ref=ovaistariq.net">here</a> if you are still running MySQL &lt; 5.1 and would like to install this patch. You should also note that for versions of MySQL &lt; 5.1 setting <code>long_query_time=0</code> would actually disable the slow query logging.</p>
<p>Installing pt-query-digest tool (as well as other tools from Percona Toolkit) is very easy, and is explained here at <a href="http://www.percona.com/doc/percona-toolkit/installation.html?ref=ovaistariq.net">this link</a>.</p>
<h3>Using pt-query-digest</h3>
<p>Using pt-query-digest is pretty straight forward:</p>
<pre>pt-query-digest /path/to/slow-query.log</pre>
<p><em>Note that executing pt-query-digest can be pretty CPU and memory consuming, so ideally you should download the &#x201C;slow query log&#x201D; to another machine and run it there.</em></p>
<h3>Analyzing pt-query-digest Output</h3>
<p>Now let&#x2019;s see what output it returns. The first part of the output is an <strong>overall summary</strong>:</p>
<pre class="mysql">
# 250ms user time, 20ms system time, 17.38M rss, 53.62M vsz
# Current date: Wed Dec 28 08:16:13 2011
# Hostname: somehost.net
# Files: ./slow-query.log
# Overall: 296 total, 12 unique, 0.00 QPS, 0.00x concurrency _____________
# Time range: 2011-11-26 17:44:58 to 2011-12-27 13:01:44
# Attribute          total     min     max     avg     95%  stddev  median
# ============     ======= ======= ======= ======= ======= ======= =======
# Exec time           736s      1s     23s      2s      6s      2s      1s
# Lock time            5ms       0   290us    17us   103us    43us       0
# Rows sent          8.31M       0   8.31M  28.75k  202.40 477.30k       0
# Rows examine      53.69k       0   3.51k  185.75  964.41  497.06       0
# Rows affecte          38       0       1    0.13    0.99    0.33       0
# Rows read          8.31M       0   8.31M  28.75k  202.40 477.30k       0
# Bytes sent       294.94M       0 275.07M 1020.33k  79.83k  15.63M  79.83k
# Tmp tables            16       0       4    0.05       0    0.45       0
# Tmp disk tbl           0       0       0       0       0       0       0
# Tmp tbl size       1.94M       0 496.08k   6.70k       0  56.06k       0
# Query size        36.89k      44     886  127.63  420.77  144.69   69.19
</pre>
<p>It tells you that there are a total of 296 slow queries which are actually invocations of 12 different queries. Following that there are summaries of various other data points such as the total query execution time and the average query execution time. One thing I suggest here is that, you should probably give more importance to the times/values reported in the 95% (95th percentile) column as that gives us more accurate understanding. Now, for example, from this summary you can easily see whether you need to bump up the <code>tmp_table_size</code> variable if you see a big &#x201C;Tmp disk tbl&#x201D; number, you can easily adjust the value of <code>tmp_table_size</code> by taking a look at the 95% column for the row dealing with &#x201C;Tmp tbl size&#x201D;. Pretty nifty!</p>
<p>Let&#x2019;s analyze next part of the output produced by pt-query-digest.</p>
<pre class="mysql">
# Profile
# Rank Query ID           Response time  Calls R/Call  Apdx V/M   Item
# ==== ================== ============== ===== ======= ==== ===== ========
#    1 0x92F3B1B361FB0E5B 644.9895 87.6%   244  2.6434 0.44  1.26 SELECT wp_options
#    2 0x555191621979A464  33.6349  4.6%    30  1.1212 0.65  0.03 REPLACE SELECT test.checksum test.sbtest_myisam
#    3 0x8354260420CBD34B  22.6124  3.1%     1 22.6124 0.00  0.00 SELECT customer address category
</pre>
<p>The above part of the output <strong>ranks the queries</strong> and shows the top slowest queries. As we can see here the slowest one is the <code>SELECT wp_options</code>, this is basically a unique way of identifying the query and simply implies that this is a <code>SELECT</code> query executed against the <code>wp_options</code> table.</p>
<p>Now let&#x2019;s take a look at the most important part of the output:</p>
<pre class="mysql">
# Query 1: 0.00 QPS, 0.00x concurrency, ID 0x92F3B1B361FB0E5B at byte 119442
# This item is included in the report because it matches --limit.
# Scores: Apdex = 0.44 [1.0], V/M = 1.26
# Query_time sparkline: |      ^ |
# Time range: 2011-12-08 17:48:20 to 2011-12-27 13:01:44
# Attribute    pct   total     min     max     avg     95%  stddev  median
# ============ === ======= ======= ======= ======= ======= ======= =======
# Count         82     244
# Exec time     87    645s      1s     10s      3s      6s      2s      1s
# Lock time     37     2ms       0   201us     8us    60us    30us       0
# Rows sent      0   3.40k       0     211   14.28  202.40   51.53       0
# Rows examine   7   4.01k       0     252   16.84  234.30   60.55       0
# Rows affecte   0       0       0       0       0       0       0       0
# Rows read      0   3.40k       0     211   14.28  202.40   51.53       0
# Bytes sent     6  19.03M  41.35k  83.95k  79.88k  79.83k   6.92k  79.83k
# Tmp tables     0       0       0       0       0       0       0       0
# Tmp disk tbl   0       0       0       0       0       0       0       0
# Tmp tbl size   0       0       0       0       0       0       0       0
# Query size    45  16.92k      71      71      71      71       0      71
# String:
# Databases    wp_blog_one (154/63%), wp_blog_tw... (81/33%)... 1 more
# Hosts
# InnoDB trxID 7F1910 (1/0%), 7F3860 (1/0%), 7F9F74 (1/0%)... 14 more
# Last errno   0
# Users        wp_blog_one (154/63%), wp_blog_two (81/33%)... 1 more
# Query_time distribution
#   1us
#  10us
# 100us
#   1ms
#  10ms
# 100ms
#    1s  ################################################################
#  10s+
# Tables
#    SHOW TABLE STATUS FROM `wp_blog_two` LIKE &apos;wp_options&apos;\G
#    SHOW CREATE TABLE `wp_blog_two`.`wp_options`\G
# EXPLAIN /*!50100 PARTITIONS*/
SELECT option_name, option_value FROM wp_options WHERE autoload = &apos;yes&apos;\G
</pre>
<p>This is the actual part of the output dealing with analysis of the most slowest <strong>query ranked #1</strong>. The first row in the table above shows the Count of number of times this query was executed. Now let&#x2019;s take a look at the values in the 95% column, we can clearly see that this query is taking up a lot of execution time (6s) and is sending a lot of rows (202) and a lot of data (79.83k). The &#x201C;Databases&#x201D; section of the output also shows the name of the databases where this query was executed. Next the &#x201C;Query_time distribution&#x201D; section shows how this query times, which you can see lies in the range 1s to 10s all the time. The &#x201C;Tables&#x201D; section lists the queries that you can use to gather more data about the underlying tables involved and the query execution plan used by MySQL.<br>
The end result might be that you end up limiting the number of results returned by the query, by using a LIMIT clause or by filtering based on the <code>option_name</code> column.</p>
<p>Let&#x2019;s analyze another slow query, this time <strong>query ranked #3</strong> by pt-query-digest.</p>
<pre class="mysql">
# Query 3: 0 QPS, 0x concurrency, ID 0x8354260420CBD34B at byte 132619 ___
# This item is included in the report because it matches --limit.
# Scores: Apdex = 0.00 [1.0]*, V/M = 0.00
# Query_time sparkline: |       ^|
# Time range: all events occurred at 2011-12-23 17:07:16
# Attribute    pct   total     min     max     avg     95%  stddev  median
# ============ === ======= ======= ======= ======= ======= ======= =======
# Count          0       1
# Exec time      3     23s     23s     23s     23s     23s       0     23s
# Lock time      1   101us   101us   101us   101us   101us       0   101us
# Rows sent     99   8.31M   8.31M   8.31M   8.31M   8.31M       0   8.31M
# Rows examine   0      24      24      24      24      24       0      24
# Rows affecte   0       0       0       0       0       0       0       0
# Rows read     99   8.31M   8.31M   8.31M   8.31M   8.31M       0   8.31M
# Bytes sent    93 275.07M 275.07M 275.07M 275.07M 275.07M       0 275.07M
# Tmp tables     0       0       0       0       0       0       0       0
# Tmp disk tbl   0       0       0       0       0       0       0       0
# Tmp tbl size   0       0       0       0       0       0       0       0
# Query size     0      92      92      92      92      92       0      92
# String:
# Databases    another_db
# Hosts
# InnoDB trxID 83E808
# Last errno   0
# Users        another_db
# Query_time distribution
#   1us
#  10us
# 100us
#   1ms
#  10ms
# 100ms
#    1s
#  10s+  ################################################################
# Tables
#    SHOW TABLE STATUS FROM `another_db` LIKE &apos;customer&apos;\G
#    SHOW CREATE TABLE `another_db`.`customer`\G
#    SHOW TABLE STATUS FROM `another_db` LIKE &apos;address&apos;\G
#    SHOW CREATE TABLE `another_db`.`address`\G
#    SHOW TABLE STATUS FROM `another_db` LIKE &apos;category&apos;\G
#    SHOW CREATE TABLE `another_db`.`category`\G
# EXPLAIN /*!50100 PARTITIONS*/
select customer.store_id, address.address, category.name
  from customer, address, category\G
</pre>
<p>Let&#x2019;s again take a look at the 95% column in the above output. And you can clearly see that the problem with this query is that its reading and sending far too many rows (8.31M) and sending far too much data (275M). Going down quickly to the &#x201C;Tables&#x201D; section, you can see why that is happening: &#x201C;Three tables joined without a join condition meaning a cartesian product of all the rows in all the three tables&#x201D;. See how easily you could pin-point the cause of slowness.<br>
<em>This query was actually executed on a demo of a MySQL Web Client running on one of the MySQL servers managed by me, providing me with good reason to turn on <code>safe-updates</code> option.</em></p>
<h3>Gather Even More Stats with some extra love from Percona Server!</h3>
<p>My colleagues at Percona have built in much more verbosity to what is output in the slow query log, which would give you even more insight into what is actually going on behind the scene during the execution of a particular slow query. This is through the edition of a new variable available in Percona Server 5.1 and above called <strong>log_slow_verbosity</strong>. You can read more about this variable and some other diagnostics added to the Percona server from this <a href="http://www.percona.com/doc/percona-server/5.1/diagnostics/slow_extended.html?ref=ovaistariq.net">link</a>. The variable <code>log_slow_verbosity</code> can have the values &#x2018;microtime&#x2019;, &#x2018;query_plan&#x2019;, &#x2018;innodb&#x2019; and &#x2018;full&#x2019;. Let&#x2019;s turn on log_slow_verbosity as follows:</p>
<pre class="mysql">set session log_slow_verbosity=&apos;microtime,query_plan,innodb&apos;;</pre>
<p>And see how verbose the new entry in slow log is:</p>
<pre class="mysql">
# Time: 111228 11:52:30
# User@Host: root[root] @ localhost []
# Thread_id: 57  Schema: mywebsql_demo  Last_errno: 0  Killed: 0
# Query_time: 204.981516  Lock_time: 0.000133  Rows_sent: 10000  Rows_examined: 8721904  Rows_affected: 0  Rows_read: 10000
# Bytes_sent: 164952  Tmp_tables: 2  Tmp_disk_tables: 1  Tmp_table_sizes: 1995142008
# InnoDB_trx_id: 856C30
# QC_Hit: No  Full_scan: Yes  Full_join: Yes  Tmp_table: Yes  Tmp_table_on_disk: Yes
# Filesort: Yes  Filesort_on_disk: Yes  Merge_passes: 662
#   InnoDB_IO_r_ops: 1  InnoDB_IO_r_bytes: 16384  InnoDB_IO_r_wait: 0.034391
#   InnoDB_rec_lock_wait: 0.000000  InnoDB_queue_wait: 0.000000
#   InnoDB_pages_distinct: 11
SET timestamp=1325073150;
select customer.store_id, address.address, category.name   from customer, address, (select * from category) as category order by customer.store_id limit 10000;
</pre>
<p>See how much more information the slow query log has now, it reports everything from InnoDB stats to on disk filesort was needed for the query, etc. Now you can clearly see this is much much more helpful then the regular slow query statistics reported by the vanilla MySQL.</p>
<h3>Conclusion</h3>
<p>The only conclusion, I can make out is &#x201C;Get yourself <a href="http://www.percona.com/software/percona-server/?ref=ovaistariq.net">Percona Server</a>, turn on log_slow_verbosity and start using pt-query-digest&#x201D;, your job of identifying bottleneck queries will be all the more simpler then.</p>
<!--kg-card-end: html-->]]></content:encoded></item></channel></rss>