安装/配置
PHP Manual

Plugin configuration file (>=1.1.x)

Note: Changelog: Feature was added in PECL/mysqlnd_ms 1.1.0-beta

下面的描述信息仅仅适用于 PECL/mysqlnd_ms >= 1.1.0-beta 即以上版本, 并不适用于这以前的版本。

插件使用自己的独立配置文件,其中包括 MySQL 主从同步的 master 服务器、 slave 服务器、负载均衡策略、错误处理策略和是否使用被动连接。

插件将在 WEB 被请求的时候装载他的配置文件,并且配置会被缓存在内存当中,为后续的 WEB 请求提供服务。这样,并不需要在更改配置以后,重新启动 PHP。对于配置文件的变更 将立即启用。

插件的配置文件通过 PHP 配置文件中使用 mysqlnd_ms.config_file 指定。请注意,PHP 配置文件指令并不会针对每个 WEB 请求而加载。所以,配置插件的 配置文件名称和路径需要重新启动 PHP。但是不需要再已经读取的插件配置变更时, 重新启动 PHP。

使用和解析 JSON 更有效率,并且使用 JSON 来表达层级的数据结构更容易,所以插件配置并没有采用类似于 php.ini 的文件格式。

Example #1 将 PHP 数组(hash) 转换为 JSON 格式

可能,开发人员对于 PHP array 更加习惯,所以这个范例展示了如何将它 转化为 JSON 格式。

<?php
$config 
= array(
  
"myapp" => array(
    
"master" => array(
      
"master_0" => array(
        
"host"   => "localhost",
        
"socket" => "/tmp/mysql.sock",
      ),
    ),
    
"slave" => array(),
  ),
);

file_put_contents("mysqlnd_ms.ini"json_encode($configJSON_PRETTY_PRINT));
printf("mysqlnd_ms.ini file created...\n");
printf("Dumping file contents...\n");
printf("%s\n"str_repeat("-"80));
echo 
file_get_contents("mysqlnd_ms.ini");
printf("\n%s\n"str_repeat("-"80));
?>

以上例程会输出:

mysqlnd_ms.ini file created...
Dumping file contents...
--------------------------------------------------------------------------------
{
    "myapp": {
        "master": {
            "master_0": {
                "host": "localhost",
                "socket": "\/tmp\/mysql.sock"
            }
        },
        "slave": [

        ]
    }
}
--------------------------------------------------------------------------------

插件的配置文件,由一个或者多个章节组成。在 JSON 文件当中, 每个章节是一个最高级别的对象。章节也可以叫做 configuration names

应用程序使用章节的名称,作为一个 host 名称传送给各种连接方法 mysqli, mysqlPDO_MYSQL。在连接时, mysqlnd 插件,将根据配置文件转化这些 章节名称。如果找到匹配的内容,那么他将装载这个章节的所有设定。

Example #2 使用章节名称的范例

{
    "myapp": {
        "master": {
            "master_0": {
                "host": "localhost"
            }
        },
        "slave": {
            "slave_0": {
                "host": "192.168.2.27"
            },
            "slave_1": {
                "host": "192.168.2.27",
                "port": 3306
            }
        }
    },
    "localhost": {
        "master": [
            {
                "host": "localhost",
                "socket": "\/path\/to\/mysql.sock"
            }
        ],
        "slave": [
            {
                "host": "192.168.3.24",
                "port": "3305"
            },
            {
                "host": "192.168.3.65",
                "port": "3309"
            }
        ]
    }
}
<?php
/* 下面所有的连接调用都将使用负载均衡 */
$mysqli = new mysqli("myapp""username""password""database");
$pdo = new PDO('mysql:host=myapp;dbname=database''username''password');
$mysql mysql_connect("myapp""username""password");

$mysqli = new mysqli("localhost""username""password""database");
?>

章节名称是一个字符串,他可以使用 192.168.2.1, 127.0.0.1 或者 localhost 作为合法的值。例如,这里定义了 localhost,应用程序去连接 localhost 的时候,连接控制就被接管。应用程序将不直接在 localhost 运行,而是使用插件提供的连接池工作,相关操作将遵循 localhost 章节中的设定运行。这样可以在不改变应用程序代码的基础上使用插件进行负载均衡。 请注意,范例的配置可能并不适用于你实际的情况。使用章节名称可以看做是一种 替代 hostname 的手段。

配置中每个章节至少要包含,master 列表和 slave 列表。master 列表使用 master 标记,slave 列表使用 slave 标记。 错误的 slave 列表,和空的 slave 列表将产生一个 E_ERROR 级别的错误。这里可以不设定 slave,当然仅仅建议在同步集群中使用。可以参考 supported clusters。 而本文档的主要目的是提供对异步的 MySQL 主从同步提供帮助。

master 和 slave 列表中的服务器,可以不定义每个服务器的名称。

Example #3 匿名 slave 列表

"slave": [
    {
        "host": "192.168.3.24",
        "port": "3305"
    },
    {
        "host": "192.168.3.65",
        "port": "3309"
    }
]

上面是一个匿名列表的 JSON array 格式。当然也可以给每个列表中 的服务器起一个满足 JSON object 要求的别名。

Example #4 使用别名的 master 列表

"master": {
    "master_0": {
        "host": "localhost"
    }
}

我们建议使用命名的服务器列表,在错误信息中我们将看到这些服务器命名。

服务器列表,会按照顺序加载到 mysqlnd_ms 当中,这样如果采用 round robin 负载均衡策略,那么第一个 SELECT 将在第一个定义的 slave 服务器中运行。

配置的服务器,可以使用 host, port, socket, db, user, passwordconnect_flags 进行设定。其中 host 是必须设定的内容,其他的是可选设定。

Example #5 Keywords to configure a server

{
    "myapp": {
        "master": {
            "master_0": {
                "host": "db_server_host",
                "port": "db_server_port",
                "socket": "db_server_socket",
                "db": "database_resp_schema",
                "user": "user",
                "password": "password",
                "connect_flags": 0
            }
        },
        "slave": {
            "slave_0": {
                "host": "db_server_host",
                "port": "db_server_port",
                "socket": "db_server_socket"
            }
        }
    }
}

如果参数遗漏了,那么插件将使用用户打开连接设定的参数替代它。可以参考 using section names example 获得更多信息。

配置文件的格式在 1.1.0-beta 版本更改,为了适应过滤器的使用。过滤器负责过滤服务器列表 的服务器来执行相关的语句。使用 filter 定义过滤器。mysqlnd_ms 将 按照过滤器中的顺序执行。当然过滤器定义是可选的。

过滤器渠道以前版本中 pick[] 的使用,并且通过新的 randomroundrobin 来提供相同的功能。

Example #6 New roundrobin filter, old functionality

{
    "myapp": {
        "master": {
            "master_0": {
                "host": "localhost"
            }
        },
        "slave": {
            "slave_0": {
                "host": "192.168.78.136",
                "port": "3306"
            },
            "slave_1": {
                "host": "192.168.78.137",
                "port": "3306"
            }
        },
        "filters": {
            "roundrobin": [

            ]
        }
    }
}

mysqlnd_ms_set_user_pick_server() 函数已经不再使用。回调策略 设定使用 user 实现。一些过滤器需要设定参数,例如 user 需要设定回调函数的名称,他相当于以前版本中,在 mysqlnd_ms_set_user_pick_server() 中的设定内容。

Example #7 The user filter replaces mysqlnd_ms_set_user_pick_server()

"filters": {
    "user": {
        "callback": "pick_server"
    }
}

The validity of the configuration file is checked both when reading the configuration file and later when establishing a connection. The configuration file is read during PHP request startup. At this early stage a PHP extension may not display error messages properly. In the worst case, no error is shown and a connection attempt fails without an adequate error message. This problem has been cured in version 1.5.0.

Example #8 Common error message in case of configuration file issues (upto version 1.5.0)

<?php
$mysqli 
= new mysqli("myapp""username""password""database");
?>

以上例程会输出:

Warning: mysqli::mysqli(): (mysqlnd_ms) (mysqlnd_ms) Failed to parse config file [s1.json]. Please, verify the JSON in Command line code

Warning: mysqli::mysqli(): (HY000/2002): php_network_getaddresses: getaddrinfo failed: Name or service not known in Command line code on line 1

Warning: mysqli::query(): Couldn't fetch mysqli in Command line code on line 1

Fatal error: Call to a member function fetch_assoc() on a non-object in Command line code on line 1

Since version 1.5.0 startup errors are additionally buffered and emitted when a connection attempt is made. Use the configuration directive mysqlnd_ms.force_config_usage to set the error type used to display buffered errors. By default an error of type E_WARNING will be emitted.

Example #9 Improved configuration file validation since 1.5.0

<?php
$mysqli 
= new mysqli("myapp""username""password""database");
?>

以上例程会输出:

Warning: mysqli::mysqli(): (mysqlnd_ms) (mysqlnd_ms) Failed to parse config file [s1.json]. Please, verify the JSON in Command line code on line 1

It can be useful to set mysqlnd_ms.force_config_usage = 1 when debugging potential configuration file errors. This will not only turn the type of buffered startup errors into E_RECOVERABLE_ERROR but also help detecting misspelled section names.

Example #10 Possibly more precise error due to mysqlnd_ms.force_config_usage=1

mysqlnd_ms.force_config_usage=1
<?php
$mysqli 
= new mysqli("invalid_section""username""password""database");
?>

以上例程会输出:

Warning: mysqli::mysqli(): (mysqlnd_ms) Exclusive usage of configuration enforced but did not find the correct INI file section (invalid_section) in Command line code on line 1 line 1

Here is a short explanation of the configuration directives that can be used.

master array or object

List of MySQL replication master servers. The list of either of the JSON type array to declare an anonymous list of servers or of the JSON type object. Please, see above for examples.

Setting at least one master server is mandatory. The plugin will issue an error of type E_ERROR if the user has failed to provide a master server list for a configuration section. The fatal error may read (mysqlnd_ms) Section [master] doesn't exist for host [name_of_a_config_section] in %s on line %d.

A server is described with the host, port, socket, db, user, password and connect_flags. It is mandatory to provide at a value for host. If any of the other values is not given, it will be taken from the user API connect call, please, see also: using section names example.

Table of server configuration keywords.

Keyword Description Version
host

Database server host. This is a mandatory setting. Failing to provide, will cause an error of type E_RECOVERABLE_ERROR when the plugin tries to connect to the server. The error message may read (mysqlnd_ms) Cannot find [host] in [%s] section in config in %s on line %d.

Since 1.1.0.
port

Database server TCP/IP port.

Since 1.1.0.
socket

Database server Unix domain socket.

Since 1.1.0.
db

Database (schemata).

Since 1.1.0.
user

MySQL database user.

Since 1.1.0.
password

MySQL database user password.

Since 1.1.0.
connect_flags

Connection flags.

Since 1.1.0.

The plugin supports using only one master server. An experimental setting exists to enable multi-master support. The details are not documented. The setting is meant for development only.

slave array or object

List of one or more MySQL replication slave servers. The syntax is identical to setting master servers, please, see master above for details.

The plugin supports using one or more slave servers.

Setting a list of slave servers is mandatory. The plugin will report an error of the type E_ERROR if slave is not given for a configuration section. The fatal error message may read (mysqlnd_ms) Section [slave] doesn't exist for host [%s] in %s on line %d. Note, that it is valid to use an empty slave server list. The error has been introduced to prevent accidently setting no slaves by forgetting about the slave setting. A master-only setup is still possible using an empty slave server list.

If an empty slave list is configured and an attempt is made to execute a statement on a slave the plugin may emit a warning like mysqlnd_ms) Couldn't find the appropriate slave connection. 0 slaves to choose from. upon statement execution. It is possible that another warning follows such as (mysqlnd_ms) No connection selected by the last filter.

global_transaction_id_injection array or object

全局同步标识,可以配置为使用服务器内置的 GTID,也可以使用客户端模拟的。

Keyword Description Version
fetch_last_gtid

用于查询最新 GTID 的 SQL 语句,当插件需要得到最新的 GTID 的时候会执行这个语句。 他也可以用于检查 MySQL 主从同步的 slave 状态。mysqlnd_ms_get_laster_gtid() 也很会使用这个设定。

Since 1.2.0.
check_for_gtid

SQL 语句,他用于检查要查询的相关内容是否已经被同步。当使用比最终一致性 更高的服务一致性级别的时候会被使用。这个 SQL 语句中必须包含 #GTID 占位符,在执行的时候他将有插件替换成需要的 GTID。 可以参考 quickstart 查询相关范例。

Since 1.2.0.
report_errors

当执行相关配置的 SQL 语句的时候若发生错误是否进行报警。

Since 1.2.0.
on_commit

客户端 GTID 模拟使用的 SQL 语句,当 master 执行语句以后,会使用这个 SQL 语句更新模拟的 GTID,可以参考 quickstart 查看相关范例。

Since 1.2.0.
wait_for_gtid_timeout

插件等待 wait_for_gtid_timeout 秒,看 slave 是否能够 满足 Session 一致性的要求。这个参数限制了 slave 状态的轮循时间,如果轮循 的时间非常长,那么总体小号的时间会超过 wait_for_gtid_timeout。 在两次轮循之间,插件会调用 sleep(1) 去等待 1 秒。

这个参数可以在客户端模拟 GTID 或者在 MySQL 5.6 版本使用服务器端内置的 GTID 的时候使用。

等待 slave 能够同步到 Session 一致性要求的 GTID,意味着将调节客户端。 这种调节,可以在 master 上间接的降低写负载。基于复制的系统,例如 MySQL 主从同步会消耗大量的时间在一致性同步上,这种设置可以防止 master 过载。

Since 1.4.0.
filters object

List of filters. A filter is responsible to filter the list of available servers for executing a given statement. Filters can be chained. The random and roundrobin filter replace the pick[] directive used in prior version to select a load balancing policy. The user filter replaces the mysqlnd_ms_set_user_pick_server() function.

Filters may accept parameters to refine their actions.

If no load balancing policy is set, the plugin will default to random_once. The random_once policy picks a random slave server when running the first read-only statement. The slave server will be used for all read-only statements until the PHP script execution ends. No load balancing policy is set and thus, defaulting takes place, if neither the random nor the roundrobin are part of a configuration section.

If a filter chain is configured so that a filter which output no more than once server is used as input for a filter which should be given more than one server as input, the plugin may emit a warning upon opening a connection. The warning may read: (mysqlnd_ms) Error while creating filter '%s' . Non-multi filter '%s' already created. Stopping in %s on line %d. Furthermore, an error of the error code 2000, the sql state HY000 and an error message similar to the warning may be set on the connection handle.

Example #11 Invalid filter sequence

{
    "myapp": {
        "master": {
            "master_0": {
                "host": "localhost"
            }
        },
        "slave": {
            "slave_0": {
                "host": "192.168.78.136",
                "port": "3306"
            }
        },
        "filters": [
            "roundrobin",
            "random"
        ]
    }
}
<?php
$link 
= new mysqli("myapp""root""""test");
printf("[%d] %s\n"mysqli_connect_errno(), mysqli_connect_error());
$link->query("SELECT 1 FROM DUAL");
?>

以上例程会输出:

PHP Warning:  mysqli::mysqli(): (HY000/2000): (mysqlnd_ms) Error while creating filter 'random' . Non-multi filter 'roundrobin' already created. Stopping in filter_warning.php on line 1
[2000] (mysqlnd_ms) Error while creating filter 'random' . Non-multi filter 'roundrobin' already created. Stopping
PHP Warning:  mysqli::query(): Couldn't fetch mysqli in filter_warning.php on line 3

Filter: random object

random 过滤器提供 random 或者 random_once 负载均衡策略, 老版本的使用可以参考 pick[]

当执行只读语句的时候,随机策略会随机挑选一个服务器,random_once 会在页面第一次 请求的时候随机挑选一个服务器,然后在页面后续的访问中使用同一个服务器。random_once 是默认设置。

如果 random 过滤器没有设定任何参数,那么会使用随机负载均衡策略。

Example #12 Random load balancing with random filter

{
    "myapp": {
        "master": {
            "master_0": {
                "host": "localhost"
            }
        },
        "slave": {
            "slave_0": {
                "host": "192.168.78.136",
                "port": "3306"
            },
            "slave_1": {
                "host": "192.168.78.137",
                "port": "3306"
            }
        },
        "filters": [
            "random"
        ]
    }
}

可以设置 sticky 参数,如果设置了这个参数 1 过滤器将采用 random_once 策略。

Example #13 Random once load balancing with random filter

{
    "filters": {
        "random": {
            "sticky": "1"
        }
    }
}

从 1.4.0 版本开始,randomroundrobin 过滤器都可以设定服务器权重 (优先级)。如果要使用权重,那么所有的服务器都需要 分配 weight。使用权重,那么 master 和 slave 都需要 使用命名设定。

Example #14 Referencing error

[E_RECOVERABLE_ERROR] mysqli_real_connect(): (mysqlnd_ms) Unknown server 'slave3' in 'random' filter configuration. Stopping in %s on line %d

如果对于一个非法的服务器命名设定 weight,那么会产生一个 类似于上面的错误信息。

如果遗漏了 weight 设定,所有服务器的权重是 1。

Example #15 Assigning a weight for load balancing

{
   "myapp": {
       "master": {
           "master1":{
               "host":"localhost",
               "socket":"\/var\/run\/mysql\/mysql.sock"
           }
       },
       "slave": {
           "slave1": {
               "host":"192.168.2.28",
               "port":3306
           },
           "slave2": {
               "host":"192.168.2.29",
               "port":3306
           },
           "slave3": {
               "host":"192.0.43.10",
               "port":3306
           },
       },
       "filters": {
           "random": {
               "weights": {
                   "slave1":8,
                   "slave2":4,
                   "slave3":1,
                   "master1":1
               }
           }
       }
   }
}

如果服务器的权重设置为 2,那么他使用的次数将是那些权重为 1 的服务器的两倍。 不同的权重设定,可以基于不同的服务器性能、网络延迟、或者你更喜欢的原因。 基于网络延迟的原因,可以给服务器设置一个比较低的权重,例如上面的范例中,对于 slave3 只有 1/8 的使用权重,这样他比 slave1slave2 只有很少的使用几率。只有当其他两台设备都产生错误时, slave3 使用率才会上升。在使用权重的时候,一定要查看错误处理 相关的说明。

可以设定 1 - 65535 之间的数字

非法的参数将会被忽略,而不会进行任何报警。

如果过滤器使用一个或者多个 master,一个 slave,那么使用 randomroundrobin 执行语句,会产生一个报警或者错误信息。

过滤器的参数

Keyword Description Version
sticky

是否激活 random_once 负载均衡策略

Since 1.2.0.
weight

为服务器设置负载均衡权重 (优先级)

Since 1.4.0.
Filter: roundrobin object

如果使用 roundrobin 过滤器,插件会轮循配置文件中 所有配置的 slaver。如果插件已经使用的 slave 列表的结尾,他会重新从列表 头开始使用 slave 服务器。

Example #16 roundrobin filter

{
    "myapp": {
        "master": {
            "master_0": {
                "host": "localhost"
            }
        },
        "slave": {
            "slave_0": {
                "host": "192.168.78.136",
                "port": "3306"
            }
        },
        "filters": [
            "roundrobin"
        ]
    }
}

如果设定了一个或者多个 master,而只设置了一个 slave,那么采用 roundrobin, random 在执行语句的 时候,会在连接中产生一个报警或者错误信息。

过滤器使用的参数。

Keyword Description Version
weight

设置服务器的权重(优先级),可以参考 above 的说明。

Since 1.4.0.
Filter: user object

The user replaces mysqlnd_ms_set_user_pick_server() function, which was removed in 1.1.0-beta. The filter sets a callback for user-defined read/write splitting and server selection.

The plugins built-in read/write query split mechanism decisions can be overwritten in two ways. The easiest way is to prepend a query string with the SQL hints MYSQLND_MS_MASTER_SWITCH, MYSQLND_MS_SLAVE_SWITCH or MYSQLND_MS_LAST_USED_SWITCH. Using SQL hints one can control, for example, whether a query shall be send to the MySQL replication master server or one of the slave servers. By help of SQL hints it is not possible to pick a certain slave server for query execution.

Full control on server selection can be gained using a callback function. Use of a callback is recommended to expert users only because the callback has to cover all cases otherwise handled by the plugin.

The plugin will invoke the callback function for selecting a server from the lists of configured master and slave servers. The callback function inspects the query to run and picks a server for query execution by returning the hosts URI, as found in the master and slave list.

If the lazy connections are enabled and the callback chooses a slave server for which no connection has been established so far and establishing the connection to the slave fails, the plugin will return an error upon the next action on the failed connection, for example, when running a query. It is the responsibility of the application developer to handle the error. For example, the application can re-run the query to trigger a new server selection and callback invocation. If so, the callback must make sure to select a different slave, or check slave availability, before returning to the plugin to prevent an endless loop.

Example #17 Setting a callback

{
    "myapp": {
        "master": {
            "master_0": {
                "host": "localhost"
            }
        },
        "slave": {
            "slave_0": {
                "host": "192.168.78.136",
                "port": "3306"
            }
        },
        "filters": {
            "user": {
                "callback": "pick_server"
            }
        }
    }
}

The callback is supposed to return a host to run the query on. The host URI is to be taken from the master and slave connection lists passed to the callback function. If callback returns a value neither found in the master nor in the slave connection lists the plugin will emit an error of the type E_RECOVERABLE_ERROR The error may read like (mysqlnd_ms) User filter callback has returned an unknown server. The server 'server that is not in master or slave list' can neither be found in the master list nor in the slave list. If the application catches the error to ignore it, follow up errors may be set on the connection handle, for example, (mysqlnd_ms) No connection selected by the last filter with the error code 2000 and the sqlstate HY000. Furthermore a warning may be emitted.

Referencing a non-existing function as a callback will result in any error of the type E_RECOVERABLE_ERROR whenever the plugin tries to callback function. The error message may reads like: (mysqlnd_ms) Specified callback (pick_server) is not a valid callback. If the application catches the error to ignore it, follow up errors may be set on the connection handle, for example, (mysqlnd_ms) Specified callback (pick_server) is not a valid callback with the error code 2000 and the sqlstate HY000. Furthermore a warning may be emitted.

The following parameters are passed from the plugin to the callback.

Parameter Description Version
connected_host

URI of the currently connected database server.

Since 1.1.0.
query

Query string of the statement for which a server needs to be picked.

Since 1.1.0.
masters

List of master servers to choose from. Note, that the list of master servers may not be identical to the list of configured master servers if the filter is not the first in the filter chain. Previously run filters may have reduced the master list already.

Since 1.1.0.
slaves

List of slave servers to choose from. Note, that the list of master servers may not be identical to the list of configured master servers if the filter is not the first in the filter chain. Previously run filters may have reduced the master list already.

Since 1.1.0.
last_used_connection

URI of the server of the connection used to execute the previous statement on.

Since 1.1.0.
in_transaction

Boolean flag indicating whether the statement is part of an open transaction. If autocommit mode is turned off, this will be set to TRUE. Otherwise it is set to FALSE.

Transaction detection is based on monitoring the mysqlnd library call set_autocommit. Monitoring is not possible before PHP 5.4.0. Please, see connection pooling and switching concepts discussion for further details.

Since 1.1.0.

Example #18 Using a callback

{
    "myapp": {
        "master": {
            "master_0": {
                "host": "localhost"
            }
        },
        "slave": {
            "slave_0": {
                "host": "192.168.2.27",
                "port": "3306"
            },
            "slave_1": {
                "host": "192.168.78.136",
                "port": "3306"
            }
        },
        "filters": {
            "user": {
                "callback": "pick_server"
            }
        }
    }
}
<?php
function pick_server($connected$query$masters$slaves$last_used_connection$in_transaction)
{
 static 
$slave_idx 0;
 static 
$num_slaves NULL;
 if (
is_null($num_slaves))
  
$num_slaves count($slaves);

 
/* default: fallback to the plugins build-in logic */
 
$ret NULL;

 
printf("User has connected to '%s'...\n"$connected);
 
printf("... deciding where to run '%s'\n"$query);

 
$where mysqlnd_ms_query_is_select($query);
 switch (
$where)
 {
  case 
MYSQLND_MS_QUERY_USE_MASTER:
   
printf("... using master\n");
   
$ret $masters[0];
   break;
  case 
MYSQLND_MS_QUERY_USE_SLAVE:
   
/* SELECT or SQL hint for using slave */
   
if (stristr($query"FROM table_on_slave_a_only"))
   {
    
/* a table which is only on the first configured slave  */
    
printf("... access to table available only on slave A detected\n");
    
$ret $slaves[0];
   }
   else
   {
    
/* round robin */
    
printf("... some read-only query for a slave\n");
    
$ret $slaves[$slave_idx++ % $num_slaves];
   }
   break;
  case 
MYSQLND_MS_QUERY_LAST_USED:
   
printf("... using last used server\n");
   
$ret $last_used_connection;
   break;
 }

 
printf("... ret = '%s'\n"$ret);
 return 
$ret;
}

$mysqli = new mysqli("myapp""root""""test");

if (!(
$res $mysqli->query("SELECT 1 FROM DUAL")))
 
printf("[%d] %s\n"$mysqli->errno$mysqli->error);
else
 
$res->close();

if (!(
$res $mysqli->query("SELECT 2 FROM DUAL")))
 
printf("[%d] %s\n"$mysqli->errno$mysqli->error);
else
 
$res->close();


if (!(
$res $mysqli->query("SELECT * FROM table_on_slave_a_only")))
 
printf("[%d] %s\n"$mysqli->errno$mysqli->error);
else
 
$res->close();

$mysqli->close();
?>

以上例程会输出:

User has connected to 'myapp'...
... deciding where to run 'SELECT 1 FROM DUAL'
... some read-only query for a slave
... ret = 'tcp://192.168.2.27:3306'
User has connected to 'myapp'...
... deciding where to run 'SELECT 2 FROM DUAL'
... some read-only query for a slave
... ret = 'tcp://192.168.78.136:3306'
User has connected to 'myapp'...
... deciding where to run 'SELECT * FROM table_on_slave_a_only'
... access to table available only on slave A detected
... ret = 'tcp://192.168.2.27:3306'

Filter: user_multi object

The user_multi differs from the user only in one aspect. Otherwise, their syntax is identical. The user filter must pick and return exactly one node for statement execution. A filter chain usually ends with a filter that emits only one node. The filter chain shall reduce the list of candidates for statement execution down to one. This, only one node left, is the case after the user filter has been run.

The user_multi filter is a multi filter. It returns a list of slave and a list of master servers. This list needs further filtering to identify exactly one node for statement execution. A multi filter is typically placed at the top of the filter chain. The quality_of_service filter is another example of a multi filter.

The return value of the callback set for user_multi must be an an array with two elements. The first element holds a list of selected master servers. The second element contains a list of selected slave servers. The lists shall contain the keys of the slave and master servers as found in the slave and master lists passed to the callback. The below example returns random master and slave lists extracted from the functions input.

Example #19 Returning random masters and slaves

<?php
function pick_server($connected$query$masters$slaves$last_used_connection$in_transaction)
{
  
$picked_masters = array()
  foreach (
$masters as $key => $value) {
    if (
mt_rand(02) > 1)
      
$picked_masters[] = $key;
  }
  
$picked_slaves = array()
  foreach (
$slaves as $key => $value) {
    if (
mt_rand(02) > 1)
      
$picked_slaves[] = $key;
  }
  return array(
$picked_masters$picked_slaves);
}
?>

The plugin will issue an error of type E_RECOVERABLE if the callback fails to return a server list. The error may read (mysqlnd_ms) User multi filter callback has not returned a list of servers to use. The callback must return an array in %s on line %d. In case the server list is not empty but has invalid servers key/ids in it, an error of type E_RECOVERABLE will the thrown with an error message like (mysqlnd_ms) User multi filter callback has returned an invalid list of servers to use. Server id is negative in %s on line %d, or similar.

Whether an error is emitted in case of an empty slave or master list depends on the configuration. If an empty master list is returned for a write operation, it is likely that the plugin will emit a warning that may read (mysqlnd_ms) Couldn't find the appropriate master connection. 0 masters to choose from. Something is wrong in %s on line %d. Typically a follow up error of type E_ERROR will happen. In case of a read operation and an empty slave list the behavior depends on the fail over configuration. If fail over to master is enabled, no error should appear. If fail over to master is deactivated the plugin will emit a warning that may read (mysqlnd_ms) Couldn't find the appropriate slave connection. 0 slaves to choose from. Something is wrong in %s on line %d.

Filter: node_groups object

The node_groups filter lets you group cluster nodes and query selected groups, for example, to support data partitioning. Data partitioning can be required for manual sharding, primary copy based clusters running multiple masters, or to avoid hot spots in update everywhere clusters that have no built-in partitioning. The filter is a multi filter which returns zero, one or multiple of its input servers. Thus, it must be followed by other filters to reduce the number of candidates down to one for statement execution.

Keyword Description Version
user defined node group name

One or more node groups must be defined. A node group can have an arbitrary user defined name. The name is used in combination with a SQL hint to restrict query execution to the nodes listed for the node group. To run a query on any of the servers of a node group, the query must begin with the SQL hint /*user defined node group name*/. Please note, no white space is allowed around user defined node group name. Because user defined node group name is used as-is as part of a SQL hint, you should choose the name that is compliant with the SQL language.

Each node group entry must contain a list of master servers. Additional slave servers are allowed. Failing to provide a list of master for a node group name_of_group may cause an error of type E_RECOVERABLE_ERROR like (mysqlnd_ms) No masters configured in node group 'name_of_group' for 'node_groups' filter.

The list of master and slave servers must reference corresponding entries in the global master respectively slave server list. Referencing an unknown server in either of the both server lists may cause an E_RECOVERABLE_ERROR error like (mysqlnd_ms) Unknown master 'server_alias_name' (section 'name_of_group') in 'node_groups' filter configuration.

Example #20 Manual partitioning

{
  "myapp": {
       "master": {
            "master_0": {
                "host": "localhost",
                "socket": "\/tmp\/mysql.sock"
            }
        },
        "slave": {
            "slave_0": {
                "host": "192.168.2.28",
                "port": 3306
            },
            "slave_1": {
                "host": "127.0.0.1",
                "port": 3311
            }
        },
        "filters": {
            "node_groups": {
                "Partition_A" : {
                    "master": ["master_0"],
                    "slave": ["slave_0"]
                }
            },
           "roundrobin": []
        }
    }
}

Please note, if a filter chain generates an empty slave list and the PHP configuration directive mysqlnd_ms.multi_master=0 is used, the plugin may emit a warning.

Since 1.5.0.
Filter: quality_of_service object

quality_of_service 用于设定群组的服务级别。 The quality_of_service identifies cluster nodes capable of delivering a certain quality of service. It is a multi filter which returns zero, one or multiple of its input servers. Thus, it must be followed by other filters to reduce the number of candidates down to one for statement execution.

The quality_of_service filter has been introduced in 1.2.0-alpha. In the 1.2 series the filters focus is on the consistency aspect of service quality. Different types of clusters offer different default data consistencies. For example, an asynchronous MySQL replication slave offers eventual consistency. The slave may not be able to deliver requested data because it has not replicated the write, it may serve stale database because its lagging behind or it may serve current information. Often, this is acceptable. In some cases higher consistency levels are needed for the application to work correct. In those cases, the quality_of_service can filter out cluster nodes which cannot deliver the necessary quality of service.

The quality_of_service filter can be replaced or created at runtime. A successful call to mysqlnd_ms_set_qos() removes all existing qos filter entries from the filter list and installs a new one at the very beginning. All settings that can be made through mysqlnd_ms_set_qos() can also be in the plugins configuration file. However, use of the function is by far the most common use case. Instead of setting session consistency and strong consistency service levels in the plugins configuration file it is recommended to define only masters and no slaves. Both service levels will force the use of masters only. Using an empty slave list shortens the configuration file, thus improving readability. The only service level for which there is a case of defining in the plugins configuration file is the combination of eventual consistency and maximum slave lag.

Keyword Description Version
eventual_consistency

Request eventual consistency. Allows the use of all master and slave servers. Data returned may or may not be current.

Eventual consistency accepts an optional age parameter. If age is given the plugin considers only slaves for reading for which MySQL replication reports a slave lag less or equal to age. The replication lag is measure using SHOW SLAVE STATUS. If the plugin fails to fetch the replication lag, the slave tested is skipped. Implementation details and tips are given in the quality of service concepts section.

Please note, if a filter chain generates an empty slave list and the PHP configuration directive mysqlnd_ms.multi_master=0 is used, the plugin may emit a warning.

Example #21 Global limit on slave lag

{
    "myapp": {
        "master": {
            "master_0": {
                "host": "localhost"
            }
        },
        "slave": {
            "slave_0": {
                "host": "192.168.2.27",
                "port": "3306"
            },
            "slave_1": {
                "host": "192.168.78.136",
                "port": "3306"
            }
        },
        "filters": {
            "quality_of_service": {
                "eventual_consistency": {
                    "age":123
                }
            }
        }
    }
}

Since 1.2.0.
session_consistency

Request session consistency (read your writes). Allows use of all masters and all slaves which are in sync with the master. If no further parameters are given slaves are filtered out as there is no reliable way to test if a slave has caught up to the master or is lagging behind. Please note, if a filter chain generates an empty slave list and the PHP configuration directive mysqlnd_ms.multi_master=0 is used, the plugin may emit a warning.

Session consistency temporarily requested using mysqlnd_ms_set_qos() is a valuable alternative to using master_on_write. master_on_write is likely to send more statements to the master than needed. The application may be able to continue operation at a lower consistency level after it has done some critical reads.

Since 1.1.0.
strong_consistency

Request strong consistency. Only masters will be used.

Since 1.2.0.
failover 1.3.x 版本以前(包含): string. 1.4.0 版本以后: object.

错误处理策略,支持:disabled (默认), master, loop_before_master (Since 1.4.0).

如果没有设定错误处理策略 (failover=disabled) 插件不会做 任何的自动错误处理。这样,只要插件连接服务器出现错误,他将抛出一个报警信息, 并且设定连接中的错误编号和信息。

请注意,自动错误处理只对已经打开的链接起作用。如果一个连接再没有自动处理前已经 打开,那么产生错误的时候他会重新被打开。例如,如果一个服务器的链接已经关闭, 用户尝试在这个链接上执行语句,那么在没有自动错误处理的时候,将不会被重试,而是 直接报告错误。

如果设置 failover=master,插件将自己到 master 进行尝试, 请参考概念文档查看鞥多关于错误处理和使用 failover=master 可能产生的风险。

Example #22 Optional master failover when failing to connect to slave (PECL/mysqlnd_ms < 1.4.0)

{
    "myapp": {
        "master": {
            "master_0": {
                "host": "localhost"
            }
        },
        "slave": {
            "slave_0": {
                "host": "192.168.78.136",
                "port": "3306"
            }
        },
        "failover": "master"
    }
}

从 1.4.0 版本开始,配置文件更改为对象定义方式。

Example #23 New syntax since 1.4.0

{
    "myapp": {
        "master": {
            "master_0": {
                "host": "localhost"
            }
        },
        "slave": {
            "slave_0": {
                "host": "192.168.78.136",
                "port": "3306"
            }
        },
        "failover": {"strategy": "master" }
    }
}

Keyword Description Version
strategy

错误处理策略,可以使用 disabled (默认), master, loop_before_master

disabled 将会禁用自动错误处理。

master 设置将会在连接 slave 出现错误的时候 尝试连接 master。如果 master 连接错误,插件将在错误处理循环中处理, 并且返回一个错误给用户。

如果 loop_before_master 设置,对于 slave 请求, 插件会在其他 slave 尝试,然后才在 master 尝试。如果设定了多个 master 并且启用了多 master 设定,那么插件也会在其他 master 进行尝试,都失败后 才会报告错误给用户。

Since 1.4.0.
remember_failed

在 WEB 请求期间记住产生错误的服务器,默认值 false

如果设置为 true,当前 WEB 页面的请求期间, 插件将记住失败的主机,并且在后面的负载均衡过程中自动跳过这个出错的主机。

从 1.4.0 版本开始,这个功能只能与 randomroundrobin 负载均衡策略同时使用,建议使用这个参数。
max_retries

在跳过一个主机前尝试的次数,默认值:0 (不限制)

这个设定用于禁止在第一次产生错误的时候,就将这个主机从主机列表中剔除, 插件将在出现错误后继续在主机列表中保留这个主机。这个主机将不会在出现 第一次连接错误的时候被剔除,在负载均衡的使用过程中,出现 n 次错误以后,才会被剔除掉。

从 1.4.0 版本开始,这个设定只能与 randomroundrobin 负载均衡策略同时使用。

如果设定 failover 的值不是 disabledmaster 或者 loop_before_master,那么 将产生一个报警信息或者是错误。

lazy_connections bool

被动连接是默认的选项,他在第一次发送执行语句的时候才真正建立连接。

我们强烈建议使用被动连接模式,他可以有效的降低连接数。如果禁用了被动连接 模式,如果配置了一个 MySQL 主从同步 master 和两个 slave,那么即使应用程序 只使用了 master 执行了一条语句,也会建立 3 个链接。

使用被动连接会对用户更改连接状态信息产生风险。插件并不能分派所有的链接 状态信息到连接池中的每个连接上,只有少量的操作会被分发到已经打开的连接中, 处于被动连接模式中还没有打开的连接无法得到改变。只有部分的设置会被记住, 并且会在被动连接模式下的链接真正建立的时候设置。

Example #24 禁用被动连接模式

{
    "myapp": {
        "master": {
            "master_0": {
                "host": "localhost"
            }
        },
        "slave": {
            "slave_0": {
                "host": "192.168.78.136",
                "port": "3306"
            }
        },
        "lazy_connections": 0
    }
}

请参考 server_charset 处理可能产生的服务器默认字符集 和使用的字符集产生的影响。

server_charset string

这个设置从 1.4.0 版本开始使用,建议在被动连接的时候使用。

这个参数设定有两个目的,在连接建立完成以后设定返回的字符串的字符集,并且 当服务器采用不同的字符集时避免产生字符集转换的错误。

字符集转换是设定在连接上的,当连接没有打开或者字符集不合法的时候字符集转换 将不起作用。如果使用的是被动连接,那么在实际的语句没有发送以前,连接是不打开的。

应用程序在使用被动连接时,在没有发送任何执行语句以前尝试进行字符集转换, 会产生一个 E_WARNING 级别的错误,因为这时连接其实 并没有建立。会在错误处理中得到一个类似于 (mysqlnd_ms) string escaping doesn't work without established connection. Possible solution is to add server_charset to your configuration 的错误信息。

server_charset 设置可以在被动连接启动以前设置,这样当连接 建立以后,会使用这个字符集作为字符集转换的目标。

在配置中指定字符集,可以避免由于服务器字符集不同而导致出现的错误。这个设定 还有一个附加的好处,迫使所有的服务器采用同样的字符集设定。无论服务器本身的 字符集设定是什么,插件将统一按照配置中的设定作为默认字符集使用。

插件不会阻止任何时候用户通过调用 set_charset() 或者在 SQL 语句中设定字符集。但是请注意,在 SQL 语句中设置字符集是不建议使用的,因为插件 无法监控到这种变化。在被动连接模式下,用户可以在连接建立以后,更改默认字符集。 在配置文件中设定的字符集,将在连接建立后使用,而不管服务器的字符集设定,也不管 用户之前的设定。在实际连接建立以前,set_charset 的设定没有 任何作用。

Example #25 在被动连接模式下,字符集转换控制

{
    "myapp": {
        "master": {
            "master_0": {
                "host": "localhost"
            }
        },
        "slave": {
            "slave_0": {
                "host": "192.168.78.136",
                "port": "3306"
            }
        },
        "lazy_connections": 1,
        "server_charset" : "utf8"
    }
}
<?php
$mysqli 
= new mysqli("myapp""username""password""database");
/* 译者注:下面将被转换为 UTF8,因为配置中这样设定的 */
$mysqli->real_escape("this will be escaped using the server_charset setting - utf8");
/* 译者注:下面的语句么有任何作用 */
$mysqli->set_charset("latin1");
/* 译者注:下面由于 mysqli 对象自己的字符集被上一条语句改变,所以本地字符转换会遵循对象内的设定被转换为 latin1 */
$mysqli->real_escape("this will be escaped using latin1");
/* 执行语句,相当于实际连接建立,配置文件中的设定会导致 mysqli 对象中的字符集重新被设定位 UTF8 */
$mysqli->query("SELECT 'This connection will be set to server_charset upon establishing' AS _msg FROM DUAL");
/* 这时进行设定,后面的相关默认字符集针对实际连接才被转换为 latin1 */
$mysqli->set_charset("latin1");
?>

master_on_write bool

如果设定这个参数,那么插件将从第一次在 master 执行语句以后,将后面 所有的语句发送给 master 执行。当然应用程序依然可以使用 SQL hints 来让插件自动判断是否从 slave 执行相关语句。

这个设置是为了解决同步延迟问题的。如果应用程序执行了一条 INSERT 语句,那么插件将默认将后面的所有操作,包括 SELECT 语句发送到 master 执行。这样将有助于解决 从 slave 服务器中查询没有完成 INSETER 同步的问题。

Example #26 Master on write for consistent reads

{
    "myapp": {
        "master": {
            "master_0": {
                "host": "localhost"
            }
        },
        "slave": {
            "slave_0": {
                "host": "192.168.78.136",
                "port": "3306"
            }
        },
        "master_on_write": 1
    }
}

请注意,从 1.2.0-alpha 版本开始,quality_of_service 已经可以使用了。 如果希望更好的完成这种控制,可以使用 服务级别 来更好的控制。

所有的 transaction stickiness 设置, 包括 trx_stickiness=on 将推翻 master_on_write=1 的设定。

trx_stickiness string

事务控制策略,支持 disabled (默认),master

这个设置需要使用 PHP 5.4.0 以上版本,如果再以前的版本使用,将会叨叨类似下面 (mysqlnd_ms) trx_stickiness strategy is not supported before PHP 5.3.99 的一条警告信息。

如果没有设定这个参数,或者设置 trx_stickiness=disabled 那么插件将不关心事务处理。这样在事务处理的中间,可能由于负载均衡而切换链接。 为了避免这个情况,就必须使用 SQL hints 来暂时屏蔽连接切换。

从 PHP 5.4.0 版本开始,mysqlnd 允许插件通过 set_autocommit() 函数监控 autocommit 的设定值。如果设置 set_stickiness=master 并且 autocommit 被 PHP MySQL 扩展通过 set_autocommit() 设置为禁用,插件就会认为 事务处理已经开始了。这时,插件会停止负载均衡,将所有的语句发送给 master, 直到 autocommit 被启用。当然整个过程中,不需要使用 SQL hints。

例如 mysqli_autocommit() 会调用 mysqlnd 内的 set_autocommit() 方法,控制 autocommit 的状态。

当然,即使设定了 trx_stickiness=master 插件也无法监控到 SQL 语句 当中 SET AUTOCOMMIT=0 或者 BEGIN 的使用。

从 PHP 5.5.0 版本开始,mysqlnd 库增加了控制事务处理的 C API。控制级别可以匹配 SQL 语句中的的意图,mysqlid 使用这些嗲用的 API 被更改。这样,从 1.5.0 版本开始,插件不仅仅可以监控 mysqli_autocommit(),也可以 监控mysqli_begin()mysqli_commit()mysqli_rollback()。这就可以识别事务处理的边界,并且在执行事务处理 过程中停止负载均衡。

Example #27 使用 master 执行事务处理

{
    "myapp": {
        "master": {
            "master_0": {
                "host": "localhost"
            }
        },
        "slave": {
            "slave_0": {
                "host": "192.168.78.136",
                "port": "3306"
            }
        },
        "trx_stickiness": "master"
    }
}

从 1.5.0 版本开始,事务处理过程中自动的和沉默的错误处理被禁用。如果事务处理的边界 被识别,事务处理控制被启动,如果服务器产生错误,无论配置中如何设定的错误处理策略, 插件将不试图连接下一个服务器去处理故障,用户必须处理这种错误。根据配置文件的设定, 插件可能发出一个 E_WARNING 级别的错误信息,类似 (mysqlnd_ms) Automatic failover is not permitted in the middle of a transaction。 并且错误可能被重写成 (mysqlnd_ms) No connection selected by the last filter。 这些错误也可能是由于失败的查询函数产生。

Example #28 没有自动错误处理的错误处理

<?php
/* 假设:配置了自动错误处理 */
$mysqli = new mysqli("myapp""username""password""database");

/* 设置插件内部状态 in_trx = 1 */
$mysqli->autocommit(false);

/* 假设:服务器错误 */
if (!($res $mysqli->query("SELECT 'Assume this query fails' AS _msg FROM DUAL"))) {
 
/* 处理事务错误,插件内部状态依然是 in_trx = 1 */
 
printf("[%d] %s"$mysqli->errno$mysqli->error);
 
/*
  如果使用 autocommit() 进行事务判断,那么必须调用 autocommit(true),
  否则插件将假设目前还在事务处理过程中,依然禁止负载均衡。
 */
 
$mysqli->autocommit(true);
 
/* 当然,你还可以开始一个新的事务处理 */
 
$mysqli->autocommit(false);
}
/* latin1 used from now on */
$mysqli->set_charset("latin1");
?>

如果再一个事务处理执行的过程中产生了服务器错误,那么插件将继续禁止 连接切换,直到事务完成。应该重新调用 API 命令,让插件检测到事务处理边界。 例如,你必须开启 autocommit 状态,这样插件就就能够继续继续负载均衡和 连接切换。同样的,如果你如果还想执行一个新的事务,那么可以再次禁用 autocommit 状态。

如果不处理错误,不使用 API 调用停止一个失败的事务,可能会引起类似下面的 报警信息Commands out of sync; you can't run this command now。 错误处理是非常必要的。

transient_error object

The setting has been introduced in 1.6.0.

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.

PECL/mysqlnd_ms can perform the retry loop on behalf of the application. By configuring transient_error 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.

Example #29 Retry loop for transient errors

{
    "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
       }
    }
}

Keyword Description Version
mysql_error_codes

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 1297 (HY000 (ER_GET_TEMPORARY_ERRMSG), Message: Got temporary error %d '%s' from %s). Before adding other codes but 1297 to the list, make sure your cluster supports a new attempt without impacting the state of your application.

Since 1.6.0.
max_retries

How often to retry an operation which fails with a transient error before forwarding the failure to the user.

Default: 1

Since 1.6.0.
usleep_retry

Milliseconds to sleep between transient error retries. The value is passed to the C function usleep(), hence the name.

Default: 100

Since 1.6.0.


安装/配置
PHP Manual