<?xml version="1.0" encoding="UTF-8"?>
<!-- generator="wordpress/1.5.2" -->
<rss version="2.0" 
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
>

<channel>
	<title>Internet Super Hero</title>
	<link>http://blog.ulf-wendel.de</link>
	<description>It's all about Nixnutz</description>
	<pubDate>Tue, 15 May 2012 13:13:26 +0000</pubDate>
	<generator>http://wordpress.org/?v=1.5.2</generator>
	<language>en</language>

		<item>
		<title>Some throttling for PECL/mysqlnd_ms 1.4</title>
		<link>http://blog.ulf-wendel.de/2012/some-throttling-for-peclmysqlnd_ms-14/</link>
		<comments>http://blog.ulf-wendel.de/2012/some-throttling-for-peclmysqlnd_ms-14/#comments</comments>
		<pubDate>Tue, 15 May 2012 13:11:37 +0000</pubDate>
		<dc:creator>Administrator</dc:creator>
		
	<category>PlanetMySQL (english)</category>
	<category>PlanetPHP (english)</category>
		<guid>http://blog.ulf-wendel.de/2012/some-throttling-for-peclmysqlnd_ms-14/</guid>
		<description><![CDATA[	
Users of MySQL Replication sometimes throttle client requests to give slaves time to catch up to the master. PECL/mysqlnd_ms 1.4, the current development version, features some throttling through the quality-of-service filter and global transaction identifier (GTID). Both the plugins client-side GTID emulation and the MySQL 5.6 built-in GTID feature can be used to slow down [...]]]></description>
			<content:encoded><![CDATA[	<p>
Users of MySQL Replication sometimes throttle client requests to give slaves time to catch up to the master. <a href="http://www.php.net/mysqlnd_ms">PECL/mysqlnd_ms</a> 1.4, the current development version, features some throttling through the quality-of-service filter and global transaction identifier (GTID). Both the plugins <a href="http://de3.php.net/manual/de/mysqlnd-ms.gtid.php">client-side GTID emulation</a> and the <a href="http://dev.mysql.com/doc/refman/5.6/en/replication-gtids.html">MySQL 5.6 built-in GTID feature</a> can be used to slow down PHP MySQL requests, if wanted.
</p>
	<h3>How its done</h3>
	<p>
The replication plugin has a neat feature called <a href="http://de3.php.net/manual/de/mysqlnd-ms.qos-consistency.php">quality-of-service</a> filter. If, for example, the quality of service you need from a MySQL Replication cluster is &quot;read your writes&quot;, you call <code><a href="http://de3.php.net/mysqlnd_ms_set_qos">mysqlnd_ms_set_qos</a>($connection, MYSQLND_MS_QOS_CONSISTENCY_SESSION)</code>. This instructs the plugin to either use a master or a slave, that has replicated your writes already, for all further reads. The plugin takes care of picking an appropriate cluster node. Once you are done with &quot;read your writes&quot; you can relax the service quality to make node selection faster.
</p>
	<p>
By default, <code>MYSQLND_MS_QOS_CONSISTENCY_SESSION</code> will enforce reading from the master. This is undesired as it increases the load on the master. However, before the introduction of global transaction identifiers, there was no safe way of knowing whether a slave had replicated a certain update already or not.
</p>
	<p>
Using either the plugins GTID emulation or the MySQL 5.6 build-in GTID feature, one can reliably check the up-to-date status of a slave using a SQL <code>SELECT</code> statement.  GTIDs are some kind of unique transaction sequence numbers. If you know the transaction sequence number of a write operation, you can check whether it has been replicated using a statement like, for example, <code>SELECT GTID_SUBSET('gtid_of_write', @@GLOBAL.GTID_DONE) AS trx_id FROM DUAL</code>. Please, check my previous posts for a more precise description of the GTID feature. This statement will check the replication status and return immediately.</p>
	<p><h3>SQL_THREAD_WAIT_AFTER_GTIDS(string gtids [, timeout])</h3>
	<p>
Alternatively, a MySQL 5.6 user can issue <code>SELECT SQL_THREAD_WAIT_AFTER_GTIDS('gtid_of_write')</code> which will block until either the slave has replicated the write in question or the statement times out. This is great to throttle clients and prevent them to send new updates before the slaves have caught up. This is what <em>some</em> throttling is about. You can control which logic PECL/mysqlnd_ms shall use when searching for an up-to-date slave.
</p>
	<p><a id="more-354"></a></p>
	<p>
Strictly speaking, you could do it in 1.3 already, if using MySQL 5.6, which is not GA yet. GTIDs are opaque to the plugin. The configuration contains a SQL statement to fetch <code>gtid_of_write</code> and one to check if <code>gtid_of_write</code> has been replicated already. You have been free to either use  <code>SQL_THREAD_WAIT_AFTER_GTIDS</code> or not for those config settings.
</p>
	<h3>The new bit</h3>
	<p>
New is a <code>wait_for_gtid_timeout</code> setting that can be used with the GTID emulation. If <code>wait_for_gtid_timeout</code> is set, the plugin will poll a slaves state for <code>wait_for_gtid_timeout</code> seconds regardless of the SQL statement configured. The plugin first runs the SQL statement to check if <code>gtid_of_write</code> has been replicated already. If not, it checks if there is time left for another poll attempt, sleeps for second and polls the status again.
</p>
	<p>
All this is done transparently in the background. All the application does is formulate its quality of service needs.
</p>
	<h3>Throttling makes synchronization costs visible</h3>
	<p>
Throttling client requests should not be understood as a hack. MySQL Replication happens to be a lazy primary copy system. All updates must be performed on the primary (master). Synchronization of secondaries (slaves) is lazy. Update transactions are finished once the primary has finished them.  An update transaction never waits for secondaries to catch up. This is an easy to implement, often fast and simple approach.
</p>
	<p>
The drawbacks are temporarily stale data on the secondaries and limited gains in availability over a single server.
</p>
	<p>
Clients get confirmation for update transactions as soon as they are finished on the primary. As soon as they are saved on just one server. There is no guarantee that the transaction ever makes it to a secondary. In the unlikely worst case, the primary crashes in an unrecoverable manner and transactions are lost before being replicated. Thus, little gain over a single server. If you don&#8217;t want that, you need eager synchronization. This is what MySQL Cluster offers, if you want it. For eager synchronization one needs to slow down updates and wait for one or all replicas to confirm the update. If updating one secondary is all you need, go for <a href="http://dev.mysql.com/doc/refman/5.5/en/replication-semisync.html">MySQL Semisynchronous Replication</a>.
</p>
	<p>
It may not be technically valid comparison, however, the slow down and wait reminds me of throttling. MySQL lets you choose whether you want to do the wait on demand and on the client side (MySQL Replication: lazy synchronization) or built-in to the distributed system (MySQL Cluster: eager synchronization). Putting all this in a matrix shows the wide range of  database replication options that MySQL has to offer.
</p>
	<table border="0" cellspacing="2" cellpadding="2">
	<tr>
	<td colspan="2">&nbsp;</td>
	<th bgcolor="#e0e0e0"  colspan="2" align="center" valign="top">Update: where</th>
	</tr>
	<tr>
	<td colspan="2">&nbsp;</td>
	<th  bgcolor="#e0e0e0" align="center" valign="top">Primary copy</th>
	<th  bgcolor="#e0e0e0" align="center" valign="top">Update anywhere</th>
	</tr>
	<tr>
	<th bgcolor="#e0e0e0" align="center" valign="middle" rowspan="2">Synch.:<br />when</th>
	<th bgcolor="#e0e0e0" align="center" valign="middle">Eager</th>
	<td align="center" valign="top">(MySQL Semisynchronous Replication - one secondary eager, rest lazy)</td>
	<td align="center" valign="top">MySQL Cluster</td>
	</tr>
	<tr bgcolor="#f0f0f0">
	<th  bgcolor="#e0e0e0" align="center" valign="middle">Lazy</th>
	<td align="center" valign="top">MySQL Replication</td>
	<td align="center" valign="top">(MySQL Cluster WAN mirror using MySQL Replication - automatic conflict detection)</td>
	</tr>
	</table>
	<p>Happy hacking!</p>
	<p  align="center">
<a href="http://twitter.com/#!/Ulf_Wendel">@Ulf_Wendel&nbsp;<img src="http://blog.ulf-wendel.de/images/twitter.png" align="middle" alt="Follow me on Twitter"/></a>
</p>
]]></content:encoded>
			<wfw:commentRSS>http://blog.ulf-wendel.de/2012/some-throttling-for-peclmysqlnd_ms-14/feed/</wfw:commentRSS>
	</item>
		<item>
		<title>PECL/mysqlnd_ms 1.4 = charset pitfalls solved</title>
		<link>http://blog.ulf-wendel.de/2012/peclmysqlnd_ms-14-charset-pitfalls-solved/</link>
		<comments>http://blog.ulf-wendel.de/2012/peclmysqlnd_ms-14-charset-pitfalls-solved/#comments</comments>
		<pubDate>Fri, 27 Apr 2012 15:41:30 +0000</pubDate>
		<dc:creator>Administrator</dc:creator>
		
	<category>PlanetMySQL (english)</category>
	<category>PlanetPHP (english)</category>
		<guid>http://blog.ulf-wendel.de/2012/peclmysqlnd_ms-14-charset-pitfalls-solved/</guid>
		<description><![CDATA[	Tweaking is the motto - what an easy release PECL/mysqlnd_ms 1.4  will be!  The first tweak for the next stable version of the mysqlnd replication and load balancing plugin solves pitfalls  around charsets. String escaping now works on lazy connection handles (default) prior to establishing a connection to MySQL. A new server_charset [...]]]></description>
			<content:encoded><![CDATA[	<p>Tweaking is the motto - what an easy release <a href="http://www.php.net/mysqlnd_ms">PECL/mysqlnd_ms</a> 1.4  will be!  The first tweak for the next stable version of the mysqlnd replication and load balancing plugin solves pitfalls  around charsets. String escaping now works on lazy connection handles (default) prior to establishing a connection to MySQL. A new <code>server_charset</code> setting has been introduced for this. The way it works also prevents you from the risk of using a different charset for escaping than used later on for your connection.
</p>
	<h3>Lazy connections and <code>server_charset</code></h3>
	<p>
PECL/mysqlnd_ms is a load balancer. A users connection handle can point to different nodes of a replication cluster over time. For example, if using MySQL Replication, the connection handle may point to the master for running writes and, later on, to one of the slaves for reads.  At the very moment a user opens a connection handle, the load balancer does not yet know which cluster node needs to be queried first.
</p>
	<p>
<code></p>
	<pre>
/* Load balanced following &quot;myapp&quot; section rules from the plugins config file */
$mysqli = new mysqli(&quot;myapp&quot;, &quot;username&quot;, &quot;password&quot;, &quot;database&quot;);
$pdo = new PDO('mysql:host=myapp;dbname=database', 'username', 'password');
$mysql = mysql_connect(&quot;myapp&quot;, &quot;username&quot;, &quot;password&quot;);
</pre>
	<p></code>
</p>
	<p>
Thus, the plugin delays opening a MySQL connection to any configured cluster node (master or slave) until a node has been selected for statement execution. The plugin calls this lazy connections. Instead of openening a connection to a default node or even opening connections to all nodes, it waits and sees.
</p>
	<p>
<code></p>
	<pre>
/* Nothing but a handle, no MySQL connection opened so far*/
$mysqli = new mysqli(&quot;myapp&quot;, &quot;username&quot;, &quot;password&quot;, &quot;database&quot;);
/* Escaping on a lazy connection is not possible - will emit a warning */
$mysqli-&gt;real_escape(&quot;What charset to use?&quot;);
/* A node is picked and a connection will be openend */
$mysqli-&gt;query(&quot;SELECT 'connection will be opened now' AS _msg FROM DUAL&quot;);
</pre>
	<p></code>
</p>
	<p>
While lazy connections potentially help to keep the number of connections opened as low as possible, there is a problem. Which charset to use for string escaping prior to opening a connection to MySQL? PECL/mysqlnd_ms 1.4 will search for a <code>server_charset</code> setting in its <a href="http://docs.php.net/manual/en/mysqlnd-ms.plugin-ini-json.php">configuration file</a> and use it. If it is not there, it will bark at you, pretty much like all previous stable releases. A warning will be thrown that reads like <code>(mysqlnd_ms) string escaping doesn't work without established connection</code> in the current series and is a bit more verbose in the 1.4 series, like <code>(mysqlnd_ms) string escaping doesn't work without established connection. Possible solution is to add server_charset to your configuration</code>
</p>
	<p>
Setting <code>server_charset</code> removes the warning. PECL/mysqlnd_ms 1.4 will use the <code>server_charset</code> to do the string escaping. At any time thereafter the user can change the charset using an API call for string escaping with a different charset. SQL statements shall not be used to change charsets as they are not monitored by the plugin. However, upon establishing a connection to any MySQL server, the connection will be set to <code>server_charset</code> again.
</p>
	<h3>No need to take care of the server configuration</h3>
	<p>
Enforcing the configured <code>server_charset</code> whenever a connection is opened free&#8217;s the administrator from the need to set the same default charset on all servers. When using version 1.3 or older you should make sure that servers use the same charset. This prevents tapping into the pitfall of escaping a string using the charset of the first server contacted, then switching the connection to another server/connection with a different charset and accidently using a wrongly escaped string.
</p>
	<p>
More tweaks and improvements considered for version 1.4 are listed at <a href="http://wiki.php.net/pecl/mysqlnd_ms">http://wiki.php.net/pecl/mysqlnd_ms</a>. Please, do not understand the list as a firm promise that everything will be implemented. Feel free to add ideas or tasks to the wiki page.
</p>
	<p>Happy hacking!</p>
	<p  align="center">
<a href="http://twitter.com/#!/Ulf_Wendel">@Ulf_Wendel&nbsp;<img src="http://blog.ulf-wendel.de/images/twitter.png" align="middle" alt="Follow me on Twitter"/></a>
</p>
]]></content:encoded>
			<wfw:commentRSS>http://blog.ulf-wendel.de/2012/peclmysqlnd_ms-14-charset-pitfalls-solved/feed/</wfw:commentRSS>
	</item>
		<item>
		<title>Slides: MySQL 5.6 Global Transaction Identifier and PECL/mysqlnd_ms for session consistency</title>
		<link>http://blog.ulf-wendel.de/2012/slides-mysql-56-global-transaction-identifier-and-peclmysqlnd_ms-for-session-consistency/</link>
		<comments>http://blog.ulf-wendel.de/2012/slides-mysql-56-global-transaction-identifier-and-peclmysqlnd_ms-for-session-consistency/#comments</comments>
		<pubDate>Tue, 27 Mar 2012 14:19:57 +0000</pubDate>
		<dc:creator>Administrator</dc:creator>
		
	<category>PlanetMySQL (english)</category>
	<category>PlanetPHP (english)</category>
		<guid>http://blog.ulf-wendel.de/2012/slides-mysql-56-global-transaction-identifier-and-peclmysqlnd_ms-for-session-consistency/</guid>
		<description><![CDATA[	Why do we have to bother about built-in GTID support in MySQL 5.6 at all? Sure, it is a tremendous step forward for a lazy primary copy system like MySQL Replication. Period. GTIDs make server-side failover  easier (slides). And, load balancer, including PECL/mysqlnd_ms as an example of a driver integrated load balancer, can use [...]]]></description>
			<content:encoded><![CDATA[	<p>Why do we have to bother about built-in GTID support in MySQL 5.6 at all? Sure, it is a tremendous step forward for a lazy primary copy system like MySQL Replication. Period. GTIDs make server-side failover  easier (<a href="http://www.slideshare.net/nixnutz/mysql-56-global-transaction-identifier-use-case-failover">slides</a>). And, load balancer, including <a href="http://php.net/mysqlnd_ms">PECL/mysqlnd_ms</a> as an example of a driver integrated load balancer, can use them to provide session consistency. Please, see the slides. But&#8230;
</p>
	<p align="center">
	<div style="width:425px" id="__ss_12173656"> <strong style="display:block;margin:12px 0 4px"><a href="http://www.slideshare.net/nixnutz/mysql-56-global-transaction-ids-use-case-session-consistency" title="MySQL 5.6 Global Transaction IDs - Use case: (session) consistency" target="_blank">MySQL 5.6 Global Transaction IDs - Use case: (session) consistency</a></strong> <iframe src="http://www.slideshare.net/slideshow/embed_code/12173656" width="425" height="355" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"></iframe><br />
<div style="padding:5px 0 12px"> View more <a href="http://www.slideshare.net/" target="_blank">presentations</a> on <a href="http://www.slideshare.net/nixnutz" target="_blank">MySQL and mysqlnd</a> </div>
 </div>
	</p>
	<p>
&#8230; the primary remains a single point of failure.  GTIDs can be described as cluster-wide transaction counters generated on the master. In case of a master failure, the slave that has replicated the highest transaction counter shall be promoted to become the master. Its the most current slave. Failover made easy - no doubt! Adequately deployed, you should reach very reasonable availability.
</p>
	<h3>Know the limits of replicated systems</h3>
	<p>
A multi-master (update anywhere) design does not have a single point of failure. But among the biggest is scaling a multi-master solution. <a href="http://en.wikipedia.org/wiki/Jim_Gray_%28computer_scientist%29">Jim Gray</a> and Pat Helland concluded 1996 in &quot;<a href="http://research.microsoft.com/apps/pubs/default.aspx?id=68247">The Dangers of Replication and a Solution</a>&quot;: <cite>Update anywhere-anytime-anyway transactional replication has unstable behavior as the workload scales up: a ten-fold increase in nodes and traffic gives a thousand fold increase in deadlocks or reconciliations.</cite>. N^3 - buuuhhhh, anything worse than linear scale is not appreciated. Guess what: Microsoft SQL Azure is using primary copy combined with partitioning.
</p>
	<p><a id="more-353"></a></p>
	<p>
In practice things are not that bad, particulary not for a small number of nodes and recent algorithms.  For example, <a href="http://dev.mysql.com/tech-resources/articles/mysql-cluster-7.2-ga.html">MySQL Cluster</a> (<a href="http://dev.mysql.com/news-and-events/web-seminars/display-695.html">related webinar on March 29</a>) is a  true multi-master solution - even eager/synchronous.  To overcome the write-scale limitations it has built-in partitioning (sharding). The two classical scale-out solutions - replication and partitioning - are combined in one product.  If you want extreme performance and are ready to pay for the costs of partitioning&#8230; try it.
</p>
	<h3>Anything to learn from the NoSQL kids on the block?</h3>
	<p>
 Some other kids offer relaxed eventual consistency just as MySQL Replication does. Sometimes the <a href="http://en.wikipedia.org/wiki/CAP_theorem">CAP theorem</a> is cited as an excuse for it . Some leave conflict resolution, even conflict detection to the application developer . A massively scalabale, high available, synchronous update anywhere solution with built-in conflict resolution - the big thing we all dream of - is hard to create.
</p>
	<h3>In the meanwhile&#8230; - maybe custer-aware APIs</h3>
	<p>
While we all wait for the one-fits-all solution, there is something we can do. We can start to tell our load balancers precisely what we need and request no higher level of service than needed.  Consistency  - as in CAP - is one aspect of service quality. We should start to have cluster-aware APIs abstracting the details of replication architectures. Then, our load balancers, including PECL/mysqlnd_ms can hide everything that makes working with a cluster complicated (connection pooling, request splitting and redirection, failover, node selection, load distribution, &#8230;). Also, vendors can start to play with consistency to improve performance without messing up application logic.
</p>
	<p>
Below is how you use the PECL/mysqlnd_ms 1.2+ function <code>mysqlnd_ms_set_qos()</code> to switch between eventual consistency (stale data allowed) and session concistency (read-your-writes).  MySQL Replication details hidden behind a function call.
</p>
	<p><pre>
<code>
$mysqli = new mysqli(&quot;myapp&quot;, &quot;username&quot;, &quot;password&quot;, &quot;database&quot;);
if (!$mysqli)
  /* Of course, your error handling is nicer... */
  die(sprintf(&quot;[%d] %s\n&quot;, mysqli_connect_errno(), mysqli_connect_error()));
	
/* read-write splitting: master used */
if (!$mysqli-&gt;query(&quot;INSERT INTO orders(order_id, item) VALUES (1, 'christmas tree, 1.8m')&quot;)) {
   /* Please use better error handling in your code */
  die(sprintf(&quot;[%d] %s\n&quot;, $mysqli-&gt;errno, $mysqli-&gt;error));
}
	
/* Request session consistency: read your writes */
if (!mysqlnd_ms_set_qos($mysqli, MYSQLND_MS_QOS_CONSISTENCY_SESSION))
  die(sprintf(&quot;[%d] %s\n&quot;, $mysqli-&gt;errno, $mysqli-&gt;error));
	
/* Plugin picks a node which has the changes, here: master */
if (!$res = $mysqli-&gt;query(&quot;SELECT item FROM orders WHERE order_id = 1&quot;))
  die(sprintf(&quot;[%d] %s\n&quot;, $mysqli-&gt;errno, $mysqli-&gt;error));
	
var_dump($res-&gt;fetch_assoc());
	
/* Back to eventual consistency: stale data allowed */
if (!mysqlnd_ms_set_qos($mysqli, MYSQLND_MS_QOS_CONSISTENCY_EVENTUAL))
  die(sprintf(&quot;[%d] %s\n&quot;, $mysqli-&gt;errno, $mysqli-&gt;error));
	
/* Plugin picks any slave, stale data is allowed */
if (!$res = $mysqli-&gt;query(&quot;SELECT item, price FROM specials&quot;))
  die(sprintf(&quot;[%d] %s\n&quot;, $mysqli-&gt;errno, $mysqli-&gt;error));
</code>
</pre>
	</p>
	<h3>GTID for clients? Buzz alarm!</h3>
	<p>
PECL/mysqlnd_ms 1.3 does not bring any ground breaking changes with regards to consistency or GTIDs. It can now either use the driver built-in GTID emulation (1.2+) or the server-side GTID feature (1.3+, MySQL 5.6) for session consistency. That&#8217;s all. I confess, the slide title is pure buzz. But in every tale is some truth.
</p>
	<h3>Cluster-aware APIs and better load balancer? Follow up!</h3>
	<p>
I&#8217;m convinced that good load balancers can make application developers life much easier. Read-your-writes and session consistency is an example  how new API calls may come handy. Transparently replacing remote slave accesses with client-side cache accesses (coming with 1.3) is an example how load balancers can optimize overall cluster performance.
</p>
	<p>
Whoever designs a replication solution in 2012 should include the load balancer into his considerations&#8230; - even for multi-master.
</p>
	<p>Happy hacking!</p>
	<p  align="center">
<a href="http://twitter.com/#!/Ulf_Wendel">@Ulf_Wendel&nbsp;<img src="http://blog.ulf-wendel.de/images/twitter.png" align="middle" alt="Follow me on Twitter"/></a>
</p>
]]></content:encoded>
			<wfw:commentRSS>http://blog.ulf-wendel.de/2012/slides-mysql-56-global-transaction-identifier-and-peclmysqlnd_ms-for-session-consistency/feed/</wfw:commentRSS>
	</item>
		<item>
		<title>Slides: MySQL 5.6 Global Transaction Identifier and PECL/mysqlnd_ms for failover</title>
		<link>http://blog.ulf-wendel.de/2012/slides-mysql-56-global-transaction-identifier-and-peclmysqlnd_ms-for-failover/</link>
		<comments>http://blog.ulf-wendel.de/2012/slides-mysql-56-global-transaction-identifier-and-peclmysqlnd_ms-for-failover/#comments</comments>
		<pubDate>Tue, 13 Mar 2012 13:00:23 +0000</pubDate>
		<dc:creator>Administrator</dc:creator>
		
	<category>PlanetMySQL (english)</category>
	<category>PlanetPHP (english)</category>
		<guid>http://blog.ulf-wendel.de/2012/slides-mysql-56-global-transaction-identifier-and-peclmysqlnd_ms-for-failover/</guid>
		<description><![CDATA[	
	 MySQL 5.6 Global Transaction Identifier - Use case: Failover 
 View more presentations on PHP and MySQL 
 
	
	
The long lasting MySQL replication failover issue is cured. MySQL 5.6 makes master failover easy, PECL/mysqlnd_ms assists with the client/connection failover.  Compared to the past this is a significant step towards improving MySQL replication cluster [...]]]></description>
			<content:encoded><![CDATA[	<p align="center">
	<div style="width:425px" id="__ss_11985353"> <strong style="display:center;margin:12px 0 4px"><a href="http://www.slideshare.net/nixnutz/mysql-56-global-transaction-identifier-use-case-failover" title="MySQL 5.6 Global Transaction Identifier - Use case: Failover" target="_blank">MySQL 5.6 Global Transaction Identifier - Use case: Failover</a></strong> <iframe src="http://www.slideshare.net/slideshow/embed_code/11985353" width="425" height="355" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"></iframe><br />
<div style="padding:5px 0 12px"> View more <a href="http://www.slideshare.net/" target="_blank">presentations</a> on <a href="http://www.slideshare.net/nixnutz" target="_blank">PHP and MySQL</a> </div>
 </div>
	</p>
	<p>
The long lasting MySQL replication failover issue is cured. MySQL 5.6 makes master failover easy, <a href="http://de.php.net/mysqlnd_ms">PECL/mysqlnd_ms</a> assists with the client/connection failover.  Compared to the past this is a significant step towards improving MySQL replication cluster availability, eleminating the need to use 3rd party tools in many cases. The slides illustrate the basic idea, <a href="http://blog.ulf-wendel.de/2011/wonders-of-global-transaction-id-injection/">as blogged about before</a>.
</p>
	<p>
There is not much to say about the feature as such. Slave to master promotion works without hassles, finally. Regardless if you do failover because of an error of the current master or switchover because you want to change the master server, its easy now. Congratulations to the replication team!
</p>
	<h3>Limitations of the current server implementation</h3>
	<p>
The global transaction identifier implementation in MySQL 5.6 has a couple of limitations, though. Its not hard to guess that mixing transactional and non-transactional updates in one transaction can cause problems.  Its pretty much the first pitfall I ran into when trying to setup a MySQL 5.6.5-m8 (not 5.6.4-m8&#8230;) slave using a <code>mysqldump</code> generated SQL dump.  MySQL bailed at me and stopped me from failing.
</p>
	<p><a id="more-351"></a></p>
	<p>
Let a master run a transaction which first updates an InnoDB table. followed by an update of a MyISAM table, followed by another update: <code>t(U<sup>InnoDB</sup>, U<sup>MyISAM</sup>, U<sup>X</sup>)</code>. Let the binary log settings be so that this transaction is written as one to the binary log (<code>binlog_format=statement, binlog_direct_non_transactional_updates=0</code>).  It is then copied &#8220;as is&#8221; to the relay log of a slave. Assume that the slave runs with different binary log settings so that <code>t(U<sup>InnoDB</sup>, U<sup>MyISAM</sup>, U<sup>X</sup>)</code> is split up to <code>t(U<sup>MyISAM</sup>), t(U<sup>InnoDB</sup>[, &#8230;])</code>and logged as distinct transactions in the slaves binary log.  </p>
	<table cellspacing="2" cellpadding="2">
	<tr bgcolor="#e0e0e0">
	<th align="center" valign="top" colspan="4">Worst case: conflicting binary log settings
<th>
</tr>
	<tr>
	<th bgcolor="#f0f0f0" align="center" valign="top" colspan="2">Master</th>
	<th bgcolor="#f0f0f0" align="center" valign="top" colspan="2">Slave</th>
	</tr>
	<tr>
	<td align="left" valign="top" >GTID=M:1</th>
	<td align="left" valign="top"><code>t(U<sup>InnoDB</sup>, U<sup>MyISAM</sup>, U<sup>X</sup>)</code></td>
	<td align="left" valign="top">GTID=M:1</td>
	<td align="left" valign="top"><code>t(U<sup>MyISAM</sup>)</code></td>
	</tr>
	<tr>
	<td colspan="2">
	<td align="left" valign="top" bgcolor="#fff0f0">GTID=M:1</td>
	<td align="left" valign="top"><code>t(U<sup>InnoDB</sup>[, &#8230;])</code></td>
	</tr>
	</table>
	<p>
Because slaves must preserve global transaction identifiers they got from their master, the two resulting transactions are given the same identifier. The transaction identifier in the slaves binary log is no longer unique, it now refers to two transactions not just one (issue #1).  Any slave that would read from the binary log of the above slave may loose the InnoDB transaction because it may refuse to execute a transaction using an id that has been executed already (issue #2).
</p>
	<p>
The workaround? Don&#8217;t mix InnoDB and MyISAM updates in one transaction.  To me it does not sound that much of an issue in 2012. Please note, I&#8217;m describing my experience with MySQL 5.6.5-m8, which is a development version.
</p>
	<h3>The load balancer update</h3>
	<p>
MySQL Replication takes a primary copy approach to replication. A primary/master handles all the updates. Read-only replicas/slaves replicate from the primary. The primary is a single point of failure.
</p>
	<table cellspacing="2" cellpadding="2" width="100%">
	<tr>
	<td bgcolor="#f0f0f0" align="left" valign="top">Writes</td>
	<td  bgcolor="#f0fff0" align="center" colspan="3">Primary/master</td>
	</tr>
	<tr>
	<td bgcolor="#f0f0f0" align="left" valign="top">Reads</td>
	<td bgcolor="#f0fff0" align="center" valign="top">Slave</td>
	<td align="center" valign="top">&nbsp;</td>
	<td bgcolor="#f0fff0" align="center" valign="top">Slave</td>
	</tr>
	</table>
	<p>
The failure of a slave is unproblematic. A client usually has plenty of other slaves to start reading from.  If no slave is available, reads can even be forwarded to the master.
</p>
	<table cellspacing="2" cellpadding="2" width="100%">
	<tr>
	<td align="center" valign="top" colspan="3" bgcolor="#f0f0f0">PHP</td>
	</tr>
	<tr>
	<td  align="center" valign="top" colspan="3" bgcolor="#e0e0e0">Load Balancer, e.g PECL/mysqlnd_ms
<td>
 </tr>
	<tr>
	<td align="center" valign="top" colspan="3">Read</td>
	</tr>
	<tr>
	<td align="center" valign="top" bgcolor="#fff0f0"><del >Slave</del></td>
	<td align="center" valign="top">&nbsp;</td>
	<td align="center" valign="top" bgcolor="#f0fff0">Slave</td>
	</tr>
	</table>
	<p>
All a PECL/mysqlnd_ms user has to do is check for an error after statement execution. If there&#8217;s one and the error code hints that the server has gone away, the user reruns the statement. The connection handle remains useable all the time. Upon rerun, PECL/mysqlnd_ms openes a new connection to another slave.
</p>
	<p>
<code></p>
	<pre>
do {
  $res = $mysql-&gt;query(&quot;SELECT id, title FROM news&quot;);
} while (isset($connection_error_codes[$mysql-&gt;errno]));
	
if (!$res) {
  bail(&quot;SQL error&quot;, $mysql-&gt;errno, $mysql-&gt;error);
}
</pre>
	<p></code>
</p>
	<p>
A master failure is much more problematic. There is no server to send a write to but the master. The master is a single point of failure.  The new global transaction identifier help to reduce the time it takes to put a new master in place after a failure.
</p>
	<table cellspacing="2" cellpadding="2" width="100%">
	<tr>
	<td align="center" valign="top" colspan="3" bgcolor="#f0f0f0">PHP</td>
	</tr>
	<tr>
	<td  align="center" valign="top" colspan="3" bgcolor="#e0e0e0">Load Balancer, e.g PECL/mysqlnd_ms
<td>
 </tr>
	<tr>
	<td align="center" valign="top" colspan="3">Write</td>
	</tr>
	<tr>
	<td align="center" valign="top" bgcolor="#fff0f0" colspan="3"><del >Master</del></td>
	</tr>
	</table>
	<p>
After a master failure some process needs to promote a former slave to the new master and, preferrable atomically, update all other slaves to start replicating from the new master. The below illustration is a bit confusing. It is intentionally. What happens during the simple to say &#8220;slave to master promotion&#8221; is a complete restructuring of the cluster.
</p>
	<table cellspacing="2" cellpadding="2" width="100%">
	<tr>
	<td bgcolor="#f0f0f0" align="left" valign="top"><del>Writes</del></td>
	<td bgcolor="#e0e0e0" align="left" valign="top">&nbsp;</td>
	<td  bgcolor="#fff0f0" align="center" colspan="3"><del >Primary/master</del> (gone)</td>
	</tr>
	<tr>
	<td bgcolor="#f0f0f0" align="left" valign="top"><del>Read</del></td>
	<td bgcolor="#e0e0e0" align="left" valign="top">Write</td>
	<td bgcolor="#f0fff0" align="center" valign="top"><del>Slave</del> Master (promoted former slave)</td>
	</tr>
	<tr>
	<td bgcolor="#f0f0f0" align="left" valign="top"><del>Read</del></td>
	<td bgcolor="#e0e0e0" align="left" valign="top">Read</td>
	<td bgcolor="#f0fff0" align="center" valign="top">Slave (no change)</td>
	</tr>
	</table>
	<h3>Don&#8217;t forget to update the load balancer</h3>
	<p>
After the cluster has been reorganized, the load balancer configurations must be updated. PECL/mysqlnd_ms happens to be a driver integrated load balancer. However, other than that, it is not different from a classical load balancer.  Whatever process restructures the cluster it must take care of deploying the load balancer configurations afterwards.
</p>
	<p>
Global transaction identifiers are a great help for the biggest part of the failover job - the server side. But, they are no swiss army knife. Don&#8217;t forget to update your load balancer configuration - the client side.  No matter where it is. Whether it is part of the application code, driver integrated or you are using MySQL Proxy.  As long as we are talking primary copy, a master failure will always be a major pain.
</p>
	<p>Happy hacking!</p>
	<p  align="center">
<a href="http://twitter.com/#!/Ulf_Wendel">@Ulf_Wendel&nbsp;<img src="http://blog.ulf-wendel.de/images/twitter.png" align="middle" alt="Follow me on Twitter"/></a>
</p>
]]></content:encoded>
			<wfw:commentRSS>http://blog.ulf-wendel.de/2012/slides-mysql-56-global-transaction-identifier-and-peclmysqlnd_ms-for-failover/feed/</wfw:commentRSS>
	</item>
		<item>
		<title>PECL/mysqlnd_ms:  MySQL 5.6.4-m8+ global transaction identifier feature supported</title>
		<link>http://blog.ulf-wendel.de/2012/peclmysqlnd_ms-mysql-564-m8-global-transaction-identifier-feature-supported/</link>
		<comments>http://blog.ulf-wendel.de/2012/peclmysqlnd_ms-mysql-564-m8-global-transaction-identifier-feature-supported/#comments</comments>
		<pubDate>Tue, 06 Mar 2012 13:05:04 +0000</pubDate>
		<dc:creator>Administrator</dc:creator>
		
	<category>PlanetMySQL (english)</category>
	<category>PlanetPHP (english)</category>
		<guid>http://blog.ulf-wendel.de/2012/peclmysqlnd_ms-mysql-564-m8-global-transaction-identifier-feature-supported/</guid>
		<description><![CDATA[	
MySQL Replication is sometimes critizied for being asynchronous and having slaves that lag behind. True! However, sometimes slaves can be used safely and reliably for read-your-writes. Its easy for PHP MySQL users. All the magic is in the driver. As of yesterday, the development version of PECL/mysqlnd_ms 1.3.0-alpha supports not only a client-side global transaction [...]]]></description>
			<content:encoded><![CDATA[	<p>
MySQL Replication is sometimes critizied for being asynchronous and having slaves that lag behind. True! However, sometimes slaves can be used safely and reliably for read-your-writes. Its easy for PHP MySQL users. All the magic is in the driver. As of yesterday, the development version of <a href="http://docs.php.net/mysqlnd_ms">PECL/mysqlnd_ms</a> 1.3.0-alpha supports not only a client-side global transaction ID emulation but also the  global transaction identifier feature of <a href="https://launchpad.net/~mysql">MySQL 5.6.4-m8</a>.
</p>
	<h3>Read-your-writes (session consistency) with MySQL Replication</h3>
	<p>
A global transaction identifier can be understood as a sequence number for a transaction. The sequence number is incremented whenever a write transaction is performed on a MySQL replication master. Slaves replicate the transaction ID.  After a client has executed  a write on the master he can obtain a global transaction identifier created for his write set. Then, the client can use the ID to find a slave which has replicated the writes already.
</p>
	<table cellspacing="2" cellpadding="2" width="100%">
	<tr bgcolor="#f0f0f0">
	<th colspan="3"><code></p>
	<pre>
$link-&gt;query(&quot;INSERT INTO test(id) VALUES (123)&quot;);
$gtid = mysqlnd_ms_get_last_gtid($link);
</pre>
	<p></code></th>
	</tr>
	<tr>
	<td align="center" valign="top" colspan="3">|</td>
	</tr>
	<tr >
	<td>&nbsp;</td>
	<td bgcolor="#e0e0e0" align="center" valign="top">Master</td>
	<td>&nbsp;</td>
	</tr>
	<tr >
	<td>&nbsp;</td>
	<td  align="center" valign="top">GTID = 27263</td>
	<td>&nbsp;</td>
	</tr>
	<tr>
	<td align="center" valign="top" bgcolor="#e0e0e0">Slave 1</td>
	<td align="center" valign="top"  bgcolor="#e0e0e0">Slave 2</td>
	<td align="center" valign="top" bgcolor="#e0e0e0">Slave 3</td>
	</tr>
	<tr>
	<td align="center" valign="top">GTID = 27263</td>
	<td align="center" valign="top" >GTID = 27251</td>
	<td align="center" valign="top" >GTID = 27263</td>
	</tr>
	</table>
	<p>
Without global transaction identifiers there is no safe and water-proof way of telling whether a slave has replicated the latest changes or not.  Thus, PHP clients in need for session consistency had to query the master only after their first write for the rest of their request. This approach has two downsides: the master has to handle read load at all and it potentially has to handle reads although slaves have caught up.
</p>
	<h3>Client-side emulation and server-side feature</h3>
	<p>
PECL/mysqlnd_ms 1.2.0 has introduced a client-side global transaction ID emulation to solve this.  Details of the server selection and the global transaction ID emulation are greatly hidden from the user. Set the consistency level you need calling <code>mysqlnd_ms_set_qos()</code> and the plugin takes care.  More than 75 pages full of examples, a quickstart and reference materials in the <a href="http://docs.php.net/mysqlnd_ms">PHP manual</a> give the details.  <code>$link</code> can be a MySQL connection from mysql, mysqli or PDO_MySQL, if those have been compiled to use the mysqlnd library, which is a default on all platforms as of PHP 5.4.0.
</p>
	<p>
<code></p>
	<pre>
$link-&gt;query(&quot;INSERT INTO test(id) VALUES (123)&quot;);
$gtid = mysqlnd_ms_get_last_gtid($link);
	
/* requesting read-your-writes */
if (false == mysqlnd_ms_set_qos($link, MYSQLND_MS_QOS_CONSISTENCY_SESSION, MYSQLND_MS_QOS_OPTION_GTID, $gtid)) {
 printf(&quot; [%d] %s\n&quot;, $link-&gt;errno, $link-&gt;error);
}
	
/* do your reads */
	
/* return to relaxed eventual consistency */
if (false == mysqlnd_ms_set_qos($link, MYSQLND_MS_QOS_CONSISTENCY_EVENTUAL)) {
 printf(&quot; [%d] %s\n&quot;, $link-&gt;errno, $link-&gt;error);
}
</pre>
	<p></code>
</p>
	<p>
Maintaining a global transaction ID using a client-side emulation has some limitations. Unless one is faced with an heterogenous environment with MySQL servers of many different versions, this may not be the best option.</p>
	<ul>
	<li>DBAs must deploy global transaction identifier sequence tables on all nodes</li>
	<li>Clients must be able to detect transaction boundaries for proper sequence numbering</li>
	<li>If not all clients update the sequence number gaps are likely. This can easily be the case when not only PHP clients access the master</li>
	</ul>
	<p>
MySQL 5.6.4-m8 or later add a choice by introducing built-in global transaction identifiers.  The server-side approach has none of the listed limitations but may have others that you hopefully will find described in the MySQL Reference Manual soon. PECL/mysqlnd_ms 1.3.0-alpha can either use its own client-side emulation or the server-side feature. From the perspective of a client only after the read-your-writes the only difference is in the SQL that is needed to access and compare global transaction IDs.
</p>
	<h3>Accessing and comparing GTIDs in MySQL 5.6.4-m8+</h3>
	<p>
The MySQL server does not use a simple sequence number as a global transaction identifier. Instead it uses a combination of a server identifier and a sequence number, such as <code>123-some-server-uuid:n-m</code>. The global transaction identifiers can be accessed through the new global server variable <code>GTID_DONE</code> and be compared with the new server SQL function <code>GTID_SUBSET</code>.
</p>
	<p>
<code></p>
	<pre>
&quot;myapp&quot;: {
     &quot;master&quot;: {
         &quot;master_0&quot;: {
             &quot;host&quot;: &quot;localhost&quot;,
             &quot;socket&quot;: &quot;/tmp/mysql.sock&quot;
         }
      },
     &quot;slave&quot;: {
         &quot;slave_0&quot;: {
             &quot;host&quot;: &quot;127.0.0.1&quot;,
             &quot;port&quot;: &quot;3306&quot;
       }
      },
     &quot;global_transaction_id_injection&quot;:{
         &quot;fetch_last_gtid&quot; : &quot;SELECT @@GLOBAL.GTID_DONE AS trx_id FROM DUAL&quot;,
          &quot;check_for_gtid&quot; : &quot;SELECT GTID_SUBSET('#GTID', @@GLOBAL.GTID_DONE) AS trx_id FROM DUAL&quot;,
          &quot;report_error&quot;:true
      }
  }
}
</pre>
	<p></code>
</p>
	<p>
The above is an example PECL/mysqlnd_ms 1.3.0-alpha plugin configuration to use the global transaction identifier feature of MySQL 5.6.  Don&#8217;t let the section name <code>global_transaction_id_injection</code> confuse you. The section <code>global_transaction_id_injection</code> is used for configuring the SQL to fetch the latest GTID and to check if a server has replicated a certain GTID no matter if you want to use the client-side emulation or the server-side feature.
</p>
	<h3>Client-side GTID emulation continues to be supported</h3>
	<p>
 To hint PECL/mysqlnd_ms that you want to use a client-side emulation you must additionally provide a SQL statement for incrementing a GTID at the end of a transaction as shown in the example below.
</p>
	<p>
<code></p>
	<pre>
{
    &quot;myapp&quot;: {
        &quot;master&quot;: {
            &quot;master_0&quot;: {
                &quot;host&quot;: &quot;localhost&quot;,
                &quot;socket&quot;: &quot;/tmp/mysql.sock&quot;
            }
        },
        &quot;slave&quot;: {
            &quot;slave_0&quot;: {
                &quot;host&quot;: &quot;127.0.0.1&quot;,
                &quot;port&quot;: &quot;3306&quot;
            }
        },
        &quot;global_transaction_id_injection&quot;:{
            &quot;on_commit&quot;:&quot;UPDATE test.trx SET trx_id = trx_id + 1&quot;,
            &quot;fetch_last_gtid&quot; : &quot;SELECT MAX(trx_id) FROM test.trx&quot;,
            &quot;check_for_gtid&quot; : &quot;SELECT trx_id FROM test.trx WHERE trx_id >= #GTID&quot;,
            &quot;report_error&quot;:true
        }
    }
}
</pre>
	<p></code>
</p>
	<p>
Comparing the two example configuration you may get the impression MySQL 5.6 could make your life easier&#8230; True? Stay tuned. I didn&#8217;t like everything.
</p>
	<p>
PHP documentation updates related to GTID support by PECL/mysqlnd_ms 1.3.0-alpha (development version, trunk) have been been pushed today. It should take a day or two until they appear on all mirrors.
</p>
	<p>Happy hacking!</p>
	<p  align="center">
<a href="http://twitter.com/#!/Ulf_Wendel">@Ulf_Wendel&nbsp;<img src="http://blog.ulf-wendel.de/images/twitter.png" align="middle" alt="Follow me on Twitter"/></a>
</p>
]]></content:encoded>
			<wfw:commentRSS>http://blog.ulf-wendel.de/2012/peclmysqlnd_ms-mysql-564-m8-global-transaction-identifier-feature-supported/feed/</wfw:commentRSS>
	</item>
		<item>
		<title>PECL/mysqlnd_qc: table pattern based query caching</title>
		<link>http://blog.ulf-wendel.de/2012/peclmysqlnd_qc-table-pattern-based-query-caching/</link>
		<comments>http://blog.ulf-wendel.de/2012/peclmysqlnd_qc-table-pattern-based-query-caching/#comments</comments>
		<pubDate>Fri, 02 Mar 2012 13:56:22 +0000</pubDate>
		<dc:creator>Administrator</dc:creator>
		
	<category>PlanetMySQL (english)</category>
	<category>PlanetPHP (english)</category>
		<guid>http://blog.ulf-wendel.de/2012/peclmysqlnd_qc-table-pattern-based-query-caching/</guid>
		<description><![CDATA[	Cache all queries which match a schema pattern is one of the few visible feature additions to PECL/mysqlnd_qc 1.1, the client-side query cache plugin for the mysqlnd library. As usual, this client-side cache is mostly transparent, works with all PHP MySQL APIs (mysql, mysqli, PDO_MySQL) and, of course, supports various storage backends including Memcache, process [...]]]></description>
			<content:encoded><![CDATA[	<p>Cache all queries which match a schema pattern is one of the few visible feature additions to <a href="http://docs.php.net/mysqlnd_qc">PECL/mysqlnd_qc</a> 1.1, the client-side query cache plugin for the <a href="http://docs.php.net/mysqlnd">mysqlnd</a> library. As usual, this client-side cache is mostly transparent, works with all PHP MySQL APIs (mysql, mysqli, PDO_MySQL) and, of course, supports various storage backends including Memcache, process memory, SQLite, user-defined and more. Please, find details in the <a href="http://de3.php.net/manual/en/mysqlnd-qc.quickstart.php">quickstart</a>.</p>
	<h3>Setting a cache condition</h3>
	<p>
Caching only selected queries is something that could be done in 1.0 already, for example, using a callback. What&#8217;s new is that filtering is built-in to 1.1.  The new feature is straigth forward to use.
</p>
	<p>
<code></p>
	<pre>
mysqlnd_qc_set_cache_condition(
  MYSQLND_QC_CONDITION_META_SCHEMA_PATTERN,
  &quot;test.old%&quot;,
  1);
	
/* cached, TTL = 1s */
$link-&gt;query(&quot;SELECT id, title FROM oldnews&quot;);
	
/* uncached */
$link-&gt;query(&quot;SELECT id, title FROM hotnews&quot;);
</pre>
	<p></code>
</p>
	<p>
Internally, at the C level, we take an optimistic approach to caching. If cache conditions have been set, we start the internal cache logic for every query. Regardless if it contains a SQL hint to enable caching or not, regardless whether it is a <code>SELECT</code> statement or not. After the query has been processed by the MySQL server, the server send the result set to the client. The result set contains of the actual data and meta data. Then, we compare the database and table names from the meta data with the list of cache conditions set. If they match we cache the query. If they don&#8217;t match we drop the recorded wire protocol data and do not put it into the cache.
</p>
	<h3>Other enhancements</h3>
	<p>
The proposed API allows for potential future additions. For example, we may decide to support conditions which define a run time criteria. If a statement exceeds a certain run time, we cache it. Or, a size criteria. Let us know what you need.
</p>
	<p>
However, this is not the main focus of the 1.1 release. The primary goal is to make PECL/mysqlnd_ms and PECL/mysqlnd_qc work together in a way that MySQL Replication slave reads can be transparently replaced with cache accesses, if the application allows for it (<a href="http://blog.ulf-wendel.de/?p=348">more on the idea</a>).  I got it working on my computer but that&#8217;s another story&#8230;
</p>
	<p>Happy hacking!</p>
	<p  align="center">
<a href="http://twitter.com/#!/Ulf_Wendel">@Ulf_Wendel&nbsp;<img src="http://blog.ulf-wendel.de/images/twitter.png" align="middle" alt="Follow me on Twitter"/></a>
</p>
]]></content:encoded>
			<wfw:commentRSS>http://blog.ulf-wendel.de/2012/peclmysqlnd_qc-table-pattern-based-query-caching/feed/</wfw:commentRSS>
	</item>
		<item>
		<title>PECL/mysqlnd_ms: faster slave reads</title>
		<link>http://blog.ulf-wendel.de/2012/peclmysqlnd_ms-faster-slave-accesses/</link>
		<comments>http://blog.ulf-wendel.de/2012/peclmysqlnd_ms-faster-slave-accesses/#comments</comments>
		<pubDate>Tue, 31 Jan 2012 18:59:34 +0000</pubDate>
		<dc:creator>Administrator</dc:creator>
		
	<category>PlanetMySQL (english)</category>
	<category>PlanetPHP (english)</category>
		<guid>http://blog.ulf-wendel.de/2012/peclmysqlnd_ms-faster-slave-accesses/</guid>
		<description><![CDATA[	
Why read stale data from an asynchronous MySQL replica (slave)? Fetch it from a local cache instead! Good for the clusters overall load, good for your applications performance. And, possible with PECL/mysqlnd_ms 1.3, the replication and load balancing plugin for PHP MySQL users.

	The idea is simple
	
Any application using asynchronous MySQL replication must be capable of [...]]]></description>
			<content:encoded><![CDATA[	<p>
Why read stale data from an asynchronous MySQL replica (slave)? Fetch it from a local cache instead! Good for the clusters overall load, good for your applications performance. And, possible with <a href="http://php.net/mysqlnd_ms">PECL/mysqlnd_ms</a> 1.3, the replication and load balancing plugin for PHP MySQL users.
</p>
	<h3>The idea is simple</h3>
	<p>
Any application using asynchronous MySQL replication must be capable of handling stale results read from a slave (replica) that is lagging behind the master. The quality of service that the application needs from the database cluster is low.  If an application explicitly states the minimum service quality it needs, the underlying systems can adopt to it. That&#8217;s a cool thing, because the underlying systems don&#8217;t need to do more work than necessary. In the case of a PHP MySQL user, the first underlying system is the database driver library, which is mysqlnd.
</p>
	<p>
Tell mysqlnd that you can deal with data that is as old as five seconds. Then, mysqlnd can search a matching slave lagging no more than five seconds or even replace the slave access with a TTL-based cache access. Cache? Sure, PECL/mysqlnd_qc, various storage backends including main memory, user-defined, APC and Memcache &#8230; have a look at the <a href="http://de3.php.net/manual/en/mysqlnd-qc.quickstart.php">quickstart</a>.
</p>
	<h3>It exists&#8230;</h3>
	<p>
The first step is done. The development trees of <a href="http://de3.php.net/mysqlnd_qc">PECL/mysqlnd_qc</a> 1.1 and PECL/mysqlnd_ms 1.3 have been de-stabilized.  A first, crude approach to make the query cache and replication plugin work transparently together exists.
</p>
	<p>
<code><br />
./configure --enable-mysqlnd-ms --enable-mysqlnd-ms-cache-support<br />
</code>
</p>
	<p>
PECL/mysqlnd_ms 1.2 introduced the <code>mysqlnd_ms_set_qos()</code> function for setting the service level required from the cluster.
</p>
	<p>
<code></p>
	<pre>
 mysqlnd_ms_set_qos($connection,
  MYSQLND_MS_QOS_CONSISTENCY_EVENTUAL,
  MYSQLND_MS_OPTION_CACHE,
  5);
</pre>
	<p></code>
</p>
	<p>
If you set the service level as shown above, PECL/mysqlnd_ms does never read from a slave that reports itself to be lagging more than <code>5</code> seconds behind the master.  If no matching slave is found, PECL/mysqlnd_ms picks the master. Additionally, PECL/mysqlnd_ms tries to cache all slave queries for up to <code>5</code> seconds. The cache logic is so, that you never get data older than <code>5</code> seconds.
</p>
	<h3>The initial cache logic</h3>
	<p>
First, PECL/mysqlnd_ms asks PECL/mysqlnd_qc if the query is already in the cache. If so, PECL/mysqlnd_ms stops searching slaves, continues working and tries to fetch the results from the cache in the following. If fetching from cache fails, which should happen rarely, it reads the result from a master.
</p>
	<p>
In case the query is not cached yet, PECL/mysqlnd_ms searches for all slaves that lag no more than <code>5</code> seconds. The cache TTL is reduced by the highest lag found. If, for example, there are two slaves, lagging <code>2</code> and <code>3</code> seconds behind, the cache TTL is set to <code>5 - max(2, 3) = 5 - 3 = 2</code> seconds.
</p>
	<table width="100%">
	<tr bgcolor="#e0e0e0">
	<td align="center" valign="top">&nbsp;</td>
	<th align="center" valign="top">MYSQLND_MS_OPTION_CACHE </th>
	<th align="center" valign="top">Slave lag</th>
	<th align="center" valign="top">TTL</th>
	</tr>
	<tr>
	<td align="right" valign="top">Slave 1</td>
	<td align="right" valign="top">5</td>
	<td align="right" valign="top">2</td>
	<td align="right" valign="top"  bgcolor="fff0ff">3</td>
	</tr>
	<tr bgcolor="#f0f0f0">
	<td align="right" valign="top">Slave 2</td>
	<td align="right" valign="top">5</td>
	<td align="right" valign="top" >3</td>
	<th align="right" valign="top" bgcolor="f0fff0">2</th>
	</tr>
	</table>
	<p>
Then, slave selection continues, for example, load balancing is done. At the end of the chain eventually one slave has been selected. The query is run on the slave and put into the cache for <code>2</code> seconds.
</p>
	<h3>How the plugins work together</h3>
	<p>
PECL/mysqlnd_ms does control the cache, PECL/mysqlnd_qc, through SQL hints. PECL/mysqlnd_ms sets exactly the same SQL hints that are also available to the user, as described in the <a href="http://de3.php.net/manual/en/mysqlnd-qc.quickstart.php">PECL/mysqlnd_qc manual</a>.
</p>
	<p>
<code></p>
	<pre>
/*qc=on*//*qc_ttl=2*/SELECT id FROM test
</pre>
	<p></code>
</p>
	<p>
&#8230; and tomorrow: a sneak preview of the new built-in pattern based caching for PECL/mysqlnd_qc 1.1.
</p>
	<p>Happy hacking!</p>
	<p  align="center">
<a href="http://twitter.com/#!/Ulf_Wendel">@Ulf_Wendel&nbsp;<img src="http://blog.ulf-wendel.de/images/twitter.png" align="middle" alt="Follow me on Twitter"/></a>
</p>
]]></content:encoded>
			<wfw:commentRSS>http://blog.ulf-wendel.de/2012/peclmysqlnd_ms-faster-slave-accesses/feed/</wfw:commentRSS>
	</item>
		<item>
		<title>PECL/mysqlnd_qc: query cache statistics log</title>
		<link>http://blog.ulf-wendel.de/2012/peclmysqlnd_qc-query-cache-statistics-log/</link>
		<comments>http://blog.ulf-wendel.de/2012/peclmysqlnd_qc-query-cache-statistics-log/#comments</comments>
		<pubDate>Tue, 24 Jan 2012 17:20:51 +0000</pubDate>
		<dc:creator>Administrator</dc:creator>
		
	<category>PlanetMySQL (english)</category>
	<category>PlanetPHP (english)</category>
		<guid>http://blog.ulf-wendel.de/2012/peclmysqlnd_qc-query-cache-statistics-log/</guid>
		<description><![CDATA[	
 Is it worth the efforts to cache the results of a MySQL query at the client? In most cases the answer is: try it, measure it! Install the development version of the mysqlnd query cache plugin, which can be used with PDO_MySQL, mysqli and mysql.  Set three PHP directives and find the answer [...]]]></description>
			<content:encoded><![CDATA[	<p>
 Is it worth the efforts to cache the results of a MySQL query at the client? In most cases the answer is: try it, measure it! Install the development version of the <a href="http://de3.php.net/mysqlnd_qc">mysqlnd query cache plugin</a>, which can be used with <a href="http://de2.php.net/pdo_mysql">PDO_MySQL</a>, <a href="http://de3.php.net/mysqli">mysqli</a> and <a href="http://de3.php.net/manual/en/book.mysql.php">mysql</a>.  Set three PHP directives and find the answer in a log file.
</p>
	<p>
While updating the query cache plugin to support PHP 5.4, the latest versions of <a href="http://de2.php.net/apc">APC</a> and <a href="http://memcached.org/">Memcached </a>for cache storage, I virtually stumbled upon an undocumented feature I had long forgotten. The plugin can periodically dump statistics into a log file. The plugin collects tons of statistics and query traces to <a href="http://docs.php.net/manual/en/mysqlnd-qc.cache-candidates.php">find cache candidates</a> and for <a href="http://docs.php.net/manual/en/mysqlnd-qc.cache-efficiency.php">measuring cache efficiency</a>. Details can be found in the <a href="http://docs.php.net/manual/en/mysqlnd-qc.quickstart.php">quickstart</a>.
</p>
	<h3>Quick and dirty evaluation</h3>
	<p>
A quick and dirty evaluation of the maximum performance gain client-side query caching can give you is obtained by caching all statements. The first PHP directive to set is <code>mysqlnd_qc.cache_by_default = 1</code>.  Ignore the fact that the cache may serve stale data because its default invalidation strategy is Time-to-Live (TTL). Quick and dirty&#8230;
</p>
	<p><a id="more-347"></a></p>
	<p>
Enable the collection of per-process cache statistics with <code>mysqlnd_qc.collect_statistics</code>. Tell the plugin to dump statistics into the log file set through <code>mysqlnd_qc.collect_statistics_log_file</code>. The plugin will now dump per-process cache statistics into the log at every 10th web request.
</p>
	<p><pre>
<code>
info : pid=17092
info : cache_hit=9
info : cache_miss=5
info : cache_put=5
info : query_should_cache=14
info : query_should_not_cache=21
info : query_not_cached=21
info : query_could_cache=14
info : query_found_in_cache=9
info : query_uncached_other=0
info : query_uncached_no_table=0
info : query_uncached_no_result=0
info : query_uncached_use_result=0
info : query_aggr_run_time_cache_hit=232
info : query_aggr_run_time_cache_put=1785
info : query_aggr_run_time_total=2017
info : query_aggr_store_time_cache_hit=113
info : query_aggr_store_time_cache_put=214
info : query_aggr_store_time_total=327
info : receive_bytes_recorded=355
info : receive_bytes_replayed=639
info : send_bytes_recorded=205
info : send_bytes_replayed=369
info : slam_stale_refresh=0
info : slam_stale_hit=0
info : -----------------------------
info : pid=17099
info : cache_hit=12
info : cache_miss=6
info : cache_put=6
info : query_should_cache=18
info : query_should_not_cache=27
info : query_not_cached=27
info : query_could_cache=18
info : query_found_in_cache=12
info : query_uncached_other=0
info : query_uncached_no_table=0
info : query_uncached_no_result=0
info : query_uncached_use_result=0
info : query_aggr_run_time_cache_hit=185
info : query_aggr_run_time_cache_put=3017
info : query_aggr_run_time_total=3202
info : query_aggr_store_time_cache_hit=145
info : query_aggr_store_time_cache_put=405
info : query_aggr_store_time_total=550
info : receive_bytes_recorded=426
info : receive_bytes_replayed=852
info : send_bytes_recorded=246
info : send_bytes_replayed=492
info : slam_stale_refresh=0
info : slam_stale_hit=0
</code>
</pre>
	</p>
	<p>Restart your web server, if needed, to make it recognize the new ini settings. Put some load on it, make sure the PHP scripts run a couple of MySQL queries. Note that its per-process statistics and that they are dumped on every 10th web request  served by a process. In other words: you must have at least one process serve 10 requests before you can expect to find something in the log file.</p>
	<p>
The rest is simple math&#8230; pointers are given in the manual, for example, under <code><a href=" http://docs.php.net/manual/en/function.mysqlnd-qc-get-core-stats.php">mysqlnd_qc_get_core_stats()</a></code>. No math, Perl, sed, grep, whatever-other-post-processing for you? Check out the <code>web/</code> directory in the source distribution. There&#8217;s a basic web monitor.
</p>
	<p>
The ini setting <code>mysqlnd_qc.collect_statistics_log_file</code> for setting a log file name is new and only available in the development tree. The feature itself - dump of statistics into a file - is old. Earlier versions have a compiled in file name of <code>/tmp/mysqlnd.stats</code>.
</p>
	<p>Happy hacking!</p>
	<p  align="center">
<a href="http://twitter.com/#!/Ulf_Wendel">@Ulf_Wendel&nbsp;<img src="http://blog.ulf-wendel.de/images/twitter.png" align="middle" alt="Follow me on Twitter"/></a>
</p>
]]></content:encoded>
			<wfw:commentRSS>http://blog.ulf-wendel.de/2012/peclmysqlnd_qc-query-cache-statistics-log/feed/</wfw:commentRSS>
	</item>
		<item>
		<title>PHP mysqlnd query cache plugin quickstart is online!</title>
		<link>http://blog.ulf-wendel.de/2012/php-mysqlnd-query-cache-plugin-quickstart-is-online/</link>
		<comments>http://blog.ulf-wendel.de/2012/php-mysqlnd-query-cache-plugin-quickstart-is-online/#comments</comments>
		<pubDate>Fri, 13 Jan 2012 20:41:00 +0000</pubDate>
		<dc:creator>Administrator</dc:creator>
		
	<category>PlanetMySQL (english)</category>
	<category>PlanetPHP (english)</category>
		<guid>http://blog.ulf-wendel.de/2012/php-mysqlnd-query-cache-plugin-quickstart-is-online/</guid>
		<description><![CDATA[	
New in the PHP manual: a quickstart for the mysqlnd query cache plugin.  PECL/mysqlnd_qc, the mysqlnd query cache plugin, is transparent and ease to use. But, how? Some pointers have been given in assorted presentations, here on my blog and in some, few examples from the manual. Fixed. You can now browse a quickstart [...]]]></description>
			<content:encoded><![CDATA[	<p>
New in the PHP manual: a <a href="http://docs.php.net/manual/en/mysqlnd-qc.quickstart.php">quickstart for the mysqlnd query cache plugin</a>.  PECL/mysqlnd_qc, the mysqlnd query cache plugin, is transparent and ease to use. But, how? Some pointers have been given in assorted <a href="www.slideshare.net/nixnutz/">presentations</a>, here on my blog and in some, few examples from the manual. Fixed. You can now browse a quickstart to gain a quick overview.
</p>
	<ul>
	<li><a href="http://docs.php.net/manual/en/mysqlnd-qc.quickstart.concepts.php">Architecture and Concepts</li>
	<li><a href="http://docs.php.net/manual/en/mysqlnd-qc.quickstart.configuration.php">Setup</li>
	<li><a href="http://docs.php.net/manual/en/mysqlnd-qc.per-query-ttl.php">Setting the TTL</li>
	<li><a href="http://docs.php.net/manual/en/mysqlnd-qc.pattern_based_caching.php">Pattern based caching</li>
	<li><a href="http://docs.php.net/manual/en/mysqlnd-qc.slam-defense.php">Slam defense</li>
	<li><a href="http://docs.php.net/manual/en/mysqlnd-qc.cache_candidates.php">Finding cache candidates</li>
	<li><a href="http://docs.php.net/manual/en/mysqlnd-qc.cache_efficiency.php">Measuring cache efficiency</li>
	<li><a href="http://docs.php.net/manual/en/mysqlnd-qc.set-user-handlers.php">Beyond TTL: user-defined storage</li>
	</ul>
	<h3>Should I consider it?</h3>
	<p>
The <a href="http://pecl.php.net/package/mysqlnd_qc">PECL/mysqlnd_qc</a> manual is well worth 15 minutes of your attention if you either have a remote MySQL server or, you cannot use the query cache built-in to the MySQL server but want to use query caching.  If that&#8217;s not the case, you may still want to check its query traces to abuse them for performance monitoring. More on that below.
</p>
	<p>
Caching for the web always follows the same pattern. First, you move caches as close to the client as possible. Then, you select an appropriate granularity for cache contents on all layers for which you plan to use caching. The <a href="http://dev.mysql.com/doc/refman/5.6/en/query-cache.html">MySQL server query cache</a> is neat: it never serves stale data and, it comes with MySQL.  But, it is not as close to the client as possible. This adds latency and makes scale-by-client a bit more difficult.  Unfortunately, there is still no way to connect it to a client-side cache. Thus, PECL/mysqlnd_qc.
</p>
	<p align="center">
<img src="http://blog.ulf-wendel.de/images/mysqlnd_qc_snapshot.jpg" alt="Monitoring"  border="1" /><br />
<i>Simple monitor from the source distributions <code>web/</code> directory.</i>
</p>
	<p>
The mysqlnd query cache plugin with its various storage handlers (process memory, APC, Memcache, SQLite, user-defined) has a slide edge over an application centric solution:</p>
	<ul>
	<li>No or minimal application changes
	<ul>
	<li>no hassle when updating 3rd party solutions</li>
	<li>can be used even if code change is not possible but auto_prepend can be set</li>
	<li>compatible with all PHP MySQL APIs (mysqli, PDO_MySQL, mysql)</li>
	<li>plugs into to the driver: no extra PHP library/software to install</li>
	</ul>
	</li>
	<li>Flexible storage
	<ul>
	<li>process scope: process memory</li>
	<li>single machine scope: APC, Memcache, SQLite (memory)</li>
	<li>multiple machines scope: Memcache</li>
	</ul>
	</li>
	<li>Solid monitoring </li>
	</ul>
	<p>
Whether your cache solution shall have a granularity of individual SQL statements or, for example, should cache rendered HTML fragments is a different story&#8230; A nice aspect of PECL/mysqlnd_qc is that you can use it to evaluate the impact of database caching pretty quickly. Turn on caching of all statements, run a benchmark. Whatever database cache solution you end up with, results won&#8217;t be better than that. Based on the figures you can decide if its worth the efforts.
</p>
	<h3>The story about monitoring</h3>
	<p>
Even if the caching aspect is not for you, <code>mysqlnd_qc_get_query_trace_log()</code> may appeal to you.  To help finding cache candidates the plugin can be instructed to collect a query trace log. The trace contains a statements string, the statements run time, its store time and a backtrace to its origin in the source. Each and every query inspected by the plugin is listed.  Because PECL/mysqlnd_qc operated on the driver level, you see all queries from every PHP MySQL extension. The background is described in more detail <a href="Uh, uh… extending mysqlnd: monitoring and statement redirection">here</a>.
</p>
	<p>
<code></p>
	<pre>
mysqlnd_qc.enable_qc=1
mysqlnd_qc.collect_query_trace=1
</pre>
	<p></code><br />
<code></p>
	<pre>
/* connect to MySQL */
$mysqli = new mysqli(&quot;host&quot;, &quot;user&quot;, &quot;password&quot;, &quot;schema&quot;, &quot;port&quot;, &quot;socket&quot;);
	
/* dummy queries to fill the query trace */
for ($i = 0; $i < 2; $i++) {
  $res = $mysqli-&gt;query(&quot;SELECT 1 AS _one FROM DUAL&quot;);
  $res-&gt;free();
}
	
/* dump trace */
var_dump(mysqlnd_qc_get_query_trace_log());
</pre>
	<p></code><br />
<code></p>
	<pre>
array(2) {
  [0]=&gt;
  array(8) {
    [&quot;query&quot;]=&gt;
    string(26) &quot;SELECT 1 AS _one FROM DUAL&quot;
    [&quot;origin&quot;]=&gt;
    string(102) &quot;#0 qc.php(7): mysqli-&gt;query('SELECT 1 AS _on...')
#1 {main}&quot;
    [&quot;run_time&quot;]=&gt;
    int(0)
    [&quot;store_time&quot;]=&gt;
    int(25)
    [&quot;eligible_for_caching&quot;]=&gt;
    bool(false)
    [&quot;no_table&quot;]=&gt;
    bool(false)
    [&quot;was_added&quot;]=&gt;
    bool(false)
    [&quot;was_already_in_cache&quot;]=&gt;
    bool(false)
  }
  [1]=&gt;
  array(8) {
    [&quot;query&quot;]=&gt;
    string(26) &quot;SELECT 1 AS _one FROM DUAL&quot;
    [&quot;origin&quot;]=&gt;
    string(102) &quot;#0 qc.php(7): mysqli-&gt;query('SELECT 1 AS _on...')
#1 {main}&quot;
    [&quot;run_time&quot;]=&gt;
    int(0)
    [&quot;store_time&quot;]=&gt;
    int(8)
    [&quot;eligible_for_caching&quot;]=&gt;
    bool(false)
    [&quot;no_table&quot;]=&gt;
    bool(false)
    [&quot;was_added&quot;]=&gt;
    bool(false)
    [&quot;was_already_in_cache&quot;]=&gt;
    bool(false)
  }
}
</pre>
	<p></code>
</p>
	<p>Happy hacking!</p>
	<p>
<a href="http://twitter.com/#!/Ulf_Wendel">Follow me on Twitter - @Ulf_Wendel</a>
</p>
]]></content:encoded>
			<wfw:commentRSS>http://blog.ulf-wendel.de/2012/php-mysqlnd-query-cache-plugin-quickstart-is-online/feed/</wfw:commentRSS>
	</item>
		<item>
		<title>PHP mysqli quickstart is online!</title>
		<link>http://blog.ulf-wendel.de/2012/php-mysqli-quickstart-is-online/</link>
		<comments>http://blog.ulf-wendel.de/2012/php-mysqli-quickstart-is-online/#comments</comments>
		<pubDate>Thu, 12 Jan 2012 18:31:40 +0000</pubDate>
		<dc:creator>Administrator</dc:creator>
		
	<category>PlanetMySQL (english)</category>
	<category>PlanetPHP (english)</category>
		<guid>http://blog.ulf-wendel.de/2012/php-mysqli-quickstart-is-online/</guid>
		<description><![CDATA[	
New in the PHP manual: a mysqli quickstart.  You are new to PHP but you know how to code, you know SQL, you know relational databases and MySQL? Then, I hope, this is for you.  All you need is a quick overview on the concepts? The rest is in the reference section! Here [...]]]></description>
			<content:encoded><![CDATA[	<p>
New in the PHP manual: a <a href="http://docs.php.net/manual/en/mysqli.quickstart.php">mysqli quickstart</a>.  You are new to PHP but you know how to code, you know SQL, you know relational databases and MySQL? Then, I hope, this is for you.  All you need is a quick overview on the concepts? The rest is in the reference section! Here you go.
</p>
	<p>
The quickstart contains:</p>
	<ul>
	<li><a href="http://docs.php.net/manual/en/mysqli.quickstart.dual-interface.php">Dual procedural and object-oriented interface</a>:<br />
something pioneerd by MySQL when PHP learned OOP at 5.0 times.
</li>
	<li><a href="http://docs.php.net/manual/en/mysqli.quickstart.connections.php">Connections</a>: how, options, <del datetime="2012-01-11T19:40:22+00:00">persistent</del>/pooled connections.</li>
	<li><a href="http://docs.php.net/manual/en/mysqli.quickstart.statements.php">Executing statements</a>: buffered, unbuffered, impact of MySQL Client Server protocol flavour used</li>
	<li><a href="http://docs.php.net/manual/en/mysqli.quickstart.prepared-statements.php">Prepared Statements</a>: what, how, pros and cons</li>
	<li><a href="http://docs.php.net/manual/en/mysqli.quickstart.stored-procedures.php">Stored Procedures</a>: how, parameters, prepared statements</li>
	<li><a href="http://docs.php.net/manual/en/mysqli.quickstart.multiple-statement.php">Multiple Statements</a>: what, security considerations</li>
	<li><a href="http://docs.php.net/manual/en/mysqli.quickstart.transactions.php">API support for transactions</a></li>
	<li><a href="http://docs.php.net/manual/en/mysqli.quickstart.metadata.php">Metadata</a></li>
	</ul>
	<p>
In case you prefer listening over reading there is a <a href="http://dev.mysql.com/news-and-events/on-demand-webinars/display-od-668.html">PHP MySQL web seminar series</a>  on PHP for you (hint: search &quot;On Demand&quot; for more).  To please everybody, we are giving a webinar summary in german as well on 18.01.2012, <a href="http://www.mysql.com/news-and-events/web-seminars/display-680.html">register now</a>.
</p>
	<p>
Please, note that I am inpatient and linking to the PHP documentation teams server: <a href="http://docs.php.net/manual/en/mysqli.quickstart.php">http://docs.php.net/manual/en/mysqli.quickstart.php</a>. The php.net mirrors will need a while to catch up.
</p>
	<p>Happy hacking!</p>
	<p>
<a href="http://twitter.com/#!/Ulf_Wendel">@Ulf_Wendel</a>
</p>
]]></content:encoded>
			<wfw:commentRSS>http://blog.ulf-wendel.de/2012/php-mysqli-quickstart-is-online/feed/</wfw:commentRSS>
	</item>
		<item>
		<title>PECL/mysqlnd_*: CCC - cloud, cluster, caching!</title>
		<link>http://blog.ulf-wendel.de/2012/peclmysqlnd_-ccc-cloud-cluster-caching/</link>
		<comments>http://blog.ulf-wendel.de/2012/peclmysqlnd_-ccc-cloud-cluster-caching/#comments</comments>
		<pubDate>Wed, 11 Jan 2012 19:00:37 +0000</pubDate>
		<dc:creator>Administrator</dc:creator>
		
	<category>PlanetMySQL (english)</category>
	<category>PlanetPHP (english)</category>
		<guid>http://blog.ulf-wendel.de/2012/peclmysqlnd_-ccc-cloud-cluster-caching/</guid>
		<description><![CDATA[	
We are giving PECL/mysqlnd_qc a second chance. PECL/mysqlnd_qc is a query cache plugin for mysqlnd. It can cache any query issued by any PHP MySQL extension using storage handler for process memory, APC, Memcache and SQLlite. Its default invalidation strategy is Time to Live (TTL). Using a more sophisticated invalidation strategy is possible. Of course, [...]]]></description>
			<content:encoded><![CDATA[	<p>
We are giving <a href="http://pecl.php.net/package/mysqlnd_qc">PECL/mysqlnd_qc</a> a second chance. PECL/mysqlnd_qc is a query cache plugin for mysqlnd. It can cache any query issued by any PHP MySQL extension using storage handler for process memory, APC, Memcache and SQLlite. Its default invalidation strategy is Time to Live (TTL). Using a more sophisticated invalidation strategy is possible. Of course, its transparent to use and inherits all the other advantages of a driver based approach.
</p>
	<p><div style="width:425px" id="__ss_5425799"> <strong style="display:block;margin:12px 0 4px"><a href="http://www.slideshare.net/nixnutz/mysqlnd-plugin-oxid" title="Award-winning technology: Oxid loves the query cache" target="_blank">Award-winning technology: Oxid loves the query cache</a></strong> <iframe src="http://www.slideshare.net/slideshow/embed_code/5425799" width="425" height="355" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"></iframe><br />
<div style="padding:5px 0 12px"> View more <a href="http://www.slideshare.net/" target="_blank">presentations</a> on <a href="http://www.slideshare.net/nixnutz" target="_blank">PHP and MySQL</a> </div>
 </div>
	</p>
	<h3>Cloud and Cluster</h3>
	<p>
Albeit quite powerful the plugin came late and is faced with stiff competition from application-based solutions.  With everybody talking about cloud and database clusters, there is a new use case for client-side caching.
</p>
	<p>
No all-in-one cluster solution for all purposes exsits. MySQL users, for example, can choose between MySQL Replication, MySQL Cluster and an emerging number of third party solutions, which proof MySQL to be alive and rocking. The <a href="http://en.wikipedia.org/wiki/CAP_theorem">CAP theorem</a> makes me assume that MySQL users will continue to have multiple choices.
</p>
	<p>
Whatever cluster solution will become the dominating force, applications should be enabled to see a cluster as a service. Accordingly, PECL/mysqlnd_ms 1.2 has introduced an <a href="http://docs.php.net/manual/en/mysqlnd-ms.qos_consistency.php">API to set the required service level</a>.  In version 1.2 the service level option focusses on consistency:</p>
	<ul>
	<li>Eventual consistency - stale data allows, e.g. when reading from a MySQL replication slave</li>
	<li>Session consistency - read your writes</li>
	<li>Strong consistency - every client sees all writes</li>
	</ul>
	<p>
Whatever type of cluster is used, PECL/mysqlnd_ms will try to deliver the requested consistency by selecting appropriate nodes.
</p>
	<h3>Caching</h3>
	<p>
If the application hints the database driver that eventual consistency is sufficient but data returned shall not be more than five seconds behind, the database driver can replace a slow, eventually remote database access with a fast, local cache access. That&#8217;s the second chance PECL/mysqlnd_qc will be given.
</p>
	<table cellspacing="2" cellpadding="2">
	<tr>
	<td bgcolor="#f0f0f0" colspan="5" align="center" valign="top">PHP application</td>
	</tr>
	<tr>
	<td colspan="5" align="center" valign="top">Service level: eventual consistency, max 5 seconds old</td>
	</tr>
	<tr>
 </tr>
	<tr>
	<td bgcolor="#f0f0f0"  colspan="5" align="center" valign="top">Any PHP MySQL extension (mysqli, PDO_MySQL, mysql)</td>
	</tr>
	<tr>
	<td bgcolor="#f0f0f0"  colspan="5" align="center" valign="top">mysqlnd library</td>
	</tr>
	<tr>
	<td bgcolor="#f0f0f0"  align="center" valign="top">PECL/mysqlnd_ms</td>
	<td>&#8211;&gt;</td>
	<td bgcolor="#f0f0f0"  colspan="3" align="center" valign="top">PECL/mysqlnd_qc</td>
	</tr>
	<tr>
	<td align="center" valign="top">&nbsp;</td>
	<td>&nbsp;</td>
	<td align="center" valign="top">|</td>
	<td align="center" valign="top">or</td>
	<td align="center" valign="top">|</td>
	</tr>
	<tr>
	<td align="center" valign="top">&nbsp;</td>
	<td>&nbsp;</td>
	<td bgcolor="#f0f0f0"  align="center" valign="top">Process memory, Memcache, &#8230;</td>
	<td align="center" valign="top">&nbsp;</td>
	<td align="center" valign="top">|</td>
	</tr>
	<tr>
	<td align="center" valign="top">&nbsp;</td>
	<td>&nbsp;</td>
	<td align="center" valign="top">&nbsp;</td>
	<td align="center" valign="top">&nbsp;</td>
	<td bgcolor="#f0f0f0"  align="center" valign="top">MySQL</td>
	</tr>
	</table>
	<h3>Documentation updates</h3>
	<p>
Before we begin with it, I have given the PECL/mysqlnd_qc a second chance as well. You can expect to find an improved Quickstart and Examples section at <a href="http://docs.php.net/manual/en/book.mysqlnd-qc.php">http://docs.php.net/manual/en/book.mysqlnd-qc.php</a> soon.  Have a look during the next days, its a cool plugin thing even without the cloud buzzword bingo&#8230;
</p>
	<p>Happy New Year and happy hacking!</p>
	<p>
<a href="http://twitter.com/#!/Ulf_Wendel">@Ulf_Wendel</a>
</p>
	<div style="background:#f0f0f0">
	<h4>PHP 5.4 and APC notes</h4>
	<p>
PECL/mysqlnd_qc 1.0.1 is not compatible with PHP 5.4. It has not been updated to the latest mysqlnd API as found in PHP 5.4. <a href="http://www.hristov.com/andrey/">Andrey</a> and I have prepared a patch and hope to push a 1.0.2 release soon. Unfortunately, the (private) C API of APC has also changed in the past year. Thus, the cache cannot use a recent APC version for storing cache entries. Of course, you can still use the latest version of APC to boost your PHP scripts even if the scripts use the query cache plugin.
</p>
	</div>
]]></content:encoded>
			<wfw:commentRSS>http://blog.ulf-wendel.de/2012/peclmysqlnd_-ccc-cloud-cluster-caching/feed/</wfw:commentRSS>
	</item>
		<item>
		<title>PHP MySQL documentation updates</title>
		<link>http://blog.ulf-wendel.de/2011/php-mysql-documentation-updates/</link>
		<comments>http://blog.ulf-wendel.de/2011/php-mysql-documentation-updates/#comments</comments>
		<pubDate>Fri, 23 Dec 2011 12:36:09 +0000</pubDate>
		<dc:creator>Administrator</dc:creator>
		
	<category>PlanetMySQL (english)</category>
	<category>PlanetPHP (english)</category>
		<guid>http://blog.ulf-wendel.de/2011/php-mysql-documentation-updates/</guid>
		<description><![CDATA[	
The MySQL part of the PHP reference manual is currently being restructured: new landing and overview page, mysqli quickstart prepared. Ten years ago, there was the mysql extension and that was it. Today, beginners are faced with three MySQL APIs/extensions, two libraries and more than three library plugins. MySQL support by PHP has never been [...]]]></description>
			<content:encoded><![CDATA[	<p>
<strong>The MySQL part of the PHP reference manual is currently being restructured: new landing and overview page, mysqli quickstart prepared.</strong> Ten years ago, there was the mysql extension and that was it. Today, beginners are faced with <strong>three MySQL APIs/extensions, two libraries and more than three library plugins. MySQL support by PHP has never been better.</strong> But, where to start: web search for tutorials, a book? The results one gets tend to be flawed: outdated, incomplete, flawed&#8230;  Thus, the update.
</p>
	<h3>A landing and overview page</h3>
	<p>
The MySQL documentation staging server already shows the new <a href="http://docs.php.net/manual/en/set.mysqlinfo.php">landing and overview page &quot;MySQL Drivers and Plugins&quot;</a>. Its introduction makes the PHP reference manuals &quot;Vendor Specific Database Extensions&quot; section less cluttered by grouping all MySQL information under this new overview page.
</p>
	<p>
Under the address <a href="http://docs.php.net/manual/en/mysql.php">http://docs.php.net/manual/en/mysql.php</a> (later on php.net/mysql may work) users find an overview of the MySQL PHP drivers:</p>
	<ul>
	<li><a href="http://docs.php.net/manual/en/mysqlinfo.terminology.php">Terminology overview</a></li>
	<li><a href="http://docs.php.net/manual/en/mysqlinfo.api.choosing.php">Choosing an API</a></li>
	<li><a href="http://docs.php.net/manual/en/mysqlinfo.library.choosing.php">Choosing a library</a></li>
	</ul>
	<p>After an overview on terminology the three PHP MySQL APIs/extensions mysql, mysqli and PDO_MySQL are compared. A comprehensive feature matrix helps to get started. Next, it is explained how the extensions connect to MySQL by help of a client library. Again, a comprehensive feature matrix compares the two choices, the MySQL Client Library (AKA libmysql) and mysqlnd.
</p>
	<p>
The landing page continues with links to the mysql, mysqli APIs/extensions, followed by mysqlnd and its various plugins.
</p>
	<h3>Hands-on mysqli quickstart prepared</h3>
	<p>
Many years ago when <a href="http://zak.greant.com/">Zak Greant</a> and Georg Richter developed the mysqli extension they made sure to have examples for each and every function. That&#8217;s fantastic but meanwhile there is a logical and good trend to include hands-on quickstarts and background concepts information to PHP manual. We all know, a software is worth nothing without adequate easy to use documentation.The documentation must cover the needs of beginners, intermediate users and experts who need little more than reference materials. A bit like with the ~70 pages of <a href="http://php.net/mysqlnd_ms">PECL/mysqlnd_ms documentation</a>, which begins with a quickstart and a concepts section before the reference section.
</p>
	<p>
Therefore, I&#8217;ve written a mysqli quickstart. You have seen some excerpts of it already in my blog:</p>
	<ul>
	<li><a href="http://blog.ulf-wendel.de/2011/using-mysql-with-php-mysqli-connections-options-pooling/">Using MySQL with PHP mysqli: Connections, Options, Pooling</a></li>
	<li><a href="http://blog.ulf-wendel.de/2011/executing-mysql-queries-with-php-mysqli/">Executing MySQL queries with PHP mysqli</a></li>
	<li><a href="http://blog.ulf-wendel.de/2011/using-mysql-prepared-statements-with-php-mysqli/">Using MySQL prepared statements with PHP mysqli</a></li>
	<li><a href="http://blog.ulf-wendel.de/2011/using-mysql-multiple-statements-with-php-mysqli/">Using MySQL multiple statements with PHP mysqli</a></li>
	<li><a href="http://blog.ulf-wendel.de/2011/using-mysql-stored-procedures-with-php-mysqli/">Using MySQL stored procedures with PHP mysqli</a></li>
	</ul>
	<p>
I hope Philip will be able to review and add the quickstart to the mysqli extension documentation soon. That&#8217;s it? Come on, its not yet christmas eve and, do we really need chrismas for making presents&#8230;
</p>
	<p>
If you would like to comment on the new contents, please do so on the <a href="http://php.net/mailing-lists.php">php.net documentation mailing lists</a>. That&#8217;s the appropriate forum for discussions on the PHP reference manual. I&#8217;m sure there are still some edges in the new materials that need to be cut off.
</p>
	<p>
.oO( If <a href="http://hristov.com/andrey/">Andrey</a> and I continued our current pace, where would we be next christmas&#8230; )
</p>
	<p>
Happy hacking, happy holidays!
</p>
	<p>
<a href="http://twitter.com/#!/Ulf_Wendel">@Ulf_Wendel</a>
</p>
]]></content:encoded>
			<wfw:commentRSS>http://blog.ulf-wendel.de/2011/php-mysql-documentation-updates/feed/</wfw:commentRSS>
	</item>
		<item>
		<title>Load balancing for PHP and MySQL</title>
		<link>http://blog.ulf-wendel.de/2011/load-balancing-for-php-and-mysql/</link>
		<comments>http://blog.ulf-wendel.de/2011/load-balancing-for-php-and-mysql/#comments</comments>
		<pubDate>Fri, 23 Dec 2011 10:04:36 +0000</pubDate>
		<dc:creator>Administrator</dc:creator>
		
	<category>PlanetMySQL (english)</category>
	<category>PlanetPHP (english)</category>
		<guid>http://blog.ulf-wendel.de/2011/load-balancing-for-php-and-mysql/</guid>
		<description><![CDATA[	
A single MySQL server is a single point of failure. A single MySQL server can only be scaled vertically by increasing hardware size, which has its limits. That&#8217;s two good reasons to migrate from a single MySQL server to a cluster of MySQL servers. However, in cloudy white christmas times, few appreciate the extra work [...]]]></description>
			<content:encoded><![CDATA[	<p>
A single MySQL server is a single point of failure. A single MySQL server can only be scaled vertically by increasing hardware size, which has its limits. That&#8217;s two good reasons to migrate from a single MySQL server to a cluster of MySQL servers. However, in cloudy white christmas times, few appreciate the extra work that using a cluster causes. For example, MySQL connections must be load balanced.  <strong>Please, find a comparison of different load balancing architectures in the short <a href="http://www.slideshare.net/nixnutz/load-balancing-for-php-and-mysql">presentation</a></strong>. Choose the one that&#8217;s best for you - maybe it is <strong><a href="http://php.net/mysqlnd_ms">PECL mysqlnd_ms 1.2</a>, the mysqlnd replication and load balancing plugin&#8230;</strong>
</p>
	<p align="center">
	<div style="width:425px" id="__ss_10672887"> <strong style="display:block;margin:12px 0 4px"><a href="http://www.slideshare.net/nixnutz/load-balancing-for-php-and-mysql" title="Load Balancing for PHP and MySQL" target="_blank">Load Balancing for PHP and MySQL</a></strong> <iframe src="http://www.slideshare.net/slideshow/embed_code/10672887" width="425" height="355" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"></iframe><br />
<div style="padding:5px 0 12px"> View more <a href="http://www.slideshare.net/" target="_blank">presentations</a> on <a href="http://www.slideshare.net/nixnutz" target="_blank">mysqlnd</a> </div>
 </div></p>
	<p>Seasons greetings!</p>
	<p>
<a href="http://twitter.com/#!/Ulf_Wendel">@Ulf_Wendel</a>
</p>
]]></content:encoded>
			<wfw:commentRSS>http://blog.ulf-wendel.de/2011/load-balancing-for-php-and-mysql/feed/</wfw:commentRSS>
	</item>
		<item>
		<title>Welcome PECL/mysqlnd_ms 1.2.0-alpha with global transaction ID support</title>
		<link>http://blog.ulf-wendel.de/2011/welcome-peclmysqlnd_ms-120-alpha-with-global-transaction-id-support/</link>
		<comments>http://blog.ulf-wendel.de/2011/welcome-peclmysqlnd_ms-120-alpha-with-global-transaction-id-support/#comments</comments>
		<pubDate>Tue, 13 Dec 2011 23:45:46 +0000</pubDate>
		<dc:creator>Administrator</dc:creator>
		
	<category>PlanetMySQL (english)</category>
	<category>PlanetPHP (english)</category>
		<guid>http://blog.ulf-wendel.de/2011/welcome-peclmysqlnd_ms-120-alpha-with-global-transaction-id-support/</guid>
		<description><![CDATA[	
Christmas time, time for presents! Version 1.2.0-alpha of the free and open source PHP mysqlnd replication and load balancing plugin has been made available on PECL.  PECL/mysqlnd_ms  makes using any kind of MySQL database cluster easier featuring:
	
	Read-write splitting: automatic, SQL hints, can be disabled
	Load balancing: random, round robin, user defined
	Fail over
	Global transaction ID [...]]]></description>
			<content:encoded><![CDATA[	<p>
Christmas time, time for presents! Version 1.2.0-alpha of the free and open source PHP mysqlnd replication and load balancing plugin <a href="http://pecl.php.net/package/mysqlnd_ms/1.2.0">has been made available on PECL</a>.  <a href="http://de.php.net/mysqlnd_ms">PECL/mysqlnd_ms</a>  makes using any kind of MySQL database cluster easier featuring:</p>
	<ul>
	<li>Read-write splitting: automatic, SQL hints, can be disabled</li>
	<li>Load balancing: random, round robin, user defined</li>
	<li>Fail over</li>
	<li>Global transaction ID support: client-side emulation</li>
	<li>Service levels: eventual consistency, session consistency, strong consistency</li>
	</ul>
	<p>The last two features are new. The motto/theme of the 1.2 series is: Global Transaction ID injection and quality-of-service concept.
</p>
	<p>
For many years MySQL has adviced PHP developers to implement all kinds of logic needed to use MySQL Replication or MySQL Cluster in the application. PECL/mysqlnd_ms is changing this. Take any PHP MySQL application using any PHP MySQL extension (mysql, mysqli, PDO_MySQL), compile PHP to use the mysqlnd library, install the PECL module, drop it in and, be ready to migrate the application from a single database to a database cluster. At any time, it shall be possible to overrule all automatic decisions of the plugin, whenever needed.
</p>
	<h3>Service levels</h3>
	<p>
One of the biggest challenges when switching from a single database to  an asynchronous database cluster, such as a MySQL Replication cluster,  is the change in data consistency. A single server delivers strong consistency: all clients see each others changes. A MySQL replication cluster defaults to eventual consistency for a slave access: a client may or may not see its own changes, which is a significantly lower service level. However, in many cases its OK, why else would have an asynchronous approach have gained such popularity.
</p>
	<p>
Version 1.2.0-alpha of mysqlnd_ms introduces a quality of service filter. The application says what service level it needs from the cluster and the plugin delivers:</p>
	<ul>
	<li>Eventual consistency 
	<ul>
	<li>optional parameter: maximum age, don&#8217;t read from slaves that lag too far behind</li>
	</ul>
	<li>Session consistency (read your writes)
	<ul>
	<li>optional parameter: global transaction ID for reading from &quot;up-to-date&quot; slaves</li>
	</ul>
	</li>
	<li>Strong consistency</li>
	</ul>
	<p>A simple function call  - <code>mysqlnd_ms_set_qos()</code> - sets the service level.
 </p>
	<p>
Further readings:</p>
	<ul>
	<li>Blog posting <a href="http://blog.ulf-wendel.de/2011/peclmysqlnd_ms-quality-of-service-filter/">PECL/mysqlnd_ms: quality of service filter</a>
	<li>New <a href="http://docs.php.net/manual/en/mysqlnd-ms.qos_consistency.php">service level concepts section</a> in the PHP mysqlnd_ms manual (more coming)</li>
	</ul>
	<h3>Global Transaction ID support</h3>
	<p>
In its most basic form a global transaction ID can be described as a transaction counter maintained on the master. If the master fails, the most current slave for master promotion can easily be found by searching the slave with highest transaction ID.  The <a href="http://www.mysql.com/news-and-events/web-seminars/display-677.html">MySQL 5.6 Development Release</a> contains this feature, however, it is neither production ready nor fully functional yet.  And, so far, master fail over remains a manual task of the database administrator. Whenever the server solution is ready, mysqlnd_ms users are prepared to make the most out of it.
</p>
	<p>
Beginning with version 1.2.0-alpha, PECL/mysqlnd_ms can to a client-side emulation of the feature and transparently maintain a global transaction ID table on the master. Client-side emulation is a second best solution but one of the few options one has in heterogenous environments with servers that do not have the functionality built-in.
</p>
	<p>
A global transaction ID can also be used for improving session consistency (read your writes) load balancing for MySQL replication. Without a global transaction ID a client cannot say for sure in advance if a slave has already replicated a change. To read the own writes, the client must query the master. By help of a global transaction ID one can find if a certain write has been replicated already by a slave. Read your writes becomes possible on slaves. Read load is taken away from the master.
</p>
	<p>
Further reading:</p>
	<ul>
	<li>Blog posting <a href="http://blog.ulf-wendel.de/2011/peclmysqlnd_ms-global-transaction-id-injection-status/">PECL/mysqlnd_ms global transaction ID injection status</a></li>
	<li>New <a href="http://docs.php.net/manual/en/mysqlnd-ms.gtid.php">global transaction ID concepts section</a> in the PHP mysqlnd_ms manual (more coming)</li>
	</ul>
	<p align="center">
	<div style="width:425px" id="__ss_8966762"> <strong style="display:block;margin:12px 0 4px"><a href="http://www.slideshare.net/nixnutz/the-mysqlnd-replication-and-load-balancing-plugin" title="The mysqlnd replication and load balancing plugin" target="_blank">The mysqlnd replication and load balancing plugin</a></strong> <iframe src="http://www.slideshare.net/slideshow/embed_code/8966762" width="425" height="355" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"></iframe><br />
<div style="padding:5px 0 12px"> View more <a href="http://www.slideshare.net/" target="_blank">presentations</a> on <a href="http://www.slideshare.net/nixnutz" target="_blank">mysqlnd</a> </div>
 </div>
	</p>
	<p>
There is more to say about the release. Please, stay tuned. We started updating the manual. It will take a couple of days to complete the work and until the latest changes have made their way from the <a href="http://docs.php.net">PHP manual staging area</a> to the PHP manual mirrors. More blogs are coming as well.
</p>
	<p>
Happy hacking!
</p>
	<p>
<a href="http://twitter.com/#!/Ulf_Wendel">@Ulf_Wendel</a>
</p>
	<p>
PS: Pierre, it should build fine on Windows.
</p>
]]></content:encoded>
			<wfw:commentRSS>http://blog.ulf-wendel.de/2011/welcome-peclmysqlnd_ms-120-alpha-with-global-transaction-id-support/feed/</wfw:commentRSS>
	</item>
		<item>
		<title>PECL/mysqlnd_ms: quality of service filter</title>
		<link>http://blog.ulf-wendel.de/2011/peclmysqlnd_ms-quality-of-service-filter/</link>
		<comments>http://blog.ulf-wendel.de/2011/peclmysqlnd_ms-quality-of-service-filter/#comments</comments>
		<pubDate>Mon, 05 Dec 2011 10:52:17 +0000</pubDate>
		<dc:creator>Administrator</dc:creator>
		
	<category>PlanetMySQL (english)</category>
	<category>PlanetPHP (english)</category>
		<guid>http://blog.ulf-wendel.de/2011/peclmysqlnd_ms-quality-of-service-filter/</guid>
		<description><![CDATA[	
What if your PHP application could tell the mysqlnd library what service quality you need when using a MySQL replication cluster? If you wanted read-your-writes, the driver would select replication nodes for you which can offer it. If you can allow replication lag but no more than three seconds, the driver would select&#8230; One function [...]]]></description>
			<content:encoded><![CDATA[	<p>
What if your PHP application could tell the mysqlnd library what service quality you need when using a <a href="http://dev.mysql.com/doc/refman/5.5/en/replication.html">MySQL replication cluster</a>? If you wanted read-your-writes, the driver would select replication nodes for you which can offer it. If you can allow replication lag but no more than three seconds, the driver would select&#8230; One function call and you get the service you need. That&#8217;s what version 1.2 of <a href="http://de2.php.net/manual/en/book.mysqlnd-ms.php">PECL/mysqlnd_ms</a> is about.
</p>
	<h3>The quality of service filter</h3>
	<p>
In the world of PECL/mysqlnd_ms, the free and Open Source replication and load balancing plugin for mysqlnd, a so-called filter is responsible for choosing  nodes for statement execution. A filter looks at the SQL statement to be executed and picks a capable server.  The current production ready 1.1 release has three filters. Two load balancing filter (random, round-robin) and a user hook filter (user).
</p>
	<p>
For example, if you run a <code>SELECT</code> statement, the filters of PECL/mysqlnd_ms ensure it ends up on a slave.
</p>
	<table cellspacing="2" cellpadding="2" width="100%">
	<tr bgcolor="#f0f0f0">
	<th colspan="3"><code>query(SELECT id FROM test)</code></th>
	</tr>
	<tr>
	<td align="center" valign="top" colspan="3">|</td>
	</tr>
	<tr bgcolor="#000000">
	<td align="center"  valign="top" style="color:#ffffff">mysqli</td>
	<td align="center"  valign="top" style="color:#ffffff">PDO_MySQL</td>
	<td align="center"  valign="top" style="color:#ffffff">mysql</td>
	</tr>
	<tr bgcolor="#000000">
	<td colspan="3" align="center"  valign="top" style="color:#ffffff">mysqlnd library</td>
	</tr>
	<tr bgcolor="#000000">
	<th colspan="3" align="center"  valign="top" style="color:#ffffff">PECL/mysqlnd_ms magic</th>
	</tr>
	<tr>
	<td align="center" valign="top" colspan="3">|</td>
	</tr>
	<tr >
	<td>&nbsp;</td>
	<td bgcolor="#ffe0e0" align="center" valign="top">Master</td>
	<td>&nbsp;</td>
	</tr>
	<tr>
	<th align="center" valign="top" bgcolor="#e0ffe0">Slave 1</th>
	<td align="center" valign="top"  bgcolor="#ffe0e0">Slave 2</td>
	<td align="center" valign="top" bgcolor="#ffe0e0">Slave 3</td>
	</tr>
	</table>
	<p>
PECL/mysqlnd_ms 1.2 brings a new quality-of-service filter.  The quality of service filter can be configured in the plugins configuration file but also at runtime. The latter is new and unique to this filter.
</p>
	<h3>Reading from slaves no more than n seconds behind</h3>
	<p>
Certain elements on a web site qualify for simple TTL based caching. Others don&#8217;t. One could say, that the quality of service demands for cacheable contents are lower than for non-cacheable. The same goes for SQL statements.  Stale data may be OK, but it may not be older than n seconds, you may want to set a time-to-live, so to say.
</p>
	<p>
MySQL Replication is asynchronous. It takes some time until a write operation on the master has been replicated to all slaves. Slaves may not always serve current data. The MySQL administrative statement <code>SHOW SLAVE STATUS</code> give a hint how many seconds a slave is behind the master (<code><a href="http://dev.mysql.com/doc/refman/5.5/en/show-slave-status.html">Seconds_Behind_Master</a></code>).  It is a rather rough estimation that MySQL makes but its the best built-in logic I am aware of. Please, check the <a href="http://dev.mysql.com/doc/refman/5.5/en/show-slave-status.html">MySQL reference manual </a>for details.
</p>
	<table cellspacing="2" cellpadding="2" width="100%">
	<tr >
	<td>&nbsp;</td>
	<td bgcolor="#e0e0e0" align="center" valign="top">Master</td>
	<td>&nbsp;</td>
	</tr>
	<tr>
	<td align="center" valign="top" bgcolor="#e0e0e0">Slave 1</td>
	<td align="center" valign="top"  bgcolor="#e0e0e0">Slave 2</td>
	<td align="center" valign="top" bgcolor="#e0e0e0">Slave 3</td>
	</tr>
	<tr>
	<td align="center" valign="top"><code>Seconds_Behind_Master = 0</code></td>
	<td align="center" valign="top"><code>Seconds_Behind_Master = 3</code></td>
	<td align="center" valign="top"><code>Seconds_Behind_Master = 5</code></td>
	</tr>
	</table>
	<p>
Say your application is fine with reading from slaves that lag no more than three seconds behind the master.  With PECL/mysqlnd_ms 1.2 it will be one line to set the required service quality.
</p>
	<p><pre>
<code>
mysqlnd_ms_set_qos($link,
  MYSQLND_MS_QOS_CONSISTENCY_EVENTUAL,
  MYSQLND_MS_QOS_OPTION_AGE,
  3);
</code>
</pre>
	</p>
	<p>
After the function call, PECL/mysqlnd_ms checks for every statement nodes quality for executing the statement. If the statement is a write, the quality-of-service (qos) filter, returns a list of all masters. If the statement is a read, the qos filter returns all masters and all slaves for which <code>Seconds_Behind_Master &lt;= 3</code> is true. In the example, a <code>SELECT</code> statement would be run on the master, slave 1 or slave 2, depending on the choice of the load balancing filter.  Slave 3 is not used because its replication lag is too high.
</p>
	<p>
To be very clear here: the qos filter may execute <code>SHOW SLAVE STATUS</code> on all slaves.  This is an expensive and slow operation. But it is the only option availablewith todays MySQL replication server features. One may try to cache the <code>SHOW SLAVE STATUS</code> results but there&#8217;s no fundamental change until the MySQL replication cluster can tell clients which nodes to use.
</p>
	<p>
Don&#8217;t drop and forget the idea after this warning. The cool thing is, that if you tell PECL/mysqlnd_ms it may replace the slave access with a local TTL cache access&#8230;  allow disabling the slow status query, focus on the caching idea, and &#8230; But that&#8217;s for sure not for 1.2.
</p>
	<h3>Reading from slaves which have replicated a global transaction ID</h3>
	<p>
Setting the maximum age using the qos filter gives you <a href="http://blog.ulf-wendel.de/?p=333">eventual consistency</a>.  Using global transaction ids, the qos filter can also offer session consistency or read-your-wrtites. PECL/mysqlnd_ms 1.2 can do <a href="http://blog.ulf-wendel.de/?p=335">global transaction id injection</a> and the MySQL replication team has published a <a href="http://d2-systems.blogspot.com/2011/10/global-transaction-identifiers-feature.html">global transaction id feature preview</a> release in October. Because the server preview is not fully functional, 1.2 focusses on its client-side emulation and injection.
</p>
	<table cellspacing="2" cellpadding="2" width="100%">
	<tr bgcolor="#f0f0f0">
	<th colspan="3"><code></p>
	<pre>
$link-&gt;query(&quot;INSERT INTO test(id) VALUES (123)&quot;);
$gtid = mysqlnd_ms_get_last_gtid($link);
</pre>
	<p></code></th>
	</tr>
	<tr>
	<td align="center" valign="top" colspan="3">|</td>
	</tr>
	<tr >
	<td>&nbsp;</td>
	<td bgcolor="#e0e0e0" align="center" valign="top">Master</td>
	<td>&nbsp;</td>
	</tr>
	<tr >
	<td>&nbsp;</td>
	<td  align="center" valign="top">GTID = 27263</td>
	<td>&nbsp;</td>
	</tr>
	<tr>
	<td align="center" valign="top" bgcolor="#e0e0e0">Slave 1</td>
	<td align="center" valign="top"  bgcolor="#e0e0e0">Slave 2</td>
	<td align="center" valign="top" bgcolor="#e0e0e0">Slave 3</td>
	</tr>
	<tr>
	<td align="center" valign="top">GTID = 27263</td>
	<td align="center" valign="top" >GTID = 27251</td>
	<td align="center" valign="top" >GTID = 27263</td>
	</tr>
	</table>
	<p>
Whoever does maintain the global transaction ids, some SQL exists to check if a node has replicated a certain id or not. The qos filter knows the SQL and checks if a node has replicated the transaction in question. If so, the node can be used to achieve read-your-writes.
</p>
	<table cellspacing="2" cellpadding="2" width="100%">
	<tr bgcolor="#f0f0f0">
	<th colspan="3"><code></p>
	<pre>
mysqlnd_ms_set_qos(
  $link,
  MYSQLND_MS_QOS_CONSISTENCY_SESSION,
  MYSQLND_MS_QOS_OPTION_GTID,
  27263);
$link-&gt;query(&quot;SELECT * FROM test &quot;);
</pre>
	<p></code></th>
	</tr>
	<tr>
	<td align="center" valign="top" colspan="3">|</td>
	</tr>
	<tr >
	<td>&nbsp;</td>
	<td bgcolor="#e0ffe0" align="center" valign="top">Master</td>
	<td>&nbsp;</td>
	</tr>
	<tr >
	<td>&nbsp;</td>
	<td  align="center" valign="top">GTID = 27263</td>
	<td>&nbsp;</td>
	</tr>
	<tr>
	<td align="center" valign="top" bgcolor="#e0ffe0">Slave 1</td>
	<td align="center" valign="top"  bgcolor="#ffe0e0">Slave 2</td>
	<td align="center" valign="top" bgcolor="#e0ffe0">Slave 3</td>
	</tr>
	<tr>
	<td align="center" valign="top">GTID = 27263</td>
	<td align="center" valign="top" >GTID = 27251</td>
	<td align="center" valign="top" >GTID = 27263</td>
	</tr>
	</table>
	<h3>Is it worth it?</h3>
	<p>
The price of the qos filter is high. Checking nodes for every statement is slow. However, if you hit scalability limits of your master because of too many read-your-write requests, there is no choice . PECL/mysqlnd_ms, a driver-based solution, does not do worse than an application-based solution.  But, it takes work from you, the application developer.
</p>
	<p>
If that&#8217;s not convincing, OK, but what about the caching idea&#8230;
</p>
	<p>
Happy hacking!
</p>
	<p>
<a href="http://twitter.com/#!/Ulf_Wendel">@Ulf_Wendel</a>
</p>
	<p>
PS: Do you speak portuguese? If so, you may want to check out this <a href="http://www.phpconf.com.br/">PHP Conference Brasil</a> presentation from Airton Lastori.
</p>
	<p align="center">
	<div style="width:425px" id="__ss_10440137"> <strong style="display:block;margin:12px 0 4px"><a href="http://www.slideshare.net/MySQLBR/replicao-mysql-e-php" title="Replicação MySQL e PHP" target="_blank">Replicação MySQL e PHP</a></strong> <iframe src="http://www.slideshare.net/slideshow/embed_code/10440137" width="425" height="355" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"></iframe><br />
<div style="padding:5px 0 12px"> View more <a href="http://www.slideshare.net/" target="_blank">presentations</a> from <a href="http://www.slideshare.net/MySQLBR" target="_blank">MySQL Brasil</a> </div>
 </div>
	</p>
]]></content:encoded>
			<wfw:commentRSS>http://blog.ulf-wendel.de/2011/peclmysqlnd_ms-quality-of-service-filter/feed/</wfw:commentRSS>
	</item>
		<item>
		<title>Waiting for table metadata lock and PECL/mysqlnd_ms</title>
		<link>http://blog.ulf-wendel.de/2011/waiting-for-table-metadata-lock-and-peclmysqlnd_ms/</link>
		<comments>http://blog.ulf-wendel.de/2011/waiting-for-table-metadata-lock-and-peclmysqlnd_ms/#comments</comments>
		<pubDate>Tue, 29 Nov 2011 20:00:58 +0000</pubDate>
		<dc:creator>Administrator</dc:creator>
		
	<category>PlanetMySQL (english)</category>
	<category>PlanetPHP (english)</category>
		<guid>http://blog.ulf-wendel.de/2011/waiting-for-table-metadata-lock-and-peclmysqlnd_ms/</guid>
		<description><![CDATA[	
The MySQL administration SQL command SHOW PROCESSLIST  may read &#34;Waiting for table metadata lock&#34; in its &#34;State&#34; column for a statement. The statement in question is waiting for another transaction to release a metadata lock. Its a state that may appear when using the global transaction ID injection feature of PECL/mysqlnd_ms 1.2.0-alpha. But only [...]]]></description>
			<content:encoded><![CDATA[	<p>
The MySQL administration SQL command <code>SHOW PROCESSLIST</code>  may read &quot;Waiting for table metadata lock&quot; in its &quot;State&quot; column for a statement. The statement in question is waiting for another transaction to release a metadata lock. Its a state that may appear when using the global transaction ID injection feature of PECL/mysqlnd_ms 1.2.0-alpha. But only in case of errors and if not using default settings of the plugin. In the worst case, during testing only, I experienced a deadlock with MySQL 5.5.3 or higher which never got resolved automatically.
</p>
	<h3>Provoking metadata lock</h3>
	<p>
Let a transaction update a record in a table. In my specific case it was an failing <code>UPDATE</code>. It failed because the table did not exist. Let a second transaction run a DDL statement, for example, <code>DROP TABLE</code> on the same table.  The second transaction is now in waiting for the first transaction to release a metadata lock. Yes, the second transaction is waiting for a lock hold on a non-existing table, if you are using MySQL 5.5.3 or higher&#8230; The SQL is syntactically correct, thus the lock is acquired.<br />
</p<br />
<code>
	<pre>
$link = new mysqli($host, $user, $passwd, $db, $port, $socket);
$link->autocommit(false);
$link->query(\"UPDATE foo SET bar = bar + 1\");
	
$link2 = new mysqli($host, $user, $passwd, $db, $port, $socket);
$link2->query(\"DROP TABLE IF EXISTS foo\");
</pre>
	<p></code>
</p>
	<p>
<code></p>
	<pre>
mysql&gt; show processlist;
+------+------+--------------------+------+---------+------+---------------------------------+--------------------------+
| Id   | User | Host               | db   | Command | Time | State                           | Info                     |
+------+------+--------------------+------+---------+------+---------------------------------+--------------------------+
| 5754 | root | 192.168.78.1:44307 | test | Sleep   |  160 |                                 | NULL                     |
| 5755 | root | 192.168.78.1:44308 | test | Query   |  160 | Waiting for table metadata lock | DROP TABLE IF EXISTS foo |
| 5756 | root | localhost:60751    | test | Query   |    0 | NULL                            | show processlist         |
+------+------+--------------------+------+---------+------+---------------------------------+--------------------------+
</pre>
	<p></code>
</p>
	<p>
This behaviour is different from previous MySQL versions and it is documented in the <a href="http://dev.mysql.com/doc/refman/5.5/en/news-5-5-3.html">MySQL 5.5.3 Changes as an incompatible change</a>: <cite>A table that is being used by a transaction within one session cannot be used in DDL statements by other sessions until the transaction ends. </cite>. The change fixed issues with the binary log. So far, so good - though surprising.
</p>
	<p>
Under normal circumstances the server will release the lock when the clients commit their transactions or disconnect. If they don&#8217;t end their transactions nicely but die, the wait_timeout should detect failing TCP/IP clients and solve the deadlock.
</p>
	<h3>How its related to the plugin</h3>
	<p>
What I was doing here was simlating a failure of the plugin to inject a global transaction ID because the transaction table was not set up. The injection, the <code>UPDATE</code> fails, when the client is not in autocommit mode. My initial idea was that the plugin would then report and error to the application and the application could create the transaction id table, if it wanted. In my test I tried catching the error and did  <code>DROP TABLE IF EXISTS trx_table</code>, <code>CREATE TABLE trx_table</code> to recreate the table. My test timed out. And, that day it was time for me to call it a day.
</p>
	<p>
The other day, I checked the processlist and saw the deadlock. My PHP test had stopped and disconnected but the deadlock still existed and borked numerous other test runs. It was necessary to <code>KILL</code> the sleeping lock holder manually.
</p>
	<h3>Error handling in the plugin</h3>
	<p>
The plugin offers two ways of dealing with injection errors. By default the injection error is ignored and the function called by the application is executed nonetheless. If, for example, we are running in transaction mode (auto commit off), the user calls the commit() function and injection of the <code>UPDATE</code> statement for increasing the transaction counter fails, the plugin commits anyway. The transaction ends.  Other transactions should not be blocked because the metadata lock on the transaction table is released by ending the transaction. No matter if using MySQL 5.5.3 or earlier.
</p>
	<p>
<code></p>
	<pre>
user_commit()
   if (!inject_trx_id() &#038;&#038; report_error)
       return false;
	
  return commit()
</pre>
	<p></code>
</p>
	<p>
Optionally, users can tell the plugin to bubble up the injection error. If so, users should roll back the current transaction calling rollback() to prevent the metadata lock issue. Alternatively, you can check for the error code and try to detect cases when its required to recreate the transaction id table.
</p>
	<h3>Moral</h3>
	<p>
As said, if you go for plugin default settings, no locking issue but possibly gaps and holes in your transaction id table. If you know what you do, if you can adapt your application and code changes are possible, you can manually handle the error and recreate the transaction id table on demand.
</p>
]]></content:encoded>
			<wfw:commentRSS>http://blog.ulf-wendel.de/2011/waiting-for-table-metadata-lock-and-peclmysqlnd_ms/feed/</wfw:commentRSS>
	</item>
		<item>
		<title>PECL/mysqlnd_ms global transaction ID injection status</title>
		<link>http://blog.ulf-wendel.de/2011/peclmysqlnd_ms-global-transaction-id-injection-status/</link>
		<comments>http://blog.ulf-wendel.de/2011/peclmysqlnd_ms-global-transaction-id-injection-status/#comments</comments>
		<pubDate>Tue, 29 Nov 2011 06:25:50 +0000</pubDate>
		<dc:creator>Administrator</dc:creator>
		
	<category>MySQL</category>
	<category>PHP (english)</category>
		<guid>http://blog.ulf-wendel.de/2011/peclmysqlnd_ms-global-transaction-id-injection-status/</guid>
		<description><![CDATA[	
Baby PECL/mysqlnd_ms 1.2.0-alpha, the PHP MySQL replication and load balancing plugin for mysqlnd, has done its first steps into the direction of global transaction id injection: injection happens, IDs can be queried. A simulated global transaction ids can be described as a transaction counter in a table on a MySQL replication master. Slaves connected to [...]]]></description>
			<content:encoded><![CDATA[	<p>
Baby <a href="http://php.net/mysqlnd_ms">PECL/mysqlnd_ms 1.2.0-alpha</a>, the PHP MySQL replication and load balancing plugin for mysqlnd, has done its first steps into the direction of global transaction id injection: injection happens, IDs can be queried. A simulated global transaction ids can be described as a transaction counter in a table on a MySQL replication master. Slaves connected to the master replicate the transaction table. If the master fails, its easy to find the most current slave to promote it as the new master. Also, if an application wants to read its writes it can loop over the slaves to check which one has replicated the transaction id of the wrtite in question and read from those &#8220;synchronous&#8221; slaves. The dream here is: you tell the database cluster what service you need and it delivers (more dreaming).
</p>
	<h3>
An early status report<br />
</h3>
	<p>
Client-side global transaction ID injection is always a second best solution. Any client-side solution can create gaps and holes. The mysqlnd plugin based solution is for you, if you have only PHP clients accessing your MySQL replication cluster. If there is a single other client, go for a MySQL Proxy based solution or, stay tuned…
</p>
	<p>
Today, the mysqlnd plugin can increment the transaction counter for prepared statement, non-prepared statement in autocommit mode and in transaction mode - short: any statement. Transaction boundaries are detected based on API calls. The plugin does not monitor SQL statements to detect SQL like &#8220;COMMIT&#8221;. API monitoring is possible since PHP 5.4. Please find a detailed description of the limits in the manual.
</p>
	<p><code></p>
	<pre>
&quot;myapp&quot;:{
  &quot;master&quot;:{
    &quot;master1&quot;:{
      &quot;host&quot;:&quot;127.0.0.1&quot;,
      &quot;port&quot;:3306
    }
  },
  &quot;slave&quot;:{
    &quot;slave1&quot;:{
      &quot;host&quot;:&quot;192.168.78.137&quot;,
      &quot;port&quot;:3307
    }
  },
  &quot;global_transaction_id_injection&quot;:{
    &quot;on_commit&quot;:&quot;UPDATE test.trx SET trx_id = trx_id + 1&quot;,
    &quot;fetch_last_gtid&quot;:&quot;SELECT MAX(trx_id) FROM test.trx&quot;,
    &quot;check_for_gtid&quot;:&quot;SELECT trx_id FROM test.trx WHERE trx_id &gt;= #GTID&quot;
  }
 }
}
</pre>
	<p></code></p>
	<p>
The plugin increments the global transaction id:</p>
	<ul>
	<li>… in auto commit mode and…</li>
	<li> … when switching from transaction mode to auto commit mode without explicitly calling commit()
	<ul>
	<li>before executing a non-prepared statement, in query()</li>
	<li>before executing a prepared statement, in execute() </li>
	</ul>
	</li>
	<li> … in transaction mode (auto commit off)
	<ul>
	<li>before the commit() call</li>
	</ul>
	</li>
	</ul>
	<h3>Injection basics</h3>
	<p>
The plugin looks up the &#8220;on_commit&#8221; entry from the global transaction id section of the plugins configuration file. Then, the plugin executes the statement Users can choose between two different kinds of error handling. By default, any error executing the SQL from &#8220;on_commit&#8221; is ignored. This is done to allow using the plugin as a drop-in solution. A drop-in solution must not change the original behaviour, it must be transparent. Optionally, this is recommended with new applications, the error can be forwarded to the user &#8220;as is&#8221;. More on that in a future post.
</p>
	<p>
Database administrators must take care that all masters have a ready-to-use global transaction id counter table. For development we use this very inefficient table. More on better approaches in a future post: Giuseppe, the Data Charmer, has given fascinating tipps earlier this year.<br />
<code></p>
	<pre>
CREATE TABLE `trx` (
  `trx_id` int(11) DEFAULT NULL,
  `last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=latin1
</pre>
	<p></code>
</p>
	<h3>Accessing the transaction ID</h3>
	<p>
The last global transaction ID can be obtained with the new mysqlnd_ms_get_last_gtid() function. The function looks up &#8220;fetch_last_gtid&#8221; in the plugin configuration and executes the SQL. With many concurrent users you may not get exactly the transaction id of your statement but something reasonable close, something that is likely a bit higher. The function returns a string, in the hope that it gives you some freedom writing fancy SQL for the task.<br />
<code></p>
	<pre>
/* works with mysqli, PDO_MYSQL and mysql */
$link = new mysqli(&quot;myapp&quot;, &quot;root&quot;, &quot;&quot;, &quot;test&quot;);
$link-&gt;query(&quot;DROP TABLE IF EXISTS test&quot;);
printf(&quot;GTID '%s'\n&quot;, $ret = mysqlnd_ms_get_last_gtid($link));
</pre>
	<p></code>
</p>
	<h3>Read your writes</h3>
	<p>
PECL/mysqlnd_ms 1.1, the current production version, lets you read your writes when setting the configuration option &#8220;master_on_write&#8221;. As the name says, all statements will be run on the master. With 1.2.0-alpha and global transaction IDs the plugin can identify slaves ready for reading the just written. This gives you better read load balancing.<br />
<code></p>
	<pre>
/* say what you expect from the cluster... and it delivers! */
mysqlnd_ms_set_qos($link, MYSQLND_MS_QOS_CONSISTENCY_SESSION, MYSQLND_MS_QOS_OPTION_GTID, $gtid);
</pre>
	<p></code>
</p>
	<p>
Tell the plugin what quality-of-service (qos) you need. Set the consistency requirement to session and give the plugin a hint how to find nodes that can deliver session consistency. Use the new function mysqlnd_ms_set_qos() for it. In our initial implementation we loop over the slave list and search for all slaves that have replicated the transaction id. If no slave has caught up, the plugin tells the load balancer to use the configured master (servers) only.
</p>
	<p>
This looks sooo complicated compared to 1.1? Yes. BUT, what if you knew that your query may serve stale result no older than three seconds and you wanted to read from a node which is no more than 3 seconds behind the master? There’s one-liner in version 1.2 for the task:<br />
<code></p>
	<pre>
/* say what you expect from the cluster... and it delivers! */
mysqlnd_ms_set_qos($link, MYSQLND_MS_QOS_CONSISTENCY_SESSION, MYSQLND_MS_QOS_OPTION_AGE, 3);
</pre>
	<p></code>
</p>
	<h3>For early adopters</h3>
	<p>
There are edges in the implementation that need to be cut off. All over. Many edges. Injection seems to work reasonable well. The new read-your-writes (mysqlnd_ms_set_qos()) works as well. However, our initial implementation is neither very efficient nor do we have good error handling for all cases yes: alpha quality.
</p>
	<p>
Given that, should you look at it? If you like the plugin idea, please do. Please, comment on the API as early as possible.
</p>
	<p>Happy hacking!</p>
	<p>
<a href="http://twitter.com/#!/Ulf_Wendel">@Ulf_Wendel</a>
</p>
]]></content:encoded>
			<wfw:commentRSS>http://blog.ulf-wendel.de/2011/peclmysqlnd_ms-global-transaction-id-injection-status/feed/</wfw:commentRSS>
	</item>
		<item>
		<title>Global transaction ID support for PECL/mysqlnd_ms</title>
		<link>http://blog.ulf-wendel.de/2011/global-transaction-id-support-for-peclmysqlnd_ms/</link>
		<comments>http://blog.ulf-wendel.de/2011/global-transaction-id-support-for-peclmysqlnd_ms/#comments</comments>
		<pubDate>Wed, 16 Nov 2011 20:58:05 +0000</pubDate>
		<dc:creator>Administrator</dc:creator>
		
	<category>PlanetMySQL (english)</category>
	<category>PlanetPHP (english)</category>
		<guid>http://blog.ulf-wendel.de/2011/global-transaction-id-support-for-peclmysqlnd_ms/</guid>
		<description><![CDATA[	
The catchy theme/motto of the PECL/mysqlnd_ms 1.2 release will be Global Transaction ID support.  Hidden behind the buzzword are two features. We will allow users to request a certain level of service from the replication cluster (keyword: consistency) and we will do basic global transaction ID injection to help with master failover. Failover refers [...]]]></description>
			<content:encoded><![CDATA[	<p>
The catchy theme/motto of the PECL/mysqlnd_ms 1.2 release will be Global Transaction ID support.  Hidden behind the buzzword are two features.<strong> We will allow users to request a certain level of service from the replication cluster (keyword: consistency) and we will do basic global transaction ID injection to help with master failover. </strong>Failover refers to the procedure of electing a new master in case of a master failure.
</p>
	<h3>Global Transaction ID support is the 1.2 motto/theme</h3>
	<p>
The two features are somewhat related, thus the theme.  In very basic words, the idea of a global transaction ID is to have a sequential number in a table on the master. Whenever a client inserts data, the ID/counter gets incremented. The table is replicated to the slaves. If the master fails, the database administrator checks the slaves to find the one with the hightest global transaction ID.  Please find details, for example, in <a href="http://blog.ulf-wendel.de/2011/wonders-of-global-transaction-id-injection/">Wonders of Global Transaction ID injection</a>.<br />
What the plugin will do is inject a user-provided SQL statement with every transaction to increment the global transaction counter.
</p>
	<p>
However, there is also a client-side benefit to global transactions IDs. If you want to read-your-writes from a replication cluster, you usually query the master. You won&#8217;t go to the slaves, because you do not know if they have replicated your writes already. In case you need read-your-writes, set the <code><a href="http://de3.php.net/manual/en/mysqlnd-ms.plugin-ini-json.php">master_on_write</a></code> config setting in version 1.1. In version 1.2 we can offer more, if you want and need it. We can search for a slave who has replicated the global transaction ID of your write to reduce the read-your-write load on the master. The keyword here is consistency and the background posting is <a href="http://blog.ulf-wendel.de/2011/consistency-cloud-and-the-php-mysqlnd-replication-plugin/">Consistency, cloud and the PHP mysqlnd replication plugin</a>. However, consistency is not nearly as nice as a motto as the catchy global transaction ID theme.
</p>
	<p>
Of course, the day the MySQL Server has built-in Global Transaction IDs, we don&#8217;t need to do the injection any more. Meanwhile, we give it a try&#8230; a report from the hacks of the past two days. Feedback is most welcome.
</p>
	<p>
Warning: this now becomes a posting for hackers, not users. If you are not after implementation details, stop reading. The big news is the theme, nothing else. If you don&#8217;t trust any software you have not developed yourself but you like the idea of a replication and load balancing plugin, continue reading.
</p>
	<p><a id="more-334"></a></p>
	<h3>First try: injection</h3>
	<p>
&#8230; our first attempt on global transaction ID injection is straigt forward. By default, injection is done only for queries that go to the master. By default, all PHP MySQL APIs use auto commit. In the most basic case we just inject SQL before the query from the user.  Doing it first avoids hassle, if the users statement returns a result set. Injecting before the users statement also means, we increment regardless of the success of the users statement.<br />
<code></p>
	<pre>
$mysqli-&gt;query(&quot;SELECT 1&quot;);
$mysqli-&gt;query(&quot;INSERT INTO test(id) VALUES (1)&quot;);
</pre>
	<p></code><br />
<code></p>
	<pre>
SELECT -&gt;
  slave -&gt;
    auto commit on -&gt;
      query(SELECT)
	
INSERT -&gt;
   master -&gt;
     auto commit on -&gt;
        query(INJECTED), query(INSERT);
</pre>
	<p></code><br />
Optionally, we allow doing the injection on slaves as well. It can be configured if errors caused by injected SQL are ignored or reported, e.g. if the global transaction ID sequence table is unavailable.
</p>
	<p>
If not in auto commit mode, we do the injection when the user invokes the user APIs <code>commit()</code> function. This is possible as of PHP 5.4. We do not monitor all statements to catch <code>query(COMMIT)</code> calls. Same constraints as for 1.1&#8217;s  <a href="http://de3.php.net/manual/en/mysqlnd-ms.plugin-ini-json.php"><code>trx_stickiness</code></a> config setting.
</p>
	<p>
Andrey, the king of mysqlnd,  proposed to consider <code>query(INSERT), ..., query(INJECTED)</code>.  In this case we would not increment the global transaction ID, if the users <code>INSERT</code> fails. However, its something for the king himself to evaluate. In other words: its beyond my skill level to do within hours. I&#8217;m somewhat sceptical its worth the efforts.
</p>
	<p>
We also started looking into using multi statements. In this case, we prepend the users statement with the SQL to maintain the global transaction ID and run the resulting statement as a multi statement. Shown is a prefixing example. Its implemented as a hack for buffered non-prepared statements. We need to benchmark, if its worth the complicated logic over the initial approach.<br />
<code></p>
	<pre>
$mysqli-&gt;query(&quot;INSERT INTO test(id) VALUES (1)&quot;);
</pre>
	<p></code><br />
<code></p>
	<pre>
INSERT -&gt;
  master -&gt;
    set_server_option(MULTI_STATEMENT_ON) -&gt;
       query(INJECTED;  INSERT) -&gt;
         more_results -&gt;
           next_results -&gt;
             store_results -&gt;
               set_server_option(MULTI_STATEMENT_OFF)
</pre>
	<p></code>
</p>
	<h3>First try: service level</h3>
	<p>
In the area of &quot;consistency&quot; and service level, our first approach looks promising. The time Andrey invested into the 1.1 release to implement the <a href="http://de3.php.net/manual/en/mysqlnd-ms.filter.php">filter logic</a> starts to pay off.
</p>
	<p>
In short, filter mean that we have a sequence of independent tools to find a node for running a statement. A bit like Unix command line tools that are connected on the command line with a pipe.<br />
<code></p>
	<pre>
query(SELECT) -&gt;
  all masters, all slaves -&gt;
    filter(LOADBALANCING)  -&gt;
      certain slave
</pre>
	<p></code>
</p>
	<p>
We now have a new quality-of-service or &quot;consistency&quot; (qos) filter. For background information on the idea, see <a href="http://blog.ulf-wendel.de/2011/consistency-cloud-and-the-php-mysqlnd-replication-plugin/">Consistency, cloud and the PHP mysqlnd replication plugin</a>.
</p>
	<p>
If, for example, the quality-of-service (consistency level) you need from the cluster is read-your-writes, you can set it in the plugin configuration file and create a filter chain like this:<br />
<code></p>
	<pre>
query(SELECT) -&gt;
  all masters, all slaves -&gt;
    filter(QOS, STRONG_CONSISTENCY) -&gt;
      all masters, no slaves -&gt;
        filter(LOADBALANCING)  -&gt;
          certain master
</pre>
	<p></code>
</p>
	<p>
This is not much of a win over the already existing <code>master_on_write</code> configuration setting. However, together with the new filter, we also introduced a new API call to change the filter chain at runtime. You don&#8217;t have to configure read-your-writes (<code>master_on_write</code>) when setting up the plugin, you can set at runtime - on demand.
</p>
	<p>
Let a filter chain like this be given:<br />
<code></p>
	<pre>
query(SELECT) -&gt;
  all masters, all slaves -&gt;
    all masters, all slaves -&gt;
      filter(LOADBALANCING)  -&gt;
        certain slave
</pre>
	<p></code><br />
Then, at run-time you place an order in your shop and you need to read-your-writes for a short period, you do:<br />
<code></p>
	<pre>
mysqlnd_ms_set_qos(MYSQLND_MS_STRONG_CONSISTENCY);
$mysqli-&gt;query(&quot;SELECT id FROM orders&quot;);
/* ... do more queries that must not return stale data ... */
</pre>
	<p></code><br />
This will change the filter chain accordingly on-the-fly.<br />
<code></p>
	<pre>
query(SELECT) -&gt;
  all masters, all slaves -&gt;
       filter(QOS, STRONG_CONSISTENCY) -&gt;
         all masters, no slaves -&gt;
           filter(LOADBALANCING)  -&gt;
             certain master
</pre>
	<p></code><br />
Once you are done with the consistent reads, you can go back with one API call to eventual consistency (use masters and slaves, which may or may not serve current data.
</p>
	<p>
That can save you a good number of SQL hints required in 1.1, if not using <code>master_on_write</code>.
</p>
	<h3>&#8230; and back to the beginning</h3>
	<p>
With the new filter and the new API call, we can also allow things like this:<br />
<code></p>
	<pre>
$mysqli-&gt;query(&quot;INSERT INTO orders(...)&quot;);
$global_trx_id = mysqlnd_ms_get_global_trx_id($mysqli);
mysqlnd_ms_set_qos(MYSQLND_MS_SESSION_CONSISTENCY, $global_trx_id);
$mysqli-&gt;query(&quot;SELECT id FROM orders&quot;);
/* ... do more queries that must not return stale data for table orders... */
</pre>
	<p></code><br />
In this case we can read from any master and any slave which has replicated a certain global transaction ID. This is where we get back to the beginning. And, we open up for the future.
</p>
	<p>
Imagine, with a distant release (not 1.2!), you could ask for data that is no older than 2 seconds. The plugin would either read from the master, or a slave lagging no more than 2 seconds, or fetch the result from a local TTL cache, such as PECL/mysqlnd_qc, with a TTL of 2 seconds&#8230;<br />
<code></p>
	<pre>
mysqlnd_ms_set_qos(MYSQLND_MS_EVENTUAL_CONSISTENCY, MAX_LAG, 2);
$mysqli-&gt;query(&quot;SELECT id FROM news&quot;);
</pre>
	<p></code>
</p>
	<p>
Happy hacking to all of us&#8230;
</p>
	<p>
<a href="http://twitter.com/#!/Ulf_Wendel">@Ulf_Wendel</a>
</p>
]]></content:encoded>
			<wfw:commentRSS>http://blog.ulf-wendel.de/2011/global-transaction-id-support-for-peclmysqlnd_ms/feed/</wfw:commentRSS>
	</item>
		<item>
		<title>Consistency, cloud and the PHP mysqlnd replication plugin</title>
		<link>http://blog.ulf-wendel.de/2011/consistency-cloud-and-the-php-mysqlnd-replication-plugin/</link>
		<comments>http://blog.ulf-wendel.de/2011/consistency-cloud-and-the-php-mysqlnd-replication-plugin/#comments</comments>
		<pubDate>Thu, 10 Nov 2011 18:49:26 +0000</pubDate>
		<dc:creator>Administrator</dc:creator>
		
	<category>PlanetMySQL (english)</category>
	<category>PlanetPHP (english)</category>
		<guid>http://blog.ulf-wendel.de/2011/consistency-cloud-and-the-php-mysqlnd-replication-plugin/</guid>
		<description><![CDATA[	
Elastic, fantastic: click here to add a MySQL replication database cluster to your cloud configuration.  Click - yes, we can! Just one little thing, you need to update your application: consistency model changed. Plan for it. Some thoughts for PECL/mysqlnd_ms 1.x, the PHP mysqlnd replication plugin.

	Problem: C as in ACID is no more
	
A MySQL [...]]]></description>
			<content:encoded><![CDATA[	<p>
Elastic, fantastic: click here to add a MySQL replication database cluster to your cloud configuration.  Click - yes, we can! Just one little thing, you need to update your application: consistency model changed. Plan for it. Some thoughts for <a href="http://de.php.net/mysqlnd_ms">PECL/mysqlnd_ms</a> 1.x, the PHP mysqlnd replication plugin.
</p>
	<h3>Problem: C as in ACID is no more</h3>
	<p>
A MySQL replication cluster is eventual consistent. All writes are to be send to the master.  A write request is considered successful once the master has performed it. </p>
	<table cellspacing="2" cellpadding="2" width="100%">
	<tr>
	<td align="center" valign="top"  bgcolor="#c0c0ff">
	<table cellspacing="2" cellpadding="2" width="100%">
	<tr bgcolor="#c0c0ff">
	<td colspan="3" align="center"  valign="top">MySQL replication cluster</td>
	</tr>
	<tr bgcolor="#c0c0ff">
	<th align="center" valign="top">Master</th>
	<td align="center" valign="top">Slave</td>
	<td align="center" valign="top">Slave</td>
	</tr>
	<tr bgcolor="#c0c0ff">
	<th align="center" valign="top">id = 1</th>
	<td align="center" valign="top">id = NULL</td>
	<td align="center" valign="top">id = 2</td>
	</tr>
	</table>
	</td>
	</tr>
	<tr>
	<td align="center" valign="top">|</td>
	</tr>
	<tr>
	<th align="center" valign="top">set(id = 1)</th>
	</tr>
	<tr>
	<th align="center" valign="top">Client 1</th>
	</tr>
	</table>
	<p><a id="more-333"></a></p>
	<p>
Then, the master sends the update to the slave. Slave updates are asynchronous. For a short period, until all slaves have replicated the update, there is read inconsistency. The inconsistency window even exists with <a href="http://dev.mysql.com/doc/refman/5.5/en/replication-semisync.html">semisynchronous replication</a>. Semisynchronous guarantees that the update information  is stored on at least one slave but there is no promise its already available at the SQL layer.</p>
	<table cellspacing="2" cellpadding="2" width="100%">
	<tr>
	<td align="center" valign="top"  bgcolor="#c0c0ff">
	<table cellspacing="2" cellpadding="2" width="100%">
	<tr bgcolor="#c0c0ff">
	<td colspan="3" align="center"  valign="top">MySQL replication cluster</td>
	</tr>
	<tr bgcolor="#c0c0ff">
	<td align="center" valign="top">Master</td>
	<th align="center" valign="top">Slave</th>
	<td align="center" valign="top">Slave</td>
	</tr>
	<tr bgcolor="#c0c0ff">
	<td align="center" valign="top">id = 1</td>
	<th align="center" valign="top">id = NULL</th>
	<td align="center" valign="top">id = 2</td>
	</tr>
	</table>
	</td>
	</tr>
	<tr>
	<td align="center" valign="top">|</td>
	</tr>
	<tr>
	<th align="center" valign="top">get(id)</th>
	</tr>
	<tr>
	<th align="center" valign="top">Client 2</th>
	</tr>
	</table>
	<p>
Regarding the C in ACID&#8230; Transactions still exist. But as you can see, the C is no more when you take a step back to look at the cluster as a whole. Thus, application developers must plan for inconsistency.
</p>
	<h3>Analysis: consistency levels</h3>
	<p>
Any of the three consistency levels listed can be achieved with MySQL replication. Although, I must confess, strong consistency means using the master for all requests. That&#8217;s not what elastic-fantastic is about&#8230;</p>
	<ol>
	<li>Eventual consistency<br />
    Node may not have data, node may service stale version, node may serve current version.  If no new updates happen, after the inconsistency windows has passed, all nodes will eventually return the same current data. Default with MySQL replication and PECL/mysqlnd_ms 1.1.
   </li>
	<li>Session consistency<br />
     Read-your-writes. One client is guaranteed to see its updates for the duration of a session. PECL/mysqlnd_ms 1.1 has <a href="http://de.php.net/manual/en/mysqlnd-ms.plugin-ini-json.php">master_on_write</a>, which is a tiny step into this direction.
   </li>
	<li>Strong consistency<br />
    All clients get a consistent view after a successful update.
</ol>
	</p>
	<h3>Mistake: this is left to the developer</h3>
	<p>
PECL/mysqlnd_ms 1.1 leaves it to the user to implement a choice, a certain service level. Developer have to use the <a href="http://de.php.net/manual/en/mysqlnd-ms.rwsplit.php">SQL hints </a><code>MYSQLND_MS_SLAVE_SWITCH</code>, <code>MYSQLND_MS_LAST_USED_SWITCH</code>, <code>MYSQLND_MS_MASTER_SWITCH</code> &#8230;
</p>
	<p>
Wrong, stop it, thinking from the past and for 1.<code>very_low</code> releases! As a cloud user, I do not want to have to bother about details of the MySQL cluster! As a cloud users, I want a ready-to-use service. <strong>As a cloud user, I want to define the service level I need and see the database cluster deliver - within its capabilities.</strong> &quot;Cloud&quot; is used as a synonym for our times here.
</p>
	<h3>Proposing service levels</h3>
	<p>
As a cloud user, I want to set the service level like this. I don&#8217;t care much how its implemented as long I don&#8217;t have to fine-tune the setup.
</p>
	<p>
<code></p>
	<pre>
$mysqli-&gt;query(&quot;SELECT product_id, title, price FROM products&quot;);
$mysqli-&gt;query(&quot;INSERT INTO shopping_cart(cart_id, product_id) VALUES (123, 456)&quot;);
mysqlnd_ms_set_service_level(MYSQLND_MS_SESSION_CONSISTENCY);
$mysqli-&gt;query(&quot;SELECT COUNT(*) FROM shopping_cart WHERE cart_id = 123&quot;);
</pre>
	<p></code>
</p>
	<p>
Let&#8217;s see what service contracts PECL/mysqlnd_ms could fulfill with todays MySQL replication cluster capabilities and how.
</p>
	<h3>Client-side consistency level variations</h3>
	<p>
Eventual consistency and session consistency could be parametized. </p>
	<ol>
	<li>Eventual consistency
	<ol>
	<li> default - no parameter<br />
      Service guaranteed: None. Data may be unavailable, stale or current</li>
	<li>max_age<br />
      Service guaranteed: No data served which is more than <code>max_age</code> seconds old.</li>
	</ol>
	</li>
	<li>Session consistency<br >
	<ol>
	<li>default - no parameter<br />
     Service guaranteed: read-your-writes for the duration of a web request.
     </li>
	<li>session id<br />
      Service guaranteed: read-your-writes in all sessions that share a session id.
     </li>
	</ol>
	</li>
	<li>Strong consistency<br >
	<ol>
	<li>default - no parameter<br />
   Service guaranteed: consistent view on successful updates.
    </li>
	</ol>
	</li>
	</ol>
	<p>
If you compare this list with that of other players in the market, you&#8217;ll find amazing similarities&#8230;
</p>
	<h3>Implementation considerations</h3>
	<p>
The introduction of service levels into PECL/mysqlnd_ms  - or at any other place on the client - will decrease performance.  A client cannot ask a MySQL replication cluster for a list of slaves that lag no more than <code>max_age</code> seconds or have replicated a <code>session id</code> (or global transaction id) already with only one request. <strong>There is no central instance which can answer replication cluster node status requests. </strong>
</p>
	<p>
Instead, a client has to contact the cluster nodes and check their status. Imagine 100 concurrent PHP clients of which each contacts all replication nodes to check status and forget their status at the end of the web request (remember - PHP default lifetime = web request). Hmm, that is 100 multiplied by &#8230; too much.  Too much additional traffic, too many messages, too much latency.
</p>
	<p>
Something in-between a central server-side instance and  all clients check themselves is needed. Towards the central instance side dedicated daemon processes, proxies, web server plugins or job queues come to mind. All those could poll node status information either periodically or on-demand. Status information could be shared between many web requests (= PHP and PECL/mysqlnd_ms runs). But, who of us wants an extra piece in the stack? Sure, if your PHP MySQL server farm is huge, you already have a monitoring deamon running or,  you are after SaaS/PaaS, it seems an acceptable option.
</p>
	<p>
Or, data collection is not triggered externally and nodes report their status. This could be done with a MySQL server plugin. But then, where to send the information?
</p>
	<p>
Joe-Dolittle could be happier if PECL/mysqlnd_ms copies the PHP session module approach to garbage collection. Garbage collection <a href="http://www.php.net/manual/en/session.configuration.php#ini.session.gc-divisor">can be probability based</a>.  Its performed - at the average - every <code>n</code> web requests.  The query cache plugin has copied this strategy.
</p>
	<p>
PECL/mysqlnd_ms could check node status every n web requests and cache information somewhere. Somewhere could be process memory, shared memory, memcache - whatever. This could and should help to reduce the number of node status requests from clients.
</p>
	<h3>&#8230; just try it?!</h3>
	<p>
I think, we should add the idea of a service level to PECL/mysqlnd_ms regardless of potential performance issues. In the first step, we could always fall back to choosing the master. The master can fullfill all service levels.  If nothing else, an API to set a service level makes our API better and cleaner. It is a reasonable step towards hiding cluster details from the user - just as it should be in modern times&#8230;
</p>
	<p>
As we go, we can try to reduce the cases in which the master is queried, if need be.
</p>
	<p>
Eventual consistency combined with a maximum age is a relatively soft service level. If, for example, <code>max_age=2</code> and the system does 1000 req/s, an update of the cached slave lag list every 500 requests seems reasonable.
</p>
	<p>
Choosing slaves for the most basic variant of session consistency (session bound to one web request, no user-supplied session id)  could be doable by checking for global transactions ids. When it comes to user-supplied session ids, things are likely to get nasty and slow.
</p>
	<p>Thoughts?</p>
]]></content:encoded>
			<wfw:commentRSS>http://blog.ulf-wendel.de/2011/consistency-cloud-and-the-php-mysqlnd-replication-plugin/feed/</wfw:commentRSS>
	</item>
		<item>
		<title>Executing MySQL queries with PHP mysqli</title>
		<link>http://blog.ulf-wendel.de/2011/executing-mysql-queries-with-php-mysqli/</link>
		<comments>http://blog.ulf-wendel.de/2011/executing-mysql-queries-with-php-mysqli/#comments</comments>
		<pubDate>Wed, 09 Nov 2011 08:45:02 +0000</pubDate>
		<dc:creator>Administrator</dc:creator>
		
	<category>PlanetMySQL (english)</category>
	<category>PlanetPHP (english)</category>
		<guid>http://blog.ulf-wendel.de/2011/executing-mysql-queries-with-php-mysqli/</guid>
		<description><![CDATA[	
The mysqli quickstart series is coming to an end. Today, the post is about non-prepared statements. You may also want to check out the following  related blog posts:
	
	Using MySQL prepared statements with PHP mysqli
	Using MySQL multiple statements with PHP mysqli
	Using MySQL stored procedures with PHP mysqli
	
	Using mysqli to execute statements
	
Statements can be executed by [...]]]></description>
			<content:encoded><![CDATA[	<p>
The mysqli quickstart series is coming to an end. Today, the post is about non-prepared statements. You may also want to check out the following  related blog posts:</p>
	<ul>
	<li><a href="http://blog.ulf-wendel.de/2011/using-mysql-prepared-statements-with-php-mysqli/">Using MySQL prepared statements with PHP mysqli</a></li>
	<li><a href="http://blog.ulf-wendel.de/2011/using-mysql-multiple-statements-with-php-mysqli/">Using MySQL multiple statements with PHP mysqli</a></li>
	<li><a href="http://blog.ulf-wendel.de/2011/using-mysql-stored-procedures-with-php-mysqli/">Using MySQL stored procedures with PHP mysqli</a></li>
	</ul>
	<h3>Using mysqli to execute statements</h3>
	<p>
Statements can be executed by help of the <code>mysqli_query()</code>, <code>mysqli_real_query()</code> and <code>mysqli_multi_query()</code> function. The <code>mysqli_query()</code> function is the most commonly used one. It combines executing statement and doing a buffered fetch of its result set, if any, in one call. Calling <code>mysqli_query()</code> is identical to calling <code>mysqli_real_query()</code> followed by <code>mysqli_store_result</code>.
</p>
	<p>
The <code>mysqli_multi_query()</code> function is used with Multiple Statements and is described <a href="http://blog.ulf-wendel.de/2011/using-mysql-multiple-statements-with-php-mysqli/">here</a>.
</p>
	<p>
<code></p>
	<pre>
$mysqli = new mysqli(&quot;example.com&quot;, &quot;user&quot;, &quot;password&quot;, &quot;database&quot;);
	
if (!$mysqli-&gt;query(&quot;DROP TABLE IF EXISTS test&quot;) ||
    !$mysqli-&gt;query(&quot;CREATE TABLE test(id INT)&quot;) ||
    !$mysqli-&gt;query(&quot;INSERT INTO test(id) VALUES (1)&quot;))
    echo &quot;Table creation failed: (&quot; . $mysqli-&gt;errno . &quot;) &quot; . $mysqli-&gt;error;
</pre>
	<p></code>
</p>
	<h3>Buffered result sets</h3>
	<p>
After statement execution results can be retrieved at once to be buffered by the client or by read row by row. Client-side result set buffering allows the server to free resources associated with the statement results as early as possible. Generally speaking, clients are slow consuming result sets. Therefore, it is recommended to use buffered result sets. <code>mysqli_query()</code> combines statement execution and result set buffering.
</p>
	<p>
PHP applications can navigate freely through buffered results. Nagivation is fast because the result sets is hold in client memory. Please, keep in mind that it is often easier to scale by client than it is to scale the server.
</p>
	<p><code></p>
	<pre>
$mysqli = new mysqli(&quot;localhost&quot;, &quot;root&quot;, &quot;&quot;, &quot;test&quot;);
if (!$mysqli-&gt;query(&quot;DROP TABLE IF EXISTS test&quot;) ||
    !$mysqli-&gt;query(&quot;CREATE TABLE test(id INT)&quot;) ||
    !$mysqli-&gt;query(&quot;INSERT INTO test(id) VALUES (1), (2), (3)&quot;))
    echo &quot;Table creation failed: (&quot; . $mysqli-&gt;errno . &quot;) &quot; . $mysqli-&gt;error;
	
$res = $mysqli-&gt;query(&quot;SELECT id FROM test ORDER BY id ASC&quot;);
	
echo &quot;Reverse order...\n&quot;;
for ($row_no = $res-&gt;num_rows - 1; $row_no &gt;= 0; $row_no--) {
  $res-&gt;data_seek($row_no);
  $row = $res-&gt;fetch_assoc();
  echo &quot; id = &quot; . $row['id'] . &quot;\n&quot;;
}
	
echo &quot;Result set order...\n&quot;;
$res-&gt;data_seek(0);
while ($row = $res-&gt;fetch_assoc())
 echo &quot; id = &quot; . $row['id'] . &quot;\n&quot;;
</pre>
	<p></code><br />
<code></p>
	<pre>
Reverse order...
 id = 3
 id = 2
 id = 1
Result set order...
 id = 1
 id = 2
 id = 3
</pre>
	<p></code></p>
	<h3>Unbuffered result sets</h3>
	<p>
If client memory is a short resource and freeing server resources as early as possible to keep server load low is not needed, unbuffered results can be used. Scrolling through unbuffered results is not possible before all rows have been read.
</p>
	<p>
<code></p>
	<pre>
$mysqli-&gt;real_query(&quot;SELECT id FROM test ORDER BY id ASC&quot;);
$res = $mysqli-&gt;use_result();
	
echo &quot;Result set order...\n&quot;;
while ($row = $res-&gt;fetch_assoc())
 echo &quot; id = &quot; . $row['id'] . &quot;\n&quot;;
</pre>
	<p></code>
</p>
	<h3>Result set values data types</h3>
	<p>
The <code>mysqli_query()</code>, <code>mysqli_real_query()</code> and <code>mysqli_multi_query()</code> functions are used to execute non-prepared statements. At the level of the MySQL Client Server Protocol the command <code>COM_QUERY</code> and the text protocol are used for statement execution. With the text protocol, the MySQL server converts all data of a result sets into strings before sending. This conversion is done regardless of the SQL result set column data type. The mysql client libraries receive all column values as strings. No further client-side casting is done to convert columns back to their native types. Instead, all values are provided as PHP strings.
</p>
	<p>
<code></p>
	<pre>
$mysqli = mysqli_init();
$mysqli-&gt;options(MYSQLI_OPT_INT_AND_FLOAT_NATIVE, 1);
$mysqli-&gt;real_connect(&quot;localhost&quot;, &quot;root&quot;, &quot;&quot;, &quot;test&quot;);
	
if (!$mysqli-&gt;query(&quot;DROP TABLE IF EXISTS test&quot;) ||
    !$mysqli-&gt;query(&quot;CREATE TABLE test(id INT, label CHAR(1))&quot;) ||
    !$mysqli-&gt;query(&quot;INSERT INTO test(id, label) VALUES (1, 'a')&quot;))
    echo &quot;Table creation failed: (&quot; . $mysqli-&gt;errno . &quot;) &quot; . $mysqli-&gt;error;
	
$res = $mysqli-&gt;query(&quot;SELECT id, label FROM test WHERE id = 1&quot;);
$row = $res-&gt;fetch_assoc();
	
printf(&quot;id = %s (%s)\n&quot;, $row['id'], gettype($row['id']));
printf(&quot;label = %s (%s)\n&quot;, $row['label'], gettype($row['label']));
</pre>
	<p></code><br />
<code></p>
	<pre>
id = 1 (string)
label = a (string)
</pre>
	<p></code>
</p>
	<p>
It is possible to convert integer and float columns back to PHP numbers by setting the <code>MYSQLI_OPT_INT_AND_FLOAT_NATIVE</code> connection option, <strong>if using the mysqlnd libary</strong>. If set, the mysqlnd library will check the result set meta data column types and convert numeric SQL columns to PHP numbers, if the PHP data type value range allows for it. This way, for example, SQL <code>INT</code> columns are returned as integers.
</p>
	<p>
<code></p>
	<pre>
$mysqli = mysqli_init();
$mysqli->options(MYSQLI_OPT_INT_AND_FLOAT_NATIVE, 1);
$mysqli->real_connect(\"localhost\", \"root\", \"\", \"test\");
	
if (!$mysqli->query(\"DROP TABLE IF EXISTS test\") ||
    !$mysqli->query(\"CREATE TABLE test(id INT, label CHAR(1))\") ||
    !$mysqli->query(\"INSERT INTO test(id, label) VALUES (1, 'a')\"))
    echo \"Table creation failed: (\" . $mysqli->errno . \") \" . $mysqli->error;
	
$res = $mysqli->query(\"SELECT id, label FROM test WHERE id = 1\");
$row = $res->fetch_assoc();
	
printf(\"id = %s (%s)\n\", $row['id'], gettype($row['id']));
printf(\"label = %s (%s)\n\", $row['label'], gettype($row['label']));
</pre>
	<p></code><br />
<code></p>
	<pre>
id = 1 (string)
label = a (string)
</pre>
	<p></code>
</p>
	<p>
Happy hacking!
</p>
	<p>
<a href="http://twitter.com/#!/Ulf_Wendel">@Ulf_Wendel</a>
</p>
]]></content:encoded>
			<wfw:commentRSS>http://blog.ulf-wendel.de/2011/executing-mysql-queries-with-php-mysqli/feed/</wfw:commentRSS>
	</item>
	</channel>
</rss>

