-
master
массив или объект
-
Списков основных серверов MySQL. Список может быть как типа
массив JSON
для указания списка анонимных серверов,
так и типа объект JSON
. Примеры смотрите
выше.
Обязательно должен быть определён хотя бы один основной сервер.
Если в конфигурационном файле будет отсутствовать эта директива, то
плагин вызовет ошибку уровня E_ERROR
.
Фатальная ошибка может выглядеть так
(mysqlnd_ms) Section [master] doesn't exist for host
[name_of_a_config_section] in %s on line %d
.
Сервер описывается с помощью
host
, port
,
socket
, db
,
user
, password
и
connect_flags
. Обязательно должно присутствовать
значение host
. Остальные настройки по желанию. Если
их не задавать, то плагин возьмёт их из параметров, указанных
пользователем в функции соединения с БД. Также смотрите:
пример использование имён секций.
Таблица параметров настройки сервера.
Плагин поддерживает только один основной сервер. Существует экспериментальная
настройка, позволяющая использовать несколько основных серверов. Подробности не
задокументированы. Настройка предназначена только для разработки.
-
slave
массив или объект
-
Список подчинённых серверов репликации MySQL. Синтаксис аналогичен
списку основных серверов. Смотрите
master
.
Плагин поддерживает работу с одним или более подчинёнными серверами.
Список подчинённых серверов должен присутствовать в обязательном
порядке. Плагин вызовет ошибку уровня E_ERROR
,
если в конфигурационном файле будет отсутствовать директива slave
.
Сообщение об ошибке будет примерно таким
(mysqlnd_ms) Section [slave] doesn't exist for host [%s] in %s on line %d
.
Обратите внимание, что допустимо указывать пустой список.
Ошибка была введена только для контроля, что секция
slave
в принципе присутствует.
Если у вас используются только основные сервера, то допустимо оставлять
этот список пустым.
При пустом списке, если будет предпринята попытка запустить запрос на
подчинённом сервере, плагин может выдать предупреждение типа
mysqlnd_ms) Couldn't find the appropriate slave connection.
0 slaves to choose from.
.
Также возможно у другое предупреждение, такое как
(mysqlnd_ms) No connection selected by the last filter
.
-
global_transaction_id_injection
массив или объект
-
Настройка глобального идентификатора транзакции относится как
к встроенному серверному механизму глобальных идентификаторов
транзакций, так и к эмуляции на стороне клиента.
-
fabric
объект
-
Настройки, относящиеся к MySQL Fabric. Если плагин используется вместе с
MySQL Fabric, то файл конфигурации плагина не содержит секций со списками
серверов. Вместо этого плагин запрашивает эти списки у MySQL Fabric.
Минимальная конфигурация для использования плагина с MySQL Fabric должна
содержать список из одного или более хостов MySQL Fabric, к которым он будет
обращаться. Если задано более одного хоста, то плагин будет использовать
стратегию roundrobin для выбора одного из них. Другие стратегии пока недоступны.
Пример #11 Минимальная конфигурация плагина для использования с MySQL Fabric
{
"myapp": {
"fabric": {
"hosts": [
{
"host" : "127.0.0.1",
"port" : 8080
}
]
}
}
}
Каждый хост MySQL Fabric описывается объектом JSON со следующими параметрами.
Плагин использует потоки PHP для общения с MySQL Fabric через
XML RPC поверх HTTP. По умолчанию дл сетевого взаимодействия
не заданы какие0либо тайм-ауты. Таким образом, по умолчанию
используются тайм-ауты потоков PHP, которые не контролируются плагином.
Можно задать собственные тайм-ауты. Настройка тайм-аутов в
конфигурационном файле плагина будет иметь тот же эффект, что
и настройка тайм-аутов для HTTP-соединения через потоки PHP.
Тайм-аут задаётся в секундах. Допустимые значения лежат в диапазоне
от 0 до 65535. Эта настройка доступна с версии 1.6.
Пример #12 Таймаут соединения с Fabric
{
"myapp": {
"fabric": {
"hosts": [
{
"host" : "127.0.0.1",
"port" : 8080
}
],
"timeout": 2
}
}
}
Закрепление транзакции за сервером (Transaction stickiness)
и логика MySQL Fabric могут противоречить друг другу. Закрепление транзакции
запрещает переключение между серверами на протяжении выполнения транзакции.
При использовании Fabric и шардинга, пользователь ошибочно может запустить
локальную транзакцию на одном сервере и затем попытаться переключиться на
другой, используя функции mysqlnd_ms_fabric_select_shard() или
mysqlnd_ms_fabric_select_global(). В этом случае плагин не
отвергнет запрос на переключение посреди транзакции, а позволит пользователю
переключиться независимо от того, включено ли закрепление. Это будет исключительно
ошибкой пользователя, написавшего такой код.
Если закрепление транзакции включено и вы хотите получать предупреждения,
используя функции mysqlnd_ms_fabric_select_shard() или
mysqlnd_ms_fabric_select_global(), то установите
логический флаг trx_warn_server_list_changes
.
Пример #13 Предупреждение о нарушении границ транзакции
{
"myapp": {
"fabric": {
"hosts": [
{
"host" : "127.0.0.1",
"port" : 8080
}
],
"trx_warn_serverlist_changes": 1
},
"trx_stickiness": "on"
}
}
<?php
$link = new mysqli("myapp", "root", "", "test");
/*
Этот запрос скорее всего завершится с ошибкой.
Но в любом случае мы перейдём в режим
необходимый для демонстрации.
*/
@mysqlnd_ms_fabric_select_global($link, 1);
$link->begin_transaction();
@$link->query("DROP TABLE IF EXISTS test");
/*
Переключение серверов/шардов является ошибкой
при открытии локальной транзакции!
*/
mysqlnd_ms_select_global($link, 1);
?>
Результат выполнения данного примера:
PHP Warning: mysqlnd_ms_fabric_select_global(): (mysqlnd_ms) Fabric server exchange in the middle of a transaction in %s on line %d
Обратите внимание, что эта особенность экспериментальная и в будущем синтаксис и семантика могут поменяться.
-
filters
объект
-
Список фильтров. Фильтры нужны для фильтрации списка серверов доступных
для выполнения заданного запроса. Фильтры можно выстраивать цепочкой.
Фильтры random
и roundrobin
заменяют директиву
pick[]
,
ранее использовавшуюся для политик балансировки.
Фильтр user
заменяет функцию
mysqlnd_ms_set_user_pick_server().
Фильтры могут принимать параметры для уточнения своих действий.
Если политики балансировки нагрузки не заданы, то плагин будет использовать
random_once
. Политика random_once
берет случайный подчинённый сервер в момент запуска первого запроса на чтение.
Для любых запросов, производящих только чтение, будет использоваться
подчинённый сервер до момента завершения обработки PHP-скрипта.
В случае, если в этой секции не заданы random
или
roundrobin
, то балансировка нагрузки не будет использоваться.
Если цепочка фильтров настроена таким образом, что фильтр возвращающий не более
одного сервера является входом фильтра, которому необходимо получить более одного
сервера, то плагин может выдать предупреждение при создании подключения.
Предупреждение будет примерно такое: (mysqlnd_ms) Error while creating
filter '%s' . Non-multi filter '%s' already created.
Более того, для
соединения может быть установлена ошибка с номером 2000
,
SQL-состоянием HY000
и сообщением, аналогичным предупреждению.
Пример #14 Некорректная последовательность фильтров
{
"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
-
Фильтр:
random
объект
-
Фильтр random
работает как политики балансировки нагрузки,
как random и random once, устанавливаемые ранее с помощью
pick[]
.
Политика random берет случайный сервер всякий раз, когда надо выполнить
запрос на чтение. Политика random once выбирает один подчинённый сервер
и использует его для запросов на чтение на протяжении выполнения PHP-скрипта.
Если политики балансировки нагрузки не определены, то, по умолчанию,
будет использоваться random once.
Если фильтру random
не передать ни одного аргумента, то
будет выбрана политика балансировки random.
Пример #15 Стратегия random с помощью фильтра random
{
"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
.
Если параметр sticky
будет иметь значение
1
(типа строка), то фильтр будет определять стратегию
random once.
Пример #16 Стратегия random once с помощью фильтра random
{
"filters": {
"random": {
"sticky": "1"
}
}
}
Оба фильтра, random
и roundrobin
,
поддерживают установку приоритета, веса сервера, начиная с
PECL/mysqlnd_ms 1.4.0. Если в фильтре определён аргумент weight
,
он должен определять вес для всех серверов. При этом список подчинённых
серверов в секции slave
должен быть не анонимным, а именованным,
как и в секции master
. Имена должны использоваться
для определения весов конкретных серверов с помощью weight
.
Пример #17 Ошибка ссылки
[E_RECOVERABLE_ERROR] mysqli_real_connect(): (mysqlnd_ms) Unknown server 'slave3' in 'random' filter configuration. Stopping in %s on line %d
Использование ошибочного имени в секции weight
может привести к
ошибке, показанной выше.
Если секция weight
отсутствует, то вес всех серверов
считается за единицу.
Пример #18 Задание весов
для балансировки нагрузки
{
"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
}
}
}
}
}
В среднем, сервер с весом два будет выбираться в два раза чаще, чем сервер
с весом один. Различные веса могут отражать производительность разных серверов,
для задания предпочтения серверам с меньшими сетевыми задержками, или для
настройки резервного сервера, который будет использоваться в случае отказа основного.
В последнем случае имеет смысл задать резервному серверу очень маленький вес
относительно остальных. К примеру, в приведённой выше конфигурации,
сервер slave3
будет принимать только 8 процентов
всех запросов, и если slave1
и slave2
работают, он будет выбираться крайне редко. В случае отказа slave1
и slave2
, использование slave3
возрастёт.
Пожалуйста, перед тем как начать использовать веса таким образом,
почитайте об обеспечении отказоустойчивости.
Корректные значения весов лежат в диапазоне от 1 до 65535.
Неизвестные аргументы будут тихо проигнорированы.
The filter expects one or more servers as input. Outputs one server.
A filter sequence such as
random
, roundrobin
may
cause a warning and an error message to be set on the connection
handle when executing a statement.
Список аргументов фильтра.
-
Фильтр:
roundrobin
объект
-
При использовании фильтра roundrobin
, плагин
последовательно перебирает список подчинённых серверов для выбора
сервера, на котором будет выполнен запрос. Если плагин доходит до
конца списка, то перебор начинается с его начала.
Пример #19 roundrobin
filter
{
"myapp": {
"master": {
"master_0": {
"host": "localhost"
}
},
"slave": {
"slave_0": {
"host": "192.168.78.136",
"port": "3306"
}
},
"filters": [
"roundrobin"
]
}
}
Ожидает один или более серверов на вход. Возвращает один сервер.
Последовательность фильтров, такая как
roundrobin
, random
может
установить ошибку для обработчика подключения во время
выполнения запроса.
Список аргументов фильтра.
-
Фильтр:
user
объект
-
Фильтр user
заменяет функцию
mysqlnd_ms_set_user_pick_server(),
которая была удалена в версии 1.1.0-beta. Фильтр устанавливает
функцию обратного вызова, которая будет использоваться для
выбора серверов и разделения операций записи/чтения.
Встроенный в плагин механизм разделения чтения/записи может быть
переопределён двумя способами. Самый простой способ - добавить в начало
строки запроса SQL-хинт MYSQLND_MS_MASTER_SWITCH
,
MYSQLND_MS_SLAVE_SWITCH
или
MYSQLND_MS_LAST_USED_SWITCH
. Использованием SQL-хинтов
можно контролировать, например, будет ли запрос выполняться на основном сервере
или на одном из подчинённых. С помощью SQL-хинтов невозможно однозначно
указать конкретный подчинённый сервер для выполнения запроса.
Полный контроль над процедурой выбора сервера даёт использование функции
обратного вызова. Использование такой функции рекомендовано продвинутым
пользователям, так как эта функция должна покрывать все возможные ситуации,
в ином случае обрабатываемых плагином.
Плагин вызывает функцию для выбора сервера из списков подчинённых и основных серверов.
Функция должна проанализировать запрос и вернуть URI наиболее подходящего
сервера для его выполнения.
Если разрешены ленивые соединения и функция выберет подчинённый сервер, к
которому ещё не было установлено соединение и новое соединение завершится
с ошибкой, плагин вернёт ошибку до того, как с произойдёт следующая операция
с этим соединением, например запуск запроса. Это накладывает на разработчика
задачу обработки таких ошибок. К примеру, приложение может перезапустить
запрос в надежде, что в этот раз функция обратного вызова вернёт другой сервер.
Функция обратного вызова должна убедиться, что не вернёт сервер, соединение с
которым ранее завершилось ошибкой, или же изначально проверять доступность сервера,
перед тем как вернуть его плагину, чтобы не свалиться в бесконечный цикл.
Пример #20 Установка callback-функции
{
"myapp": {
"master": {
"master_0": {
"host": "localhost"
}
},
"slave": {
"slave_0": {
"host": "192.168.78.136",
"port": "3306"
}
},
"filters": {
"user": {
"callback": "pick_server"
}
}
}
}
Функция обратного вызова должны вернуть хост для выполнения запроса.
URI хоста должно браться из списков подчинённых и основных серверов,
переданных функции. Если функция вернёт значение, отсутствующее в этих
списках, то плагин вызовет ошибку уровня E_RECOVERABLE_ERROR
.
Ошибка будет примерно такая
(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
.
Если приложение перехватит и проигнорирует эту ошибку, то для соединения
будет ошибка, например такая:
(mysqlnd_ms) No connection selected by the last filter
with
the error code 2000
and the sqlstate HY000
.
Также может быть показано предупреждение.
Задание в качестве функции обратного вызова несуществующей функции приведёт
к ошибке уровня E_RECOVERABLE_ERROR
при попытке её вызвать.
Сообщение об ошибке будет примерно такое:
(mysqlnd_ms) Specified callback (pick_server) is
not a valid callback
. Если приложение перехватит и проигнорирует эту
ошибку, то для соединения будет ошибка, например такая:
(mysqlnd_ms) Specified callback (pick_server) is
not a valid callback
with the error code 2000
and the sqlstate HY000
.
Также может быть показано предупреждение.
Следующие параметры плагин передаёт функции обратного вызова.
Пример #21 Использование функции обратного вызова
{
"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);
/* по умолчанию: откат в встроеной в плагин логике */
$ret = NULL;
printf("Пользователь соединён с '%s'...\n", $connected);
printf("... решаем где выполнять '%s'\n", $query);
$where = mysqlnd_ms_query_is_select($query);
switch ($where)
{
case MYSQLND_MS_QUERY_USE_MASTER:
printf("... используем основной сервер\n");
$ret = $masters[0];
break;
case MYSQLND_MS_QUERY_USE_SLAVE:
/* SELECT или SQL-хинт для использования подчинённого */
if (stristr($query, "FROM table_on_slave_a_only"))
{
/* таблица, которая находится только на первом подчинённом сервере */
printf("... доступ к таблице возможен только на подчинённом сервере A\n");
$ret = $slaves[0];
}
else
{
/* round robin */
printf("... выполняем запрос на чтение на подчинённом сервере\n");
$ret = $slaves[$slave_idx++ % $num_slaves];
}
break;
case MYSQLND_MS_QUERY_LAST_USED:
printf("... испольщзуем тот же сервер, что и для предыдущего запроса\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();
?>
Результат выполнения данного примера:
Пользователь соединён с 'myapp'...
... решаем где выполнять 'SELECT 1 FROM DUAL'
... выполняем запрос на чтение на подчинённом сервере
... ret = 'tcp://192.168.2.27:3306'
Пользователь соединён с 'myapp'...
... решаем где выполнять 'SELECT 2 FROM DUAL'
... some read-only query for a slave
... ret = 'tcp://192.168.78.136:3306'
Пользователь соединён с 'myapp'...
... решаем где выполнять 'SELECT * FROM table_on_slave_a_only'
... доступ к таблице возможен только на подчинённом сервере A
... ret = 'tcp://192.168.2.27:3306'
-
Фильтр:
user_multi
объект
-
Фильтр user_multi
отличается от user
только в одном аспекте. Весь остальной синтаксис аналогичен.
Фильтр user
может выбрать и вернуть только один
сервер. Цепочка фильтров на этом обычно заканчивается, так как
она должна сократить список серверов ровно до одного. Соответственно,
после user
остаётся ровно один сервер, на котором и запускается запрос.
Фильтр user_multi
, напротив, возвращает список подчинённых
и основных серверов, который передаётся следующему фильтру в цепочке.
Такой фильтр обычно ставится в начале цепочки фильтров. Другой фильтр,
возвращающий более одного сервера - это quality_of_service
.
Функция обратного вызова, заданная в user_multi
должна
вернуть массив с двумя элементами. В первом список выбранных основных серверов,
а во втором - подчинённых серверов. Список должен содержать ключи подчинённых
и основных серверов, присутствующие в переданных ему ранее списках. Следующий
пример демонстрирует получения случайного списка подчинённых и основных серверов.
Пример #22 Получение случайных подчинённых и основных серверов
<?php
function pick_server($connected, $query, $masters, $slaves, $last_used_connection, $in_transaction)
{
$picked_masters = array()
foreach ($masters as $key => $value) {
if (mt_rand(0, 2) > 1)
$picked_masters[] = $key;
}
$picked_slaves = array()
foreach ($slaves as $key => $value) {
if (mt_rand(0, 2) > 1)
$picked_slaves[] = $key;
}
return array($picked_masters, $picked_slaves);
}
?>
В случае, если функция не вернёт списка серверов, плагин выдаст ошибку
уровня E_RECOVERABLE
. Ошибка будет примерно такая:
(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
.
В случае, если списки будут не пустыми, но будут содержать некорректные
ключи серверов, то будет выдана ошибка уровня E_RECOVERABLE
с примерно таким текстом: (mysqlnd_ms) User multi filter callback
has returned an invalid list of servers to use.
Server id is negative in %s on line %d
, или похожая.
Будет ли выдаваться ошибка в случае возврата пустых списков подчинённых или
основных серверов, зависит от настроек. Если возвращён пустой список
основных серверов для запроса на запись, то плагин, скорее всего, вызовет
ошибку типа (mysqlnd_ms) Couldn't find the appropriate
master connection. 0 masters to choose from. Something is wrong in %s on line %d
.
Обычно именно такая ошибка уровня E_ERROR
и произойдёт.
В случае операции чтения и пустого списка подчинённых серверов, поведение
будет определяться конфигурацией механизма защиты от отказов. Если допустим
откат к основному серверу, то ошибок не будет. Если же откат к основному серверу запрещён, то
будет ошибка типа (mysqlnd_ms) Couldn't find the appropriate
slave connection. 0 slaves to choose from. Something is wrong in %s on line %d
.
-
Фильтр:
node_groups
объект
-
Фильтр node_groups
позволяет группировать узлы кластера
и отправлять запрос на эти группы, например для поддержки партиционирования.
Партиционирование данных может потребоваться в случае ручного шардирования,
в кластерах типа primary copy с несколькими основными серверами или для
обхода узких мест в кластерах типа update everywhere, не имеющих
собственных механизмов партиционирования. Соответственно, после этого фильтра
необходимо применить другой фильтр, который выберет один сервер из возвращённого
списка.
-
Фильтр:
quality_of_service
объект
-
Фильтр quality_of_service
идентифицирует узлы кластера
способные предоставить необходимый уровень сервиса. Это фильтр, который
может вернуть ноль, один или несколько серверов. За ним обязательно
должен следовать фильтр, гарантированно возвращающий ровно один сервер.
Фильтр quality_of_service
появился в версии 1.2.0-alpha.
В версиях 1.2, этот фильтр фокусируется на таком аспекте качества, как
согласованность данных. Разные типы кластеров предоставляют разный уровень
согласованности данных. К примеру, асинхронная репликация MySQL предоставляет
не гарантированную согласованность. Подчинённый сервер может не отдать запрашиваемые
данные, либо данные на нем будут устаревшие, поскольку они на него ещё
не среплицировались. Обычно это допустимо. В других случаях, для корректной
работы приложения, требуется более высокий уровень согласованности. Для
таких случаев quality_of_service
может отбросить сервера,
которые этого не гарантируют.
Фильтр quality_of_service
может быть удалён или
создан во время исполнения.Успешный вызов mysqlnd_ms_set_qos()
удаляет все существующие qos
фильтры из списка фильтров и
добавляет новый в самое начало. Все настройки, какие можно сделать с помощью
mysqlnd_ms_set_qos(), также можно сделать и в конфигурационном
файле. Однако использование функции, безусловно, является наиболее распространённым
вариантом использования. Вместо установки уровней session_consistency и
strong_consistency, рекомендуется просто не указывать подчинённые сервера, а
только основные сервера. Использование пустого списка подчинённых серверов
короче и более читаемо. Единственный уровень сервиса, который имеет смысл
указывать в конфигурационном файле, это комбинация eventual_consistency
и контроль максимальной задержки репликации подчинённого сервера.
-
failover
До версии (включая) 1.3.x: строка.
Начиная с 1.4.0: объект.
-
Политика обработки отказов. Поддерживаемые политики:
disabled
(по умолчанию), master
,
loop_before_master
(Начиная с 1.4.0).
Если политики обработки отказов не настроены, то по умолчанию
никакой автоматической обработки отказов производиться не будет
(failover=disabled
). Всякий раз, когда
плагин не может установить соединение с сервером, он выдаёт
предупреждение и устанавливает для этого соединения код и сообщение
об ошибке. После этого он возвращает ошибку приложению на обработку и,
например, перепосылает последний запрос в надежде, что будет выбран
другой сервер.
Обратите внимание, что логика обработки отказов по умолчанию применяется
только при создании нового соединения. Если соединение было открыто, то
никаких попыток переподключения, в случае ошибки, производиться не будет.
Если, к примеру, сервер, с которым установлено соединение, отключится, то,
при попытке выполнить на нем запрос, никаких попыток восстановления
предпринято не будет. Вместо этого вернётся ошибка.
Если используется failover=master
, то плагин будет
неявно переключаться на основной сервер, если он доступен. Пожалуйста
внимательно почитайте документацию, где описаны все риски и подводные
камни использования failover=master
.
Пример #25 Откат к основному серверу в случае невозможности соединиться с
подчинённым сервером (PECL/mysqlnd_ms < 1.4.0)
{
"myapp": {
"master": {
"master_0": {
"host": "localhost"
}
},
"slave": {
"slave_0": {
"host": "192.168.78.136",
"port": "3306"
}
},
"failover": "master"
}
}
Начиная с PECL/mysqlnd_ms 1.4.0 ключ конфигурации failover должен содержать объект.
Пример #26 Новый синтаксис, начиная с версии 1.4.0
{
"myapp": {
"master": {
"master_0": {
"host": "localhost"
}
},
"slave": {
"slave_0": {
"host": "192.168.78.136",
"port": "3306"
}
},
"failover": {"strategy": "master" }
}
}
Установка failover
любым значением, отличным от
disabled
, master
или
loop_before_master
, не вызовет ошибок или
предупреждений.
-
lazy_connections
логическое
-
Контролирует использование ленивых подключений. Ленивые подключения -
это такие подключения, которые не устанавливаются, пока клиент не отправит
первый запрос. Включены по умолчанию.
Ленивые подключения крайне рекомендованы к использованию, поскольку
позволяют сильно сократить количество открытых соединений.
Если вы запретите ленивые соединения, то, например, настроив кластер из
одного основного сервера и двух подчинённых серверов, вы получите три одновременно
открытых соединения при первом же подключении к базе, хотя в вашем скрипте
используется только подключение к основному серверу.
Ленивые подключения не представляют опасности, если вы часто меняете
состояние подключения. Плагин не отправляет все изменения состояния во
все соединения из пула соединений. Небольшое количество изменений посылаются
только в открытые соединения. Ленивые соединения, открытые позже, не будут
затронуты. Только небольшое количество настроек будут "запоминаться"
и применяться к новым открытым ленивым соединениям.
Пример #27 Запрещение ленивых соединений
{
"myapp": {
"master": {
"master_0": {
"host": "localhost"
}
},
"slave": {
"slave_0": {
"host": "192.168.78.136",
"port": "3306"
}
},
"lazy_connections": 0
}
}
Внимательно изучите документацию по server_charset
,
для того, чтобы избежать проблем с экранированием строк и с серверами,
использующими другие настройки локали по умолчанию.
-
server_charset
строка
-
Эта настройка появилась в версии 1.4.0. Крайне рекомендуется её использовать
при включённых ленивых подключениях.
Настройка server_charset
служит двум целям. Она используется
как кодировка по умолчанию при экранировании строк до установления
соединения и помогает избежать подводных камней в гетерогенном
окружении, когда разные сервера используют разные кодировки по умолчанию.
При выполнении экранирования строк учитывается кодировка соединений.
Выключение экранирования строк невозможно до того, как соединение
будет открыто, и не станет известна кодировка соединения. Использование
ленивых подключений задерживает реальное открытие соединение до
момента отправки первого запроса.
Приложения использующие ленивые подключения могут попытаться экранировать
строки перед отправкой запроса. Фактически это обычное дело, когда
строка запроса нуждается в экранировании. Однако, так как ленивое
соединение ещё не открыто, то такое экранирование завершится с ошибкой.
Плагин выдаст ошибку уровня 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
больше не имеет смысла.
Пример #28 Экранирование строк для ленивых подключений
{
"myapp": {
"master": {
"master_0": {
"host": "localhost"
}
},
"slave": {
"slave_0": {
"host": "192.168.78.136",
"port": "3306"
}
},
"lazy_connections": 1,
"server_charset" : "utf8mb4"
}
}
<?php
$mysqli = new mysqli("myapp", "username", "password", "database");
$mysqli->real_escape("это будет экранироваться с помощью настройки server_charset - utf8mb4");
$mysqli->set_charset("latin1");
$mysqli->real_escape("это будет экранироваться с помощью latin1");
/* server_charset implicitly set - utf8mb4 connection */
$mysqli->query("SELECT 'это соединение будет использовать server_charset' AS _msg FROM DUAL");
/* теперь используется latin1*/
$mysqli->set_charset("latin1");
?>
-
master_on_write
логическое значение
-
Если установлено, то плагин начнёт использовать основной сервер
только после того, как на нем будет выполнен первый запрос.
Приложение также сможет использовать подчинённые сервера,
используя SQL-хинты.
Эта настройка может помочь победить задержку репликации. Если, например,
будет запущен запрос INSERT
, то, после него, все
последующие запросы плагин будет отправлять на основной сервер,
включая запросы типа SELECT
. Это может
помочь в случае, когда подчинённые сервера не успеют среплицировать
результаты запроса INSERT
.
Пример #29 Обеспечение консистентного чтения
{
"myapp": {
"master": {
"master_0": {
"host": "localhost"
}
},
"slave": {
"slave_0": {
"host": "192.168.78.136",
"port": "3306"
}
},
"master_on_write": 1
}
}
Обратите внимание, что фильтр quality_of_service
появился в версии 1.2.0-alpha. Он даёт возможность более тонко
управлять уровнем сервиса,
который вам нужен.
Все настройки привязки транзакции
к серверу, включая trx_stickiness=on
,
перебиваются master_on_write=1
.
-
trx_stickiness
строка
-
Политики привязки транзакции к серверу. Поддерживаемые политики:
disabled
(по умолчанию), master
.
Эта настройка требует версии PHP 5.4.0 или выше. Если использовать с более ранними
версиями PHP, то плагин выдаст предупреждение вида
(mysqlnd_ms) trx_stickiness strategy is not supported before PHP 5.3.99
.
Если политика не определена, либо установлена как
trx_stickiness=disabled
, то плагин может
балансировать нагрузку и переключаться между серверами в течение
транзакции. Плагин не транзакционно-безопасен. Для предотвращения
переключения соединения в ходе транзакции можно использовать SQL-хинты.
Начиная с PHP 5.4.0, библиотека mysqlnd позволяет отслеживать изменение
состояния режима autocommit
, путём перехвата
вызовов функции set_autocommit()
.
Если задано set_stickiness=master
и
autocommit
отключён расширением PHP MySQL путём
вызова mysqlnd
внутренней функции
set_autocommit()
, плагин понимает, что начата транзакция,
и все последующие запросы будут выполняться на основном сервере,
пока не будет включён autocommit
. Соответственно
можно не использовать SQL-хинты.
Например, для вызова внутренней функции библиотеки mysqlnd
set_autocommit()
, можно использовать
mysqli_autocommit().
Следует учесть, что даже с установкой trx_stickiness=master
,
плагин не сможет перехватывать изменение режима autocommit
,
вызванное SQL-запросами, такими как SET AUTOCOMMIT=0
или BEGIN
.
Начиная с PHP 5.5.0, библиотека mysqlnd содержит дополнительные вызовы C API для
контроля транзакций. Уровень контроля совпадает с заданным SQL-запросом.
mysqli
API был изменён для использования этих вызовов.
Начиная с версии 1.5.0, PECL/mysqlnd_ms может отслеживать не только
mysqli_autocommit(), но также mysqli_begin(),
mysqli_commit() и mysqli_rollback(). Это
позволяет отслеживать границы транзакций и останавливать для них балансировку.
Пример #30 Использование основного сервера для запуска транзакции
{
"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
.
Пример #31 Нет автоматического переключения при сбое, обработка ошибок
<?php
/* предположение: настроена автоматическая обработка ошибок */
$mysqli = new mysqli("myapp", "username", "password", "database");
/* переключаем внутреннее состояние плагина в in_trx = 1 */
$mysqli->autocommit(false);
/* предположение: сервер перестал отвечать */
if (!($res = $mysqli->query("SELECT 'Этот запрос не выполнился' AS _msg FROM DUAL"))) {
/* обрабатываем ошибку транзакции, внутреннее состояние плагина всё ещё in_trx = 1 */
printf("[%d] %s", $mysqli->errno, $mysqli->error);
/*
Если используется механизм определения транзакции на базе autocommit(),
то НЕОБХОДИМО вызвать autocommit(true). В противном случае плагин
будет думать, что продолжается текущая транзакция и переключиться на
другой сервер не получится.
*/
$mysqli->autocommit(true);
/* Ну и теперь вы хотите начать новую транзакцию */
$mysqli->autocommit(false);
}
/* с этого момента используем latin1 */
$mysqli->set_charset("latin1");
?>
Если сервер отказывает в середине транзакции, плагин будет
игнорировать все попытки переключиться на другой сервер, пока
транзакция не будет завершена. Напомним, что плагин контролирует
вызовы API для обнаружения границ транзакций. Таким образом,
вам нужно, например, включить режим автокоммита для завершения
текущей транзакции для того, чтобы плагин включит балансировку
нагрузки. Собственно вы можете сразу же начать новую транзакцию,
снова отключив режим автоматического подтверждения.
Если вы не будете обрабатывать ошибки и завершать некорректную транзакцию,
то дальнейшие вызовы API могут привести к ошибкам, таким как
Commands out of sync; you can't run this command now
.
Запомните - это очень важно, обрабатывать все ошибки.
-
transient_error
объект
-
Настройка появилась в версии 1.6.0.
Узел кластера базы данных может вернуть ошибку, вызванную кратковременным сбоем.
Клиент может повторить запрос на том же узле, переключиться на другой, или вообще
отменить запрос. Для подобных ошибок вполне безопасно использовать для
повторного запроса тот же сервер.
PECL/mysqlnd_ms
может выполнить повтор запроса
от имени приложения.
С помощью transient_error
можно настроить плагин
для повтора запроса, завершившегося с конкретными ошибками определённое
количество раз с паузой между попытками. Если в процессе повтора ошибка
пропадёт, то приложение этого даже не заметит. Если все попытки
завершились неудачей, то приложению будет возвращена ошибка.
Пример #32 Цикл повторов исправляемых ошибок
{
"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
}
}
}
-
xa
объект
-
Настройка появилась в версии 1.6.0.
Замечание:
Экспериментальный функционал
Эта функциональность в данный момент находится в разработке, так что
при её использовании могут возникать проблемы и ограничения.
Не используйте в промышленном окружении.
-
state_store
-
-
record_participant_credentials
-
Сохранять ли имя пользователя и пароль участника глобальной транзакции
в таблице участников. Если отключено, сборщик мусора, при подключении
к серверам будет использовать имя и пароль по умолчанию. Если вы
не используете разных пользователей для разных серверов MySQL, то
спокойно можно использовать значения по умолчанию и не сохранять
эту информацию в хранилище состояния.
Обратите внимание, что при использовании этого функционала, имя и пароль
пользователя в хранилище состояния MySQL будут храниться в текстовом виде.
Вся ответственность за обеспечение безопасности этой информации лежит на вас.
По умолчанию: false
-
participant_localhost_ip
-
Во время сбора мусора XA, плагин может найти сервер участник, для
которого был был записан хост localhost
. Если
сбор мусора запустился на другом хосте, но хост сделал запись
участника в хранилище состояния, то localhost
будет разрешаться как другой хост. Поэтому при записи имени
хоста участника в хранилище состояния следует использовать
не localhost
, а актуальный IP-адрес
localhost
.
Установка participant_localhost_ip
должна использоваться
только если нельзя избежать использования localhost
.
Если смотреть только с точки зрения сбора мусора, желательно не
настраивать соединения с сокетом, а использовать IP-адрес и порт.
-
mysql
-
В качестве хранилища состояния доступно только хранилище состояния MySQL.
-
global_trx_table
-
Имя таблицы MySQL, используемой для хранения состояния текущей или
оборванной глобальной транзакции. Для создания таблицы используйте
приведённый ниже SQL-запрос. Не забудьте заменить имя таблицы на то,
которое будете использовать в настройках.
По умолчанию: mysqlnd_ms_xa_trx
Пример #33 SQL-запрос для создания таблицы хранилища состояния транзакции
CREATE TABLE mysqlnd_ms_xa_trx (
store_trx_id int(11) NOT NULL AUTO_INCREMENT,
gtrid int(11) NOT NULL,
format_id int(10) unsigned NOT NULL DEFAULT '1',
state enum('XA_NON_EXISTING','XA_ACTIVE','XA_IDLE','XA_PREPARED','XA_COMMIT','XA_ROLLBACK') NOT NULL DEFAULT 'XA_NON_EXISTING',
intend enum('XA_NON_EXISTING','XA_ACTIVE','XA_IDLE','XA_PREPARED','XA_COMMIT','XA_ROLLBACK') DEFAULT 'XA_NON_EXISTING',
finished enum('NO','SUCCESS','FAILURE') NOT NULL DEFAULT 'NO',
modified timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
started datetime DEFAULT NULL,
timeout datetime DEFAULT NULL,
PRIMARY KEY (store_trx_id),
KEY idx_xa_id (gtrid,format_id,finished),
KEY idx_state (state)
) ENGINE=InnoDB
-
participant_table
-
Имя таблицы MySQL, используемой для хранения информации об участниках
текущей или оборванной глобальной транзакции. Для создания таблицы используйте
приведённый ниже SQL-запрос. Не забудьте заменить имя таблицы на то,
которое будете использовать в настройках.
Хранение имени и пароля пользователя контролируется настройкой
record_participant_credentials
По умолчанию: mysqlnd_ms_xa_participants
Пример #34 SQL-запрос для создания таблицы хранилища участников транзакции
CREATE TABLE mysqlnd_ms_xa_participants (
fk_store_trx_id int(11) NOT NULL,
bqual varbinary(64) NOT NULL DEFAULT '',
participant_id int(10) unsigned NOT NULL AUTO_INCREMENT,
server_uuid varchar(127) DEFAULT NULL,
scheme varchar(1024) NOT NULL,
host varchar(127) DEFAULT NULL,
port smallint(5) unsigned DEFAULT NULL,
socket varchar(127) DEFAULT NULL,
user varchar(127) DEFAULT NULL,
password varchar(127) DEFAULT NULL,
state enum('XA_NON_EXISTING','XA_ACTIVE','XA_IDLE','XA_PREPARED','XA_COMMIT','XA_ROLLBACK')
NOT NULL DEFAULT 'XA_NON_EXISTING',
health enum('OK','GC_DONE','CLIENT ERROR','SERVER ERROR') NOT NULL DEFAULT 'OK',
connection_id int(10) unsigned DEFAULT NULL,
client_errno smallint(5) unsigned DEFAULT NULL,
client_error varchar(1024) DEFAULT NULL,
modified timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (participant_id),
KEY idx_xa_bqual (bqual),
KEY idx_store_trx (fk_store_trx_id),
CONSTRAINT mysqlnd_ms_xa_participants_ibfk_1 FOREIGN KEY (fk_store_trx_id)
REFERENCES mysqlnd_ms_xa_trx (store_trx_id) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB
-
garbage_collection_table
-
Имя таблицы MySQL используемой для отслеживания и синхронизации запуска
сбора мусора. Для создания таблицы используйте
приведённый ниже SQL-запрос. Не забудьте заменить имя таблицы на то,
которое будете использовать в настройках.
По умолчанию: mysqlnd_ms_xa_gc
Пример #35 SQL-запрос для создания таблицы хранилища информации о сборе мусора
CREATE TABLE mysqlnd_ms_xa_gc (
gc_id int(10) unsigned NOT NULL AUTO_INCREMENT,
gtrid int(11) NOT NULL,
format_id int(10) unsigned NOT NULL DEFAULT '1',
fk_store_trx_id int(11) DEFAULT NULL,
modified timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
attempts smallint(5) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (gc_id),
KEY idx_store_trx (gtrid,format_id,fk_store_trx_id)
) ENGINE=InnoDB
-
host
-
Имя хоста сервера MySQL.
-
user
-
Имя пользователя.
-
password
-
Пароль.
-
db
-
База данных, в которой располагаются таблицы сборщика мусора.
Обратите внимание, что таблицы сборщика мусора необходимо
создать до использования плагина. Таблицы не создаются
во время исполнения и сборщик мусора не сможет без них работать.
-
port
-
Порт сервера MySQL.
-
socket
-
Доменный сокет unix для сервера MySQL. Обратите внимание,
что если вы используете несколько серверов PHP, то любой
из них может попытаться выполнить сборку мусора и должен
иметь доступ к хранилищу состояния. В этом случае вы можете
настроить IP-адрес и порт для сервера MySQL, хранящего
состояние, чтобы все серверы PHP могли к нему обратиться.
-
rollback_on_close
-
Производить ли автоматический откат открытой глобальной транзакции
при закрытии соединения. Если включено, то поведение будет аналогично
поведению с локальными транзакциями. Как только клиент потерял
соединение, сервер откатит все открытые и не завершённые транзакции.
По умолчанию: true
- garbage_collection
-
-
max_retries
-
Максимальное количество попыток запуска сборки мусора.
Допустимы значения в диапазоне от 0
до 100
.
0
означает отсутствие ограничений, только если
ограничения не настроены в хранилище состояния. Ограничения
хранилища состояния, предположительно, значительно выше, чем 100
.
Доступно с версии 1.6.0.
Обратите внимание, что крайне важно завершить ошибочные
XA-транзакции за разумное время, чтобы сервера участники
могли высвободить занятые ими ресурсы. Встроенный сборщик мусора
не ожидает, что будет завершаться с ошибкой длительное время, пока
сбойные сервера приходят в себя. Все ещё возможны ситуации, когда
может потребоваться вмешательство человека для решения проблем
сборщика мусора. В этом случае сперва надо убедиться, что
ситуацию нельзя разрешить принудительным запуском
mysqlnd_ms_xa_gc(), а только потом принимать
более серьёзные меры.
По умолчанию: 5
-
probability
-
Вероятность сбора мусора.
Допустимы значения от 0
до 1000
.
Установка 0
запрещает автоматический фоновый
сбор мусора. Помните, что даже установив 0
, вы сможете
запускать сборку мусора самостоятельно с помощью
mysqlnd_ms_gc().
Доступно с версии 1.6.0.
Автоматический сбор мусора для зависшей XA-транзакции возможен только
если настроено хранение состояния. Хранилище состояния отвечает за
отслеживание XA-транзакции. Основываясь на записях в хранилище состояния
можно определить участников транзакции и выполнить на них откат.
Сбор мусора запускается в качестве в процессе завершения обработки
веб-запроса PHP, как только ваш скрипт завершил работу. Надо ли
запускать сборщик мусора, определяется вычислением случайного
числа между 0
и 1000
. Если число выше
или равно настроенной вероятности, то сборка будет запущена.
По умолчанию: 5
-
max_transactions_per_run
-
Максимальное количество XA-транзакций, которые будут обработаны за
один запуск сборки мусора.
Допустимы значения от 1
до 32768
.
Доступно с версии 1.6.0.
Зачистка незавершённый XA-транзакций требует значительных затрат
времени и ресурсов. Сборщик мусора должен соединиться с несколькими
участниками незавершённой транзакции и выполнить определённые
SQL-запросы для её отката.
По умолчанию: 100