mirror of
https://github.com/sigmasternchen/php-doc-en
synced 2025-03-16 00:48:54 +00:00
MS 1.6 (current development series, alpha) - transient errors: config, concept and example, stats
git-svn-id: https://svn.php.net/repository/phpdoc/en/trunk@330540 c90b9560-bf6c-de11-be94-00142212c4b1
This commit is contained in:
parent
cf03bfdfb0
commit
5a133dd1d9
4 changed files with 363 additions and 6 deletions
|
@ -12,6 +12,63 @@
|
|||
for a complete list of changes.
|
||||
</para>
|
||||
|
||||
<section xml:id="mysqlnd-ms.changes-one-six">
|
||||
<title xmlns="http://docbook.org/ns/docbook">PECL/mysqlnd_ms 1.6 series</title>
|
||||
<para>
|
||||
1.6.0-alpha
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<simpara>
|
||||
Release date: TBD
|
||||
</simpara>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<simpara>
|
||||
Motto/theme: Maintenance
|
||||
</simpara>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
<note>
|
||||
<para>
|
||||
This is the current development series. All
|
||||
features are at an early stage. Changes may happen at any time without
|
||||
prior notice. Please, do not use this version in production environments.
|
||||
</para>
|
||||
<para>
|
||||
The documentation may not reflect all changes yet.
|
||||
</para>
|
||||
</note>
|
||||
<para>
|
||||
Bug fixes
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
No new bugs reported
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
<para>
|
||||
Feature changes
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
Introduced automatic retry loop for transient errors and
|
||||
<link linkend="function.mysqlnd-ms-get-stats">corresponding statistic</link>
|
||||
to count the number of implicit retries. Some distributed
|
||||
database clusters use transient errors to hint a client to retry
|
||||
its operation in a bit. Most often, the client is then supposed
|
||||
to halt execution (sleep) for a short moment before retrying the
|
||||
desired operation. Immediately failing over to another node
|
||||
is not necessary in response to the error. Instead, a retry loop
|
||||
can be performed. Common situation when using MySQL Cluster.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="mysqlnd-ms.changes-one-five">
|
||||
<title xmlns="http://docbook.org/ns/docbook">PECL/mysqlnd_ms 1.5 series</title>
|
||||
<para>
|
||||
|
@ -31,12 +88,11 @@
|
|||
</para>
|
||||
<note>
|
||||
<para>
|
||||
This is the current development series. All
|
||||
features are at an early stage. Changes may happen at any time without
|
||||
prior notice. Please, do not use this version in production environments.
|
||||
This is the current release series. Albeit a stable release is missing,
|
||||
it can be considered stable. Use this version in production environments.
|
||||
</para>
|
||||
<para>
|
||||
The documentation may not reflect all changes yet.
|
||||
The documentation is complete.
|
||||
</para>
|
||||
</note>
|
||||
<para>
|
||||
|
@ -140,7 +196,7 @@
|
|||
modified to use the new C API calls of the <literal>mysqlnd</literal>
|
||||
library to begin, commit, and rollback a transaction or savepoint.
|
||||
If <link linkend="ini.mysqlnd-ms-plugin-config-v2.trx-stickiness">trx_stickiness</link>
|
||||
is used to enable transaction aware load balancing, the <function>mysqli_begin</function>,
|
||||
is used to enable transaction aware load balancing, the <function>mysqli_begin</function>,
|
||||
<function>mysqli_commit</function> and <function>mysqli_rollback</function> functions
|
||||
will now be monitered by the plugin, to go along with the <function>mysqli_autocommit</function>
|
||||
function that was already supported. All SQL features to control
|
||||
|
|
|
@ -658,6 +658,166 @@ version = 5.6.2-m5-log
|
|||
</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="mysqlnd-ms.transient_errors">
|
||||
<title>Transient errors</title>
|
||||
<para>
|
||||
Some distributed database clusters make use of transient errors. A transient
|
||||
error is a temporary error that is likely to disappear soon. By definition
|
||||
it is safe for a client to ignore a transient error and retry the failed
|
||||
operation on the same database server. The retry is free of side effects.
|
||||
Clients are not forced to abort their work or to fail over to another database
|
||||
server immediately. They may enter a retry loop before to wait for the
|
||||
error to disappear before giving up on the database server.
|
||||
Transient errors can be seen, for example, when using MySQL Cluster. But they
|
||||
are not bound to any specific clustering solution per se.
|
||||
</para>
|
||||
<para>
|
||||
<literal>PECL/mysqlnd_ms</literal> can perform an automatic retry loop in
|
||||
case of a transient error. This increases distribution transparency and thus
|
||||
makes it easier to migrate an application running on a single database
|
||||
server to run on a cluster of database servers without having to change
|
||||
the source of the application.
|
||||
</para>
|
||||
<para>
|
||||
The automatic retry loop will repeat the requested operation up to a user
|
||||
configurable number of times and pause between the attempts for a configurable
|
||||
amount of time. If the error disappears during the loop, the application will
|
||||
never see it. If not, the error is forwarded to the application for handling.
|
||||
</para>
|
||||
<para>
|
||||
In the example below a duplicate key error is provoked to make the plugin
|
||||
retry the failing query two times before the error is passed to the application.
|
||||
Between the two attempts the plugin sleeps for 100 milliseconds.
|
||||
</para>
|
||||
<para>
|
||||
<example>
|
||||
<title>Provoking a transient error</title>
|
||||
<programlisting role="ini">
|
||||
<![CDATA[
|
||||
mysqlnd_ms.enable=1
|
||||
mysqlnd_ms.collect_statistics=1
|
||||
]]>
|
||||
</programlisting>
|
||||
<programlisting role="ini">
|
||||
<![CDATA[
|
||||
{
|
||||
"myapp": {
|
||||
"master": {
|
||||
"master_0": {
|
||||
"host": "localhost"
|
||||
}
|
||||
},
|
||||
"slave": {
|
||||
"slave_0": {
|
||||
"host": "192.168.78.136",
|
||||
"port": "3306"
|
||||
}
|
||||
},
|
||||
"transient_error": {
|
||||
"mysql_error_codes": [
|
||||
1062
|
||||
],
|
||||
"max_retries": 2,
|
||||
"usleep_retry": 100
|
||||
}
|
||||
}
|
||||
}
|
||||
]]>
|
||||
</programlisting>
|
||||
</example>
|
||||
</para>
|
||||
<para>
|
||||
<example>
|
||||
<title>Transient error retry loop</title>
|
||||
<programlisting role="php">
|
||||
<![CDATA[
|
||||
<?php
|
||||
$mysqli = new mysqli("myapp", "username", "password", "database");
|
||||
if (mysqli_connect_errno())
|
||||
/* Of course, your error handling is nicer... */
|
||||
die(sprintf("[%d] %s\n", mysqli_connect_errno(), mysqli_connect_error()));
|
||||
|
||||
if (!$mysqli->query("DROP TABLE IF EXISTS test") ||
|
||||
!$mysqli->query("CREATE TABLE test(id INT PRIMARY KEY)") ||
|
||||
!$mysqli->query("INSERT INTO test(id) VALUES (1))")) {
|
||||
printf("[%d] %s\n", $mysqli->errno, $mysqli->error);
|
||||
}
|
||||
|
||||
/* Retry loop is completely transparent. Checking statistics is
|
||||
the only way to know about implicit retries */
|
||||
$stats = mysqlnd_ms_get_stats();
|
||||
printf("Transient error retries before error: %d\n", $stats['transient_error_retries']);
|
||||
|
||||
/* Provoking duplicate key error to see statistics change */
|
||||
if (!$mysqli->query("INSERT INTO test(id) VALUES (1))")) {
|
||||
printf("[%d] %s\n", $mysqli->errno, $mysqli->error);
|
||||
}
|
||||
|
||||
$stats = mysqlnd_ms_get_stats();
|
||||
printf("Transient error retries after error: %d\n", $stats['transient_error_retries']);
|
||||
|
||||
$mysqli->close();
|
||||
?>
|
||||
]]>
|
||||
</programlisting>
|
||||
&example.outputs.similar;
|
||||
<screen>
|
||||
<![CDATA[
|
||||
Transient error retries before error: 0
|
||||
[1062] Duplicate entry '1' for key 'PRIMARY'
|
||||
Transient error retries before error: 2
|
||||
]]>
|
||||
</screen>
|
||||
</example>
|
||||
</para>
|
||||
<para>
|
||||
Because the execution of the retry loop is transparent from a users point of
|
||||
view, the example checks the
|
||||
<link linkend="function.mysqlnd-ms-get-stats">statistics</link>
|
||||
provided by the plugin to learn about it.
|
||||
</para>
|
||||
<para>
|
||||
As the example shows, the plugin can be instructed to consider any error
|
||||
transient regardless of the database servers error semantics. The only error
|
||||
that a stock MySQL server considers temporary has the error code
|
||||
<constant>1297</constant>. When configuring other error codes but
|
||||
<constant>1297</constant> make sure your configuration reflects
|
||||
the semantics of your clusters error codes.
|
||||
</para>
|
||||
<para>
|
||||
The following mysqlnd C API calls are monitored by the plugin to check
|
||||
for transient errors: <literal>query()</literal>,
|
||||
<literal>change_user()</literal>, <literal>select_db()</literal>,
|
||||
<literal>set_charset()</literal>, <literal>set_server_option()</literal>
|
||||
<literal>prepare()</literal>, <literal>execute()</literal>,
|
||||
<literal>set_autocommit()</literal>,
|
||||
<literal>tx_begin()</literal>, <literal>tx_commit()</literal>,
|
||||
<literal>tx_rollback()</literal>, <literal>tx_commit_or_rollback()</literal>.
|
||||
The corresponding user API calls have similar names.
|
||||
</para>
|
||||
<para>
|
||||
The maximum time the plugin may sleep during the retry loop depends on the
|
||||
function in question. The a retry loop for <literal>query()</literal>,
|
||||
<literal>prepare()</literal> or <literal>execute()</literal> will sleep for
|
||||
up to <literal>max_retries * usleep_retry</literal> milliseconds.
|
||||
</para>
|
||||
<para>
|
||||
However, functions that
|
||||
<link linkend="mysqlnd-ms.pooling">control connection state</link>
|
||||
are dispatched to all all connections. The retry loop settings are applied
|
||||
to every connection on which the command is to be run. Thus, such a function
|
||||
may interrupt program execution for longer than a function that is run
|
||||
on one server only. For example, <literal>set_autocommit()</literal> is
|
||||
dispatched to connections and may sleep up to
|
||||
<literal>(max_retries * usleep_retry) * number_of_open_connections)</literal>
|
||||
milliseconds. Please, keep this in mind when setting long sleep times
|
||||
and large retry numbers. Using the default settings of
|
||||
<literal>max_retries=1</literal>, <literal>usleep_retry=100</literal> and
|
||||
<literal>lazy_connections=1</literal> it is unlikely that you will
|
||||
ever see a delay of more than 1 second.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="mysqlnd-ms.failover">
|
||||
<title>Failover</title>
|
||||
<para>
|
||||
|
|
|
@ -442,6 +442,18 @@
|
|||
</entry>
|
||||
<entry>Since 1.2.0.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<literal>transient_error_retries</literal>
|
||||
</entry>
|
||||
<entry>
|
||||
How often an operation has been retried when a transient error was
|
||||
detected. See also,
|
||||
<link linkend="ini.mysqlnd-ms-plugin-config-v2.transient_error"><literal>transient_error</literal></link>
|
||||
plugin configuration file setting.
|
||||
</entry>
|
||||
<entry>Since 1.6.0.</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</informaltable>
|
||||
|
@ -519,6 +531,8 @@ array(26) {
|
|||
string(1) "0"
|
||||
["gtid_implicit_commit_injections_failure"]=>
|
||||
string(1) "0"
|
||||
["transient_error_retries"]=>
|
||||
string(1) "0"
|
||||
}
|
||||
]]>
|
||||
</screen>
|
||||
|
|
|
@ -2399,9 +2399,136 @@ $mysqli->set_charset("latin1");
|
|||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry xml:id="ini.mysqlnd-ms-plugin-config-v2.transient_error">
|
||||
<term>
|
||||
<parameter>transient_error</parameter>
|
||||
<type>object</type>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
The setting has been introduced in 1.6.0.
|
||||
</para>
|
||||
<para>
|
||||
A database cluster node may reply a transient error to a client. The client
|
||||
can then repeat the operation on the same node, fail over to a different node
|
||||
or abort the operation. Per definition is it safe for a client to
|
||||
retry the same operation on the same node before giving up.
|
||||
</para>
|
||||
<para>
|
||||
<literal>PECL/mysqlnd_ms</literal> can perform the retry
|
||||
loop on behalf of the application.
|
||||
By configuring <literal>transient_error</literal> the plugin can be
|
||||
instructed to repeat operations failing with a certain error code for
|
||||
a certain maximum number of times with a pause between the retries.
|
||||
If the transient error disappears during loop execution, it is
|
||||
hidden from the application. Otherwise, the error is
|
||||
forwarded to the application by the end of the loop.
|
||||
</para>
|
||||
<para>
|
||||
<example>
|
||||
<title>Retry loop for transient errors</title>
|
||||
<programlisting role="ini">
|
||||
<![CDATA[
|
||||
{
|
||||
"myapp": {
|
||||
"master": {
|
||||
"master_0": {
|
||||
"host": "localhost"
|
||||
}
|
||||
},
|
||||
"slave": {
|
||||
"slave_0": {
|
||||
"host": "192.168.78.136",
|
||||
"port": "3306"
|
||||
}
|
||||
},
|
||||
"transient_error": {
|
||||
"mysql_error_codes": [
|
||||
1297
|
||||
],
|
||||
"max_retries": 2,
|
||||
"usleep_retry": 100
|
||||
}
|
||||
}
|
||||
}
|
||||
]]>
|
||||
</programlisting>
|
||||
</example>
|
||||
</para>
|
||||
<informaltable>
|
||||
<tgroup cols="3">
|
||||
<colspec colwidth="1*"/>
|
||||
<colspec colwidth="7*"/>
|
||||
<colspec colwidth="2*"/>
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Keyword</entry>
|
||||
<entry>Description</entry>
|
||||
<entry>Version</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>
|
||||
<literal>mysql_error_codes</literal>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>
|
||||
List of transient error codes. You may add any MySQL error code
|
||||
to the list. It is possible to consider any error as transient
|
||||
not only <literal>1297</literal>
|
||||
(<literal>HY000 (ER_GET_TEMPORARY_ERRMSG),
|
||||
Message: Got temporary error %d '%s' from %s</literal>).
|
||||
Before adding other codes but <literal>1297</literal> to the list,
|
||||
make sure your cluster supports a new attempt without impacting
|
||||
the state of your application.
|
||||
</para>
|
||||
</entry>
|
||||
<entry>Since 1.6.0.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<literal>max_retries</literal>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>
|
||||
How often to retry an operation which
|
||||
fails with a transient error before forwarding the
|
||||
failure to the user.
|
||||
</para>
|
||||
<para>
|
||||
Default: <literal>1</literal>
|
||||
</para>
|
||||
</entry>
|
||||
<entry>Since 1.6.0.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<literal>usleep_retry</literal>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>
|
||||
Milliseconds to sleep between transient error retries.
|
||||
The value is passed to the C function <function>usleep</function>,
|
||||
hence the name.
|
||||
</para>
|
||||
<para>
|
||||
Default: <literal>100</literal>
|
||||
</para>
|
||||
</entry>
|
||||
<entry>Since 1.6.0.</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</informaltable>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
</para>
|
||||
</section>
|
||||
|
||||
</section>
|
||||
|
||||
<section xml:id="mysqlnd-ms.plugin-ini-v1">
|
||||
<title xmlns="http://docbook.org/ns/docbook">Plugin configuration file (<= 1.0.x)</title>
|
||||
|
|
Loading…
Reference in a new issue