|
Spec-Zone .ru
спецификации, руководства, описания, API
|
Copyright 1997-2012 PHP Documentation Group.
mysqlnd плагин выравнивания нагрузки репликации удобен. Этот быстрый запуск будет демонстрационные типичные примеры использования, и обеспечивать практический совет относительно начинания.
Строго рекомендуется считать ссылочные разделы в дополнение к быстрому запуску. Быстрый запуск пытается избежать обсуждать теоретические понятия и ограничения. Вместо этого это соединится со ссылочными разделами. Безопасно начаться с быстрого запуска. Однако, перед использованием плагина в миссии критические среды мы убеждаем Вас считать дополнительно вводную информацию из ссылочных разделов.
Фокус находится на использовании PECL mysqlnd_ms для работы с асинхронным кластером MySQL, а именно, репликации MySQL. Вообще говоря, асинхронный кластер более трудно использовать чем синхронный. Таким образом, пользователи, например, MySQL Cluster найдет больше информации чем необходимый.
Copyright 1997-2012 PHP Documentation Group.
Плагин реализуется как расширение PHP. См. также инструкции по установке, чтобы установить расширение .
Скомпилируйте или сконфигурируйте расширение MySQL PHP (API) (mysqli, PDO_MYSQL, mysql), что Вы планируете использовать с поддержкой mysqlnd библиотеки. PECL/mysqlnd_ms является плагином для mysqlnd библиотеки. Чтобы использовать плагин с любым из расширений MySQL PHP, расширение должно пользоваться mysqlnd библиотекой.
Затем, загрузите расширение в PHP и активируйте плагин в конфигурационном файле PHP, используя конфигурационную директиву PHP, названную mysqlnd_ms.enable.
Пример 22.215. Включение плагину (php.ini)
mysqlnd_ms.enable=1mysqlnd_ms.config_file=/path/to/mysqlnd_ms_plugin.ini
Плагин использует свой собственный конфигурационный файл. Используйте конфигурационную директиву PHP mysqlnd_ms.config_file, чтобы установить полный путь к файлу к сменно-специфичному конфигурационному файлу. Этот файл должен быть читаемым PHP (например, пользователь веб-сервера). Пожалуйста, отметьте, конфигурационная директива mysqlnd_ms.config_file суперотбирает mysqlnd_ms.ini_file с тех пор 1.4.0. Это - распространенная ошибка, чтобы не использовать старое, больше доступная конфигурационная директива.
Создайте сменно-специфичный конфигурационный файл. Сохраните файл к пути, установленному конфигурационной директивой PHP mysqlnd_ms.config_file.
Конфигурационным файлом плагинов является
базируемый ДЖСОН. Это делится на один или более разделов. У каждого
раздела есть имя, например, myapp. Каждый раздел делает свой собственный набор
параметров конфигурации.
Раздел должен, как минимум, перечислить главный сервер репликации MySQL, и установить список ведомых устройств. Плагин поддерживает использование только одного главного сервера на раздел. Мультиосновные установки репликации MySQL полностью еще не поддерживаются. Используйте ведущее устройство параметра конфигурации, чтобы установить имя узла, и порт или сокет главного сервера MySQL. Ведомые серверы MySQL конфигурируются, используя ведомое ключевое слово.
Пример 22.216. Минимальный сменно-специфичный конфигурационный файл (mysqlnd_ms_plugin.ini)
{ "myapp": { "master": { "master_0": { "host": "localhost" } }, "slave": [ ] }}
Конфигурирование ведомого списка сервера MySQL требуется, хотя оно может содержать пустой список. Рекомендуется всегда сконфигурировать по крайней мере один ведомый сервер.
Списки сервера могут использовать анонимный
или неанонимный синтаксис. Неанонимные списки включают имена псевдонима для серверов, такой как master_0 для ведущего устройства в вышеупомянутом примере. Быстрый запуск
использует более многословный неанонимный синтаксис.
Пример 22.217. Рекомендуемая минимальная сменно-специфичная конфигурация (mysqlnd_ms_plugin.ini)
{ "myapp": { "master": { "master_0": { "host": "localhost", "socket": "\/tmp\/mysql.sock" } }, "slave": { "slave_0": { "host": "192.168.2.27", "port": "3306" } } }}
Если есть по крайней мере два сервера всего, плагин может начать загружать соединения переключателя и баланс. Переключение соединений не всегда прозрачно и может вызвать проблемы в определенных случаях. Ссылочные разделы об объединении в пул соединения и переключении, обработке транзакции, перестаньте работать выравнивание нагрузки и чтение-запись, разделяющее всех, обеспечивают больше деталей. И потенциальные ловушки описываются позже в этом руководстве.
Это - обязанность приложения обработать потенциальные проблемы, вызванные переключателями соединения, конфигурируя ведущее устройство по крайней мере с одним ведомым сервером, который позволяет переключаться, чтобы работать поэтому, связанные проблемы могут быть найдены.
Ведущее устройство MySQL и ведомые серверы MySQL, которые Вы конфигурируете, не должны быть частью установки репликации MySQL. Для того, чтобы протестировать цель можно использовать единственный сервер MySQL и сделать известным плагину как основной и ведомый сервер как показано ниже. Это могло помочь Вам обнаружить много потенциальных проблем с переключателями соединения. Однако, такая установка не будет склонной к проблемам, вызванным задержкой репликации.
Пример 22.218. Используя один сервер как ведущее устройство и как ведомое устройство (тестирование только!)
{ "myapp": { "master": { "master_0": { "host": "localhost", "socket": "\/tmp\/mysql.sock" } }, "slave": { "slave_0": { "host": "127.0.0.1", "port": "3306" } } }}
Плагин пытается уведомить Вас относительно недопустимых конфигураций. С тех пор 1.5.0 это бросит предупреждение во время запуска PHP, если конфигурационный файл не может быть считан, пуст или анализирующий отказавшего ДЖСОНА. В зависимости от Ваших настроек PHP те ошибки могут появиться в некоторых файлах журнала только. Дальнейшая проверка допустимости делается, когда соединение должно быть установлено, и конфигурационный файл ищется допустимые разделы. Установка mysqlnd_ms.force_config_usage может помочь отладке дефектной установки. Пожалуйста, см. также примечания отладки конфигурационного файла.
Copyright 1997-2012 PHP Documentation Group.
Плагин может использоваться с любым расширением MySQL PHP (mysqli, mysql, и PDO_MYSQL), который компилируется, чтобы пользоваться mysqlnd библиотекой. PECL/mysqlnd_ms включает mysqlnd библиотеку. Это не изменяет API или поведение тех расширений.
Всякий раз, когда соединение с MySQL открывается, плагин сравнивает значение параметра узла соединить вызова
с именами раздела от сменного определенного конфигурационного файла. Если, например, у сменного
определенного конфигурационного файла есть раздел myapp тогда на раздел нужно
сослаться, открывая соединение MySQL с узлом myapp
Пример 22.219. Сменный определенный конфигурационный файл (mysqlnd_ms_plugin.ini)
{ "myapp": { "master": { "master_0": { "host": "localhost", "socket": "\/tmp\/mysql.sock" } }, "slave": { "slave_0": { "host": "192.168.2.27", "port": "3306" } } }}
Пример 22.220. Открытие загрузки сбалансированное соединение
<?php/* Load balanced following "myapp" section rules from the plugins config file */$mysqli = new mysqli("myapp", "username", "password", "database");$pdo = new PDO('mysql:host=myapp;dbname=database', 'username', 'password');$mysql = mysql_connect("myapp", "username", "password");?>
Примерами соединения выше будет сбалансированная загрузка. Плагин отправит операторы только для чтения
ведомому серверу MySQL с IP 192.168.2.27 и будет слушать на порту 3306 для клиентского соединения MySQL. Все другие операторы будут направлены
к главному серверу MySQL, работающему на узле localhost. Если на Unix как
операционные системы, ведущее устройство на localhost будет принимать
клиентские соединения MySQL на сокете домена Unix /tmp/mysql.sock, в то время
как TCP/IP является портом значения по умолчанию на Windows. Плагин будет использовать имя пользователя
username и пароль password соединяться с любым из
серверов MySQL, перечисленных в разделе myapp из конфигурационного файла
плагинов. На соединяются, плагин выберет database как текущие схемы.
Имя пользователя, пароль и имя схемы берутся от соединить вызовов API и используются для всех серверов. Другими словами: следует использовать то же самое имя пользователя и пароль для каждого сервера MySQL, перечисленного в сменном разделе конфигурационного файла. Не общее ограничение. С PECL/mysqlnd_ms 1.1.0, возможно установить имя пользователя и пароль для любого сервера в конфигурационном файле плагинов, использоваться вместо учетных данных, которые передают к вызову API.
Плагин не изменяет API для рабочих операторов. Разделение чтения-записи работает из поля. Следующий пример предполагает, что нет никакой существенной задержки репликации между ведущим устройством и ведомым устройством.
Пример 22.221. Выполнение операторов
<?php/* Load balanced following "myapp" section rules from the plugins config file */$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()));/* Statements will be run on the master */if (!$mysqli->query("DROP TABLE IF EXISTS test")) { printf("[%d] %s\n", $mysqli->errno, $mysqli->error);}if (!$mysqli->query("CREATE TABLE test(id INT)")) { printf("[%d] %s\n", $mysqli->errno, $mysqli->error);}if (!$mysqli->query("INSERT INTO test(id) VALUES (1)")) { printf("[%d] %s\n", $mysqli->errno, $mysqli->error);}/* read-only: statement will be run on a slave */if (!($res = $mysqli->query("SELECT id FROM test")) { printf("[%d] %s\n", $mysqli->errno, $mysqli->error);} else { $row = $res->fetch_assoc(); $res->close(); printf("Slave returns id = '%s'\n", $row['id'];}$mysqli->close();?>
Вышеупомянутый пример выведет что-то подобное:
Slave returns id = '1'
Copyright 1997-2012 PHP Documentation Group.
Плагин изменяет семантику дескриптора соединения MySQL PHP. Новый дескриптор соединения представляет пул соединения вместо единственного MySQL сетевое соединение клиент-сервер. Пул соединения состоит из основного соединения, и дополнительно любого числа ведомых соединений.
У каждого соединения от пула соединения есть свое собственное состояние. Например, пользовательские переменные SQL, временные таблицы и транзакции являются частью состояния. Для полного списка элементов, которые принадлежат состоянию соединения, см., что соединение объединяет в пул и переключает документацию понятий. Если плагин решает переключить соединения для выравнивания нагрузки, приложению можно было бы дать соединение, у которого есть различное состояние. Заявки должны быть поданы знающий об этом.
Пример 22.222. Сменная конфигурация с одним ведомым устройством и одним ведущим устройством
{ "myapp": { "master": { "master_0": { "host": "localhost", "socket": "\/tmp\/mysql.sock" } }, "slave": { "slave_0": { "host": "192.168.2.27", "port": "3306" } } }}
Пример 22.223. Ловушка: состояние соединения и пользовательские переменные SQL
<?php$mysqli = new mysqli("myapp", "username", "password", "database");if (!$mysqli) /* Of course, your error handling is nicer... */ die(sprintf("[%d] %s\n", mysqli_connect_errno(), mysqli_connect_error()));/* Connection 1, connection bound SQL user variable, no SELECT thus run on master */if (!$mysqli->query("SET @myrole='master'")) { printf("[%d] %s\n", $mysqli->errno, $mysqli->error);}/* Connection 2, run on slave because SELECT */if (!($res = $mysqli->query("SELECT @myrole AS _role"))) { printf("[%d] %s\n", $mysqli->errno, $mysqli->error);} else { $row = $res->fetch_assoc(); $res->close(); printf("@myrole = '%s'\n", $row['_role']);}$mysqli->close();?>
Вышеупомянутый пример выведет:
@myrole = ''
Пример открывает загрузку сбалансированное соединение и выполняет два оператора. Первый оператор SET @myrole='master' не начинается со строки SELECT.
Поэтому плагин не распознает это как запрос только для чтения, который должен быть выполнен на ведомом
устройстве. Плагин выполняет оператор на соединении с ведущим устройством. Оператор устанавливает
пользовательскую переменную SQL, которая связывается с основным соединением. Состояние основного соединения
было изменено.
Следующий оператор SELECT @myrole AS _role. Плагин действительно распознает это
как запрос только для чтения и отправляет это ведомому устройству. Оператор выполняется на соединении с
ведомым устройством. У этого второго соединения нет никаких пользовательских переменных SQL связанными с
этим. У этого есть различное состояние чем первое соединение с ведущим устройством. Требуемая
пользовательская переменная SQL не устанавливается. Печатные издания сценария в качестве примера @myrole = ''.
Это - обязанность разработчика приложений заботиться о состоянии соединения. Плагин не контролирует все действия изменения состояния соединения. Контроль всех возможных случаев был бы очень ЦП интенсивная задача, если это могло бы быть сделано вообще.
Ловушки могут легко работаться вокруг использования подсказок SQL.
Copyright 1997-2012 PHP Documentation Group.
Подсказки SQL могут вынудить запрос выбрать определенный сервер из пула соединения. Это дает плагину подсказку, чтобы использовать определяемый сервер, который может решить проблемы, вызванные переключателями соединения и состоянием соединения.
Подсказки SQL являются стандартными совместимыми комментариями SQL. Поскольку комментарии SQL, как предполагается, игнорируются системами обработки SQL, они не вмешиваются в другие программы, такие как MySQL Server, MySQL Proxy, или брандмауэр.
Три подсказки SQL поддерживаются плагином: MYSQLND_MS_MASTER_SWITCH подсказка
заставляет плагин выполнить оператор на ведущем устройстве, MYSQLND_MS_SLAVE_SWITCH осуществляет использование ведомого устройства, и
MYSQLND_MS_LAST_USED_SWITCH выполнит оператор на том же самом сервере, который
использовался для предыдущего оператора.
Плагин сканирует начало оператора для существования подсказки SQL. Подсказки SQL только распознаются, если они появляются в начале оператора.
Пример 22.224. Сменная конфигурация с одним ведомым устройством и одним ведущим устройством
{ "myapp": { "master": { "master_0": { "host": "localhost", "socket": "\/tmp\/mysql.sock" } }, "slave": { "slave_0": { "host": "192.168.2.27", "port": "3306" } } }}
Пример 22.225. SQL подсказывает, чтобы предотвратить переключатели соединения
<?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()));/* Connection 1, connection bound SQL user variable, no SELECT thus run on master */if (!$mysqli->query("SET @myrole='master'")) { printf("[%d] %s\n", $mysqli->errno, $mysqli->error);}/* Connection 1, run on master because of SQL hint */if (!($res = $mysqli->query(sprintf("/*%s*/SELECT @myrole AS _role", MYSQLND_MS_LAST_USED_SWITCH)))) { printf("[%d] %s\n", $mysqli->errno, $mysqli->error);} else { $row = $res->fetch_assoc(); $res->close(); printf("@myrole = '%s'\n", $row['_role']);}$mysqli->close();?>
Вышеупомянутый пример выведет:
@myrole = 'master'
В вышеупомянутом примере, используя MYSQLND_MS_LAST_USED_SWITCH предотвращает
сеанс, переключающийся от ведущего устройства к ведомому устройству, работая SELECT оператор.
Подсказки SQL могут также использоваться, чтобы работать SELECT операторы на
главном сервере MySQL. Это может требоваться, если ведомые серверы MySQL обычно находятся позади ведущего
устройства, но Вы нуждаетесь в текущих данных от кластера.
В версии 1.2.0 понятие уровня обслуживания было представлено, чтобы адресовать случаи, когда текущие данные требуются. Используя уровень обслуживания требует меньшего внимания и устраняет потребность использования подсказок SQL для этого варианта использования. Пожалуйста, найдите больше информации ниже в разделе непротиворечивости и уровне обслуживания.
Пример 22.226. Борьба с задержкой репликации
<?php$mysqli = new mysqli("myapp", "username", "password", "database");if (!$mysqli) /* Of course, your error handling is nicer... */ die(sprintf("[%d] %s\n", mysqli_connect_errno(), mysqli_connect_error()));/* Force use of master, master has always fresh and current data */if (!$mysqli->query(sprintf("/*%s*/SELECT critical_data FROM important_table", MYSQLND_MS_MASTER_SWITCH))) { printf("[%d] %s\n", $mysqli->errno, $mysqli->error);}?>
Вариант использования может включать создание таблиц на ведомом устройстве. Если подсказка SQL не будет
дана, то плагин передастся CREATE и INSERT
операторы ведущему устройству. Используйте подсказку SQL MYSQLND_MS_SLAVE_SWITCH если Вы хотите выполнить какой-либо такой оператор
на ведомом устройстве, например, создать временные таблицы создания отчетов.
Пример 22.227. Табличное создание на ведомом устройстве
<?php$mysqli = new mysqli("myapp", "username", "password", "database");if (!$mysqli) /* Of course, your error handling is nicer... */ die(sprintf("[%d] %s\n", mysqli_connect_errno(), mysqli_connect_error()));/* Force use of slave */if (!$mysqli->query(sprintf("/*%s*/CREATE TABLE slave_reporting(id INT)", MYSQLND_MS_SLAVE_SWITCH))) { printf("[%d] %s\n", $mysqli->errno, $mysqli->error);}/* Continue using this particular slave connection */if (!$mysqli->query(sprintf("/*%s*/INSERT INTO slave_reporting(id) VALUES (1), (2), (3)", MYSQLND_MS_LAST_USED_SWITCH))) { printf("[%d] %s\n", $mysqli->errno, $mysqli->error);}/* Don't use MYSQLND_MS_SLAVE_SWITCH which would allow switching to another slave! */if ($res = $mysqli->query(sprintf("/*%s*/SELECT COUNT(*) AS _num FROM slave_reporting", MYSQLND_MS_LAST_USED_SWITCH))) { $row = $res->fetch_assoc(); $res->close(); printf("There are %d rows in the table 'slave_reporting'", $row['_num']);} else { printf("[%d] %s\n", $mysqli->errno, $mysqli->error);}$mysqli->close();?>
Подсказка SQL MYSQLND_MS_LAST_USED запрещает переключение соединения, и
вызывает использование ранее используемого соединения.
Copyright 1997-2012 PHP Documentation Group.
Текущая версия плагина не является транзакцией, безопасной по умолчанию, потому что это не знает о рабочих транзакциях во всех случаях. Транзакции SQL являются единицами работы, которые будут выполнены на единственном сервере. Плагин не всегда знает, когда единица работы запускается и когда это заканчивается. Поэтому, плагин может решить переключить соединения в середине транзакции.
Никакой вид стабилизатора загрузки MySQL не может обнаружить границы транзакции без любого вида подсказки из приложения.
Можно или использовать подсказки SQL, чтобы работать вокруг этого ограничения. Альтернативно, можно активировать контроль вызова API транзакции. В последнем случае следует использовать вызовы API только контрольных сделок, видеть ниже.
Пример 22.228. Сменная конфигурация с одним ведомым устройством и одним ведущим устройством
[myapp]{ "myapp": { "master": { "master_0": { "host": "localhost", "socket": "\/tmp\/mysql.sock" } }, "slave": { "slave_0": { "host": "192.168.2.27", "port": "3306" } } }}
Пример 22.229. Используя SQL подсказывает для транзакций
<?php$mysqli = new mysqli("myapp", "username", "password", "database");if (!$mysqli) /* Of course, your error handling is nicer... */ die(sprintf("[%d] %s\n", mysqli_connect_errno(), mysqli_connect_error()));/* Not a SELECT, will use master */if (!$mysqli->query("START TRANSACTION")) { /* Please use better error handling in your code */ die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));}/* Prevent connection switch! */if (!$mysqli->query(sprintf("/*%s*/INSERT INTO test(id) VALUES (1)", MYSQLND_MS_LAST_USED_SWITCH)))) { /* Please do proper ROLLBACK in your code, don't just die */ die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));}if ($res = $mysqli->query(sprintf("/*%s*/SELECT COUNT(*) AS _num FROM test", MYSQLND_MS_LAST_USED_SWITCH)))) { $row = $res->fetch_assoc(); $res->close(); if ($row['_num'] > 1000) { if (!$mysqli->query(sprintf("/*%s*/INSERT INTO events(task) VALUES ('cleanup')", MYSQLND_MS_LAST_USED_SWITCH)))) { die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error)); } }} else { die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));}if (!$mysqli->query(sprintf("/*%s*/UPDATE log SET last_update = NOW()", MYSQLND_MS_LAST_USED_SWITCH)))) { die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));}if (!$mysqli->query(sprintf("/*%s*/COMMIT", MYSQLND_MS_LAST_USED_SWITCH)))) { die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));}$mysqli->close();?>
Запускаясь с PHP 5.4.0, mysqlnd библиотека позволяет плагину контролировать
состояние autocommit режим, если режим устанавливается вызовами API вместо
того, чтобы использовать SQL-операторы такой как SET AUTOCOMMIT=0. Это
позволяет плагину стать знающей транзакцией. В этом случае Вы не должны использовать подсказки SQL.
Используя PHP 5.4.0 или более новые, вызовы API, которые включают autocommit
режим, и устанавливая сменный параметр конфигурации trx_stickiness=master,
плагин может автоматически отключить выравнивание нагрузки и переключатели соединения для транзакций SQL. В
этой конфигурации плагин останавливает выравнивание нагрузки если autocommit
отключается и направляет все операторы к ведущему устройству. Это предотвращает переключатели соединения в
середине транзакции. Однажды autocommit повторно включается, плагин начинает
загружать операторы баланса снова.
API, который базируемое обнаружение границы транзакции было улучшено с PHP 5.5.0 и PECL/mysqlnd_ms 1.5.0,
чтобы покрыть не только, призывает mysqli_autocommit но также и ,
mysqli_commit и mysqli_rollback.
Пример 22.230. Транзакция осведомленное выравнивание нагрузки: установка trx_stickiness
{ "myapp": { "master": { "master_0": { "host": "localhost", "socket": "\/tmp\/mysql.sock" } }, "slave": { "slave_0": { "host": "127.0.0.1", "port": "3306" } }, "trx_stickiness": "master" }}
Пример 22.231. Знающая транзакция
<?php$mysqli = new mysqli("myapp", "username", "password", "database");if (!$mysqli) /* Of course, your error handling is nicer... */ die(sprintf("[%d] %s\n", mysqli_connect_errno(), mysqli_connect_error()));/* Disable autocommit, plugin will run all statements on the master */$mysqli->autocommit(FALSE);if (!$mysqli->query("INSERT INTO test(id) VALUES (1)")) { /* Please do proper ROLLBACK in your code, don't just die */ die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));}if ($res = $mysqli->query("SELECT COUNT(*) AS _num FROM test")) { $row = $res->fetch_assoc(); $res->close(); if ($row['_num'] > 1000) { if (!$mysqli->query("INSERT INTO events(task) VALUES ('cleanup')")) { die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error)); } }} else { die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));}if (!$mysqli->query("UPDATE log SET last_update = NOW()")) { die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));}if (!$mysqli->commit()) { die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));}/* Plugin assumes that the transaction has ended and starts load balancing again */$mysqli->autocommit(TRUE);$mysqli->close();?>
Сменный параметр конфигурации trx_stickiness=master требует PHP 5.4.0 или более новый.
Пожалуйста, отметьте ограничения, обрисованные в общих чертах в транзакции, обрабатывающей раздел понятий.
Copyright 1997-2012 PHP Documentation Group.
Уровни обслуживания были представлены в PECL mysqlnd_ms версия, с 1.2.0 альфами. mysqlnd_ms_set_qos доступно
с PHP 5.4.0 или более нов.
Различные типы решений для кластера MySQL предлагают различную услугу и уровни непротиворечивости данных их пользователям. Асинхронный кластер репликации MySQL предлагает возможную непротиворечивость по умолчанию. Чтение, выполняемое на асинхронном ведомом устройстве, может возвратить ток, устарелый или никакие данные вообще, в зависимости от того, воспроизвело ли ведомое устройство весь changesets от ведущего устройства или нет.
Приложения используя кластер репликации MySQL должны быть разработаны, чтобы работать правильно с возможными непротиворечивыми данными. В некоторых случаях, однако, устаревшие данные не являются приемлемыми. В тех случаях только определенным ведомым устройствам или даже только основным доступам позволяют достигнуть необходимого качества службы от кластера.
С PECL mysqlnd_ms 1.2.0 плагин способен к выбору узлов репликации MySQL автоматически, которые поставляют непротиворечивость сеанса или непротиворечивость strong. Непротиворечивость сеанса означает, что один клиент может считать ее записи. Другие клиенты могут или, возможно, не видят запись клиентов. Сильная непротиворечивость означает, что все клиенты будут видеть все записи от клиента.
Пример 22.232. Непротиворечивость сеанса: считайте свои записи
{ "myapp": { "master": { "master_0": { "host": "localhost", "socket": "\/tmp\/mysql.sock" } }, "slave": { "slave_0": { "host": "127.0.0.1", "port": "3306" } } }}
Пример 22.233. Запрос непротиворечивости сеанса
<?php$mysqli = new mysqli("myapp", "username", "password", "database");if (!$mysqli) /* Of course, your error handling is nicer... */ die(sprintf("[%d] %s\n", mysqli_connect_errno(), mysqli_connect_error()));/* read-write splitting: master used */if (!$mysqli->query("INSERT INTO orders(order_id, item) VALUES (1, 'christmas tree, 1.8m')")) { /* Please use better error handling in your code */ die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));}/* Request session consistency: read your writes */if (!mysqlnd_ms_set_qos($mysqli, MYSQLND_MS_QOS_CONSISTENCY_SESSION)) die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));/* Plugin picks a node which has the changes, here: master */if (!$res = $mysqli->query("SELECT item FROM orders WHERE order_id = 1")) die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));var_dump($res->fetch_assoc());/* Back to eventual consistency: stale data allowed */if (!mysqlnd_ms_set_qos($mysqli, MYSQLND_MS_QOS_CONSISTENCY_EVENTUAL)) die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));/* Plugin picks any slave, stale data is allowed */if (!$res = $mysqli->query("SELECT item, price FROM specials")) die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));?>
Уровни обслуживания могут быть установлены в конфигурационном файле плагинов и при использовании времени
выполнения mysqlnd_ms_set_qos. В
примере функция используется, чтобы осуществить непротиворечивость сеанса (считайте свои записи) для всех
будущих операторов до следующего приказа. SELECT оператор на orders таблица выполняется на ведущем устройстве, чтобы гарантировать, что
предыдущая запись может быть замечена клиентом. Логика разделения чтения-записи была адаптирована, чтобы
выполнить уровень обслуживания.
После того, как приложение считало свои изменения из orders таблица, которую
это возвращает уровню обслуживания значения по умолчанию, который является возможной непротиворечивостью.
Возможная непротиворечивость не помещает ограничений на выбор узла для выполнения оператора. Таким образом,
SELECT оператор на specials таблица выполняется на
ведомом устройстве.
Новая функциональность заменяет использование подсказок SQL и master_on_write
параметр конфигурации. Во многих случаях mysqlnd_ms_set_qos
легче использовать, более мощный улучшает мобильность.
Пример 22.234. Максимальная задержка возраста/ведомого устройства
{ "myapp": { "master": { "master_0": { "host": "localhost", "socket": "\/tmp\/mysql.sock" } }, "slave": { "slave_0": { "host": "127.0.0.1", "port": "3306" } }, "failover" : "master" }}
Пример 22.235. Ограничение ведомой задержки
<?php$mysqli = new mysqli("myapp", "username", "password", "database");if (!$mysqli) /* Of course, your error handling is nicer... */ die(sprintf("[%d] %s\n", mysqli_connect_errno(), mysqli_connect_error()));/* Read from slaves lagging no more than four seconds */$ret = mysqlnd_ms_set_qos($mysqli, MYSQLND_MS_QOS_CONSISTENCY_EVENTUAL, MYSQLND_MS_QOS_OPTION_AGE, 4);if (!$ret) die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));/* Plugin picks any slave, which may or may not have the changes */if (!$res = $mysqli->query("SELECT item, price FROM daytrade")) die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));/* Back to default: use of all slaves and masters permitted */if (!mysqlnd_ms_set_qos($mysqli, MYSQLND_MS_QOS_CONSISTENCY_EVENTUAL)) die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));?>
Возможный уровень обслуживания непротиворечивости может использоваться с дополнительным параметром, чтобы
установить максимальную ведомую задержку для того, чтобы выбрать ведомые устройства. Если установлено,
сменные проверки SHOW SLAVE STATUS для всех сконфигурированных ведомых
устройств. В случае того, примера, только ведомые устройства, для который Slave_IO_Running=Yes,
Slave_SQL_Running=Yes и Seconds_Behind_Master <=
4 истина, рассматриваются для того, чтобы выполнить оператор SELECT item,
price FROM daytrade.
Проверка SHOW SLAVE STATUS делается прозрачно с точки зрения приложений. Об
ошибках, если таковые вообще имеются, сообщают как предупреждения. Никакая ошибка не будет установлена на
дескрипторе соединения. Даже если все SHOW SLAVE STATUS SQL-операторы,
выполняемые сменным сбоем, выполнение пользовательского оператора не останавливается, переданное, что
основной сбой включается. Таким образом никакие изменения приложения не требуются.
Проверка SHOW SLAVE STATUS поскольку все ведомые устройства
добавляют издержки к приложению. Это - дорогая и медленная фоновая работа. Попытайтесь минимизировать
использование этого. К сожалению, кластер репликации MySQL не дает клиентам возможность запросить список
кандидатов от центрального экземпляра. Таким образом более эффективный способ проверить ведомую задержку
не доступен.
Пожалуйста, отметьте ограничения и свойства SHOW SLAVE STATUS как
объяснено в справочнике MySQL.
Чтобы препятствовать тому, чтобы mysqlnd_ms испустил предупреждение, если никакие ведомые устройства не могут быть сочтены той задержкой не больше, чем определенным числом секунд позади ведущего устройства, необходимо включить основному сбою в конфигурационном файле плагинов. Если никакие ведомые устройства не могут быть найдены, и сбой включается, плагин выбирает ведущее устройство для того, чтобы выполнить оператор.
Если никакое ведомое устройство не может быть найдено, и сбой выключается, плагин испускает предупреждение, это не выполняет оператор, и это устанавливает ошибку на соединении.
Пример 22.236. Перестаньте работать по не набор
{ "myapp": { "master": { "master_0": { "host": "localhost", "socket": "\/tmp\/mysql.sock" } }, "slave": { "slave_0": { "host": "127.0.0.1", "port": "3306" } } }}
Пример 22.237. Никакое ведомое устройство в пределах ограничения по времени
<?php$mysqli = new mysqli("myapp", "username", "password", "database");if (!$mysqli) /* Of course, your error handling is nicer... */ die(sprintf("[%d] %s\n", mysqli_connect_errno(), mysqli_connect_error()));/* Read from slaves lagging no more than four seconds */$ret = mysqlnd_ms_set_qos($mysqli, MYSQLND_MS_QOS_CONSISTENCY_EVENTUAL, MYSQLND_MS_QOS_OPTION_AGE, 4);if (!$ret) die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));/* Plugin picks any slave, which may or may not have the changes */if (!$res = $mysqli->query("SELECT item, price FROM daytrade")) die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));/* Back to default: use of all slaves and masters permitted */if (!mysqlnd_ms_set_qos($mysqli, MYSQLND_MS_QOS_CONSISTENCY_EVENTUAL)) die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));?>
Вышеупомянутый пример выведет:
PHP Warning: mysqli::query(): (mysqlnd_ms) Couldn't find the appropriate slave connection. 0 slaves to choose from. Something is wrong in %s on line %dPHP Warning: mysqli::query(): (mysqlnd_ms) No connection selected by the last filter in %s on line %d[2000] (mysqlnd_ms) No connection selected by the last filter
Copyright 1997-2012 PHP Documentation Group.
Клиентская глобальная инжекция ID транзакции была представлена в mysqlnd_ms версии, с 1.2.0 альфами. Функция не требуется для синхронных кластеров, таких как MySQL Cluster. Используйте это с асинхронными кластерами, такими как классическая репликация MySQL.
С MySQL, 5.6.5-m8 функции сервера MySQL встроенные глобальные идентификаторы транзакции. MySQL встроенная глобальная функция ID транзакции поддерживается PECL/mysqlnd_ms, с 1.3.0 альфами или позже.
PECL/mysqlnd_ms может или использовать свою собственную глобальную эмуляцию ID транзакции или глобальную функцию ID транзакции, встроенную к MySQL, 5.6.5-m8 или позже. С точки зрения разработчика клиентский и серверный подход предлагают те же самые функции относительно уровней обслуживания, обеспеченных PECL/mysqlnd_ms. Их различия обсуждаются в разделе понятий.
Быстрый запуск сначала демонстрирует использование клиентской глобальной эмуляции ID транзакции, встроенной к PECL/mysqlnd_ms перед его шоу, как использовать серверный дубликат. Порядок гарантирует, что базовая идея обсуждается сначала.
Идея и клиентская эмуляция
В его наиболее канонической форме глобальный ID транзакции (GTID) является счетчиком в таблице на ведущем устройстве. Счетчик постепенно увеличивается всякий раз, когда транзакция фиксируется на ведущем устройстве. Ведомые устройства тиражируют таблицу. Счетчик служит двум целям. В случае основного отказа это помогает администратору базы данных идентифицировать новое ведомое устройство для того, чтобы продвинуть это новое ведущее устройство. Новое ведомое устройство является тем с самым высоким встречным значением. Приложения могут использовать глобальный ID транзакции, чтобы искать ведомые устройства, которые уже тиражировали определенную запись (идентифицированный глобальным ID транзакции).
PECL/mysqlnd_ms может ввести SQL для каждой переданной транзакции, чтобы постепенно увеличить счетчик GTID. Так создал GTID, доступно приложением, чтобы идентифицировать операцию записи приложений. Это позволяет плагину поставить, непротиворечивость сеанса (считайте свои записи), уровень обслуживания, не только запрашивая ведущие устройства, но также и ведомые устройства, которые уже тиражировали изменение. Читайте загрузка портится ведущее устройство.
У клиентской глобальной эмуляции ID транзакции есть некоторые ограничения. Пожалуйста, считайте раздел понятий тщательно, чтобы полностью понять принципы и идеи позади этого, перед использованием в продуктивных средах. Фоновое знание не обязано продолжаться с быстрым запуском.
Во-первых, составьте встречную таблицу на своем главном сервере и вставьте запись в него. Плагин не помогает составлению таблицы. Администраторы базы данных должны удостовериться, что это существует. В зависимости от режима сообщения об ошибке плагин тихо проигнорирует нехватку таблицы или прыгнет с парашютом.
Пример 22.238. Составьте встречную таблицу на ведущем устройстве
CREATE TABLE `trx` ( `trx_id` int(11) DEFAULT NULL, `last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP) ENGINE=InnoDB DEFAULT CHARSET=latin1INSERT INTO `trx`(`trx_id`) VALUES (1);
В наборе конфигурационного файла плагинов SQL, чтобы обновить глобальное табличное использование ID
транзакции on_commit от global_transaction_id_injection раздел. Удостоверьтесь имя таблицы,
используемое для UPDATE оператор полностью определяется. В примере, test.trx используется, чтобы обратиться к таблице trx в схеме (база данных) test. Используйте
таблицу, которая была составлена в предыдущем шаге. Важно установить полностью определенное имя таблицы,
потому что соединение, на котором делается инжекция, может использовать различную базу данных значения по
умолчанию. Удостоверьтесь пользователь, который открывается, соединению позволяют выполниться UPDATE.
Позвольте сообщить ошибок, которые могут произойти, когда mysqlnd_ms делает глобальную инжекцию ID транзакции.
Пример 22.239. Сменная конфигурация: SQL для стороны клиента инжекция GTID
{ "myapp": { "master": { "master_0": { "host": "localhost", "socket": "\/tmp\/mysql.sock" } }, "slave": { "slave_0": { "host": "127.0.0.1", "port": "3306" } }, "global_transaction_id_injection":{ "on_commit":"UPDATE test.trx SET trx_id = trx_id + 1", "report_error":true } }}
Пример 22.240. Прозрачная глобальная инжекция ID транзакции
<?php$mysqli = new mysqli("myapp", "username", "password", "database");if (!$mysqli) /* Of course, your error handling is nicer... */ die(sprintf("[%d] %s\n", mysqli_connect_errno(), mysqli_connect_error()));/* auto commit mode, transaction on master, GTID must be incremented */if (!$mysqli->query("DROP TABLE IF EXISTS test")) die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));/* auto commit mode, transaction on master, GTID must be incremented */if (!$mysqli->query("CREATE TABLE test(id INT)")) die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));/* auto commit mode, transaction on master, GTID must be incremented */if (!$mysqli->query("INSERT INTO test(id) VALUES (1)")) die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));/* auto commit mode, read on slave, no increment */if (!($res = $mysqli->query("SELECT id FROM test"))) die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));var_dump($res->fetch_assoc());?>
Вышеупомянутый пример выведет:
array(1) { ["id"]=> string(1) "1"}
Пример выполняет три оператора в автоматическом режиме фиксации на ведущем устройстве, вызывая три
транзакции на ведущем устройстве. Для каждого такого оператора плагин введет сконфигурированный UPDATE прозрачно прежде, чем выполнить пользовательский SQL-оператор. Когда
сценарий заканчивается, глобальный счетчик ID транзакции на ведущем устройстве был постепенно увеличен три.
Четвертый SQL-оператор, выполняемый в примере, a SELECT, не инициировал
инкремент. Только транзакции (записи), выполняемые на ведущем устройстве, должны постепенно увеличить
счетчик GTID.
SQL, используемый для клиентской глобальной эмуляции ID транзакции, неэффективен. Это оптимизируется для clearity не для производительности. Не используйте это для продуктивных сред. Пожалуйста, справка, находящая эффективное решение для включения в руководство. Мы ценим Ваш ввод.
Пример 22.241. Сменная конфигурация: SQL для того, чтобы выбрать GTID
{ "myapp": { "master": { "master_0": { "host": "localhost", "socket": "\/tmp\/mysql.sock" } }, "slave": { "slave_0": { "host": "127.0.0.1", "port": "3306" } }, "global_transaction_id_injection":{ "on_commit":"UPDATE test.trx SET trx_id = trx_id + 1", "fetch_last_gtid" : "SELECT MAX(trx_id) FROM test.trx", "report_error":true } }}
Пример 22.242. Получение GTID после инжекции
<?php$mysqli = new mysqli("myapp", "username", "password", "database");if (!$mysqli) /* Of course, your error handling is nicer... */ die(sprintf("[%d] %s\n", mysqli_connect_errno(), mysqli_connect_error()));/* auto commit mode, transaction on master, GTID must be incremented */if (!$mysqli->query("DROP TABLE IF EXISTS test")) die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));printf("GTID after transaction %s\n", mysqlnd_ms_get_last_gtid($mysqli));/* auto commit mode, transaction on master, GTID must be incremented */if (!$mysqli->query("CREATE TABLE test(id INT)")) die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));printf("GTID after transaction %s\n", mysqlnd_ms_get_last_gtid($mysqli));?>
Вышеупомянутый пример выведет:
GTID after transaction 7GTID after transaction 8
Приложения могут попросить у PECL mysqlnd_ms глобальный ID транзакции, который принадлежит последней
операции записи, выполняемой приложением. Функция mysqlnd_ms_get_last_gtid возвращает GTID, полученный, выполняя
SQL-оператор от fetch_last_gtid запись global_transaction_id_injection
раздел от конфигурационного файла плагинов. Функция может быть вызвана после того, как GTID был постепенно
увеличен.
Приложения являются adviced, чтобы не выполнить SQL-оператор самостоятельно, поскольку это обнажает риск случайно порождения неявного инкремента GTID. Кроме того, если функция используется, легко переместить приложение от одного SQL-оператора для того, чтобы выбрать ID транзакции другому, например, если любой сервер MySQL когда-либо функции встроенная глобальная поддержка ID транзакции.
Быстрый запуск показывает SQL-оператор, который возвратит равное GTID или большее к создаваемому для
предыдущего оператора. Это - точно GTID, создаваемый для предыдущего оператора, если никакие другие клиенты
не постепенно увеличили GTID в отрезке времени между выполнением оператора и SELECT выбирать GTID. Иначе, это больше.
Пример 22.243. Сменная конфигурация: Проверка определенный GTID
{ "myapp": { "master": { "master_0": { "host": "localhost", "socket": "\/tmp\/mysql.sock" } }, "slave": { "slave_0": { "host": "127.0.0.1", "port": "3306" } }, "global_transaction_id_injection":{ "on_commit":"UPDATE test.trx SET trx_id = trx_id + 1", "fetch_last_gtid" : "SELECT MAX(trx_id) FROM test.trx", "check_for_gtid" : "SELECT trx_id FROM test.trx WHERE trx_id >= #GTID", "report_error":true } }}
Пример 22.244. Уровень обслуживания непротиворечивости сеанса и GTID объединились
<?php$mysqli = new mysqli("myapp", "username", "password", "database");if (!$mysqli) /* Of course, your error handling is nicer... */ die(sprintf("[%d] %s\n", mysqli_connect_errno(), mysqli_connect_error()));/* auto commit mode, transaction on master, GTID must be incremented */if (!$mysqli->query("DROP TABLE IF EXISTS test") || !$mysqli->query("CREATE TABLE test(id INT)") || !$mysqli->query("INSERT INTO test(id) VALUES (1)")) die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));/* GTID as an identifier for the last write */$gtid = mysqlnd_ms_get_last_gtid($mysqli);/* Session consistency (read your writes): try to read from slaves not only master */if (false == mysqlnd_ms_set_qos($mysqli, MYSQLND_MS_QOS_CONSISTENCY_SESSION, MYSQLND_MS_QOS_OPTION_GTID, $gtid)) { die(sprintf("[006] [%d] %s\n", $mysqli->errno, $mysqli->error));}/* Either run on master or a slave which has replicated the INSERT */if (!($res = $mysqli->query("SELECT id FROM test"))) { die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));}var_dump($res->fetch_assoc());?>
GTID, возвращенный из mysqlnd_ms_get_last_gtid
может использоваться в качестве опции для уровня обслуживания непротиворечивости сеанса. Непротиворечивость
сеанса поставляет, читает Ваши записи. Непротиворечивость сеанса можно требовать, вызывая mysqlnd_ms_set_qos. В примере плагин выполнится SELECT
оператор или на ведущем устройстве или на ведомом устройстве, которое тиражировало предыдущее INSERT уже.
PECL mysqlnd_ms прозрачно проверит каждое сконфигурированное ведомое устройство, если это тиражировалось
INSERT проверяя ведомые устройства таблица GTID. Проверка делается, выполняя
набор SQL с check_for_gtid опция от global_transaction_id_injection
раздел конфигурационного файла плагинов. Пожалуйста, отметьте, что это - медленная и дорогая процедура.
Приложения должны попытаться использовать это редко и только если считанная загрузка на ведущем устройстве
становится к высокому иначе.
Использование серверной глобальной функции ID транзакции
Запуск с MySQL, 5.6.5-m8 серверные глобальные ID транзакции характеристик системы MySQL Replication.
Идентификаторы транзакции автоматически сгенерированы и сохраняются сервером. Пользователи не должны
заботиться о поддержании их. Нет никакой потребности установить любые таблицы заранее, или для того, чтобы
установить on_commit. Клиентская эмуляция больше не необходима.
Клиенты могут продолжать использовать глобальный идентификатор транзакции, чтобы достигнуть
непротиворечивости сеанса, читая из ведомых устройств MySQL Replication. Алгоритм работает как описано выше.
Различные SQL-операторы должны быть сконфигурированы для fetch_last_gtid и
check_for_gtid. Операторы даются ниже. Пожалуйста, отметьте, 5.6.5-m8 MySQL
является версией разработки. Детали реализации сервера могут измениться в будущем и потребовать принятия
показанных SQL-операторов.
Используя следующую конфигурацию любая вышеупомянутая описанная функциональность может использоваться вместе
с серверной глобальной функцией ID транзакции. mysqlnd_ms_get_last_gtid и mysqlnd_ms_set_qos продолжайте работать как описано выше. Единственная
разница - то, что сервер не использует простой порядковый номер, но строку, содержащую идентификатора
сервера и порядкового номера. Таким образом пользователи не могут легко получить порядок от GTIDs,
возвращенного mysqlnd_ms_get_last_gtid.
Пример 22.245. Сменная конфигурация: использование MySQL 5.6.5-m8 встроенная функция GTID
{ "myapp": { "master": { "master_0": { "host": "localhost", "socket": "\/tmp\/mysql.sock" } }, "slave": { "slave_0": { "host": "127.0.0.1", "port": "3306" } }, "global_transaction_id_injection":{ "fetch_last_gtid" : "SELECT @@GLOBAL.GTID_DONE AS trx_id FROM DUAL", "check_for_gtid" : "SELECT GTID_SUBSET('#GTID', @@GLOBAL.GTID_DONE) AS trx_id FROM DUAL", "report_error":true } }}
Copyright 1997-2012 PHP Documentation Group.
Пожалуйста, найдите больше о требованиях версии, зависимостях от порядка загрузки расширения и текущем статусе в разделе понятий!
Кластеры баз данных могут поставить разные уровни непротиворечивости. С PECL/mysqlnd_ms 1.2.0 к совету плагин возможно рассмотреть только узлы кластера, которые могут поставить уровень непротиворечивости, который требуют. Например, используя асинхронный MySQL Replication с его возможной непротиворечивостью всего кластера, возможно запросить непротиворечивость сеанса (считайте свои записи), в любое время использование . Пожалуйста, см. также введение непротиворечивости и уровень обслуживания.
Пример 22.246. Резюме: качество службы, чтобы запросить чтение Ваши записи
/* Request session consistency: read your writes */if (!mysqlnd_ms_set_qos($mysqli, MYSQLND_MS_QOS_CONSISTENCY_SESSION)) die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));
Принятию PECL/mysqlnd явно сказали не поставить уровень непротиворечивости выше чем возможная непротиворечивость, возможно заменить доступ для чтения узла базы данных клиентским кэшем, использующим время-к-живому (TTL) в качестве его стратегии аннулирования. И узел базы данных и кэш могут или, возможно, не служат текущим данным, поскольку это - то, что определяет возможная непротиворечивость.
Замена доступа для чтения узла базы данных с локальным доступом кэша может улучшить общую производительность и понизить загрузку базы данных. Если запись кэша является каждым снова использованным другими клиентами чем та, создающая запись кэша, доступ к базе данных сохраняется, и таким образом загрузка базы данных понижается. Кроме того производительность системы может стать лучше, если вычисление и поставка запроса базы данных медленнее чем локальный доступ кэша.
Пример 22.247. Сменная конфигурация: никакие специальные записи для того, чтобы кэшироваться
{ "myapp": { "master": { "master_0": { "host": "localhost", "socket": "\/tmp\/mysql.sock" } }, "slave": { "slave_0": { "host": "127.0.0.1", "port": "3306" } }, }}
Пример 22.248. Кэширование ведомого запроса
<?php$mysqli = new mysqli("myapp", "username", "password", "database");if (!$mysqli) /* 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)") || !$mysqli->query("INSERT INTO test(id) VALUES (1)")) die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));/* Explicitly allow eventual consistency and caching (TTL <= 60 seconds) */if (false == mysqlnd_ms_set_qos($mysqli, MYSQLND_MS_QOS_CONSISTENCY_EVENTUAL, MYSQLND_MS_QOS_OPTION_CACHE, 60)) { die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));}/* To make this example work, we must wait for a slave to catch up. Brute force style. */$attempts = 0;do { /* check if slave has the table */ if ($res = $mysqli->query("SELECT id FROM test")) { break; } else if ($mysqli->errno) { die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error)); } /* wait for slave to catch up */ usleep(200000);} while ($attempts++ < 10);/* Query has been run on a slave, result is in the cache */assert($res);var_dump($res->fetch_assoc());/* Served from cache */$res = $mysqli->query("SELECT id FROM test");?>
Пример показывает, как использовать функцию кэша. Во-первых, необходимо установить качество службы к
возможной непротиворечивости и явно учесть кэширование. Это делается, вызывая mysqlnd_ms_set_qos. Затем, набор результатов каждого оператора только
для чтения кэшируется для upto что много секунд как позволено с mysqlnd_ms_set_qos.
Фактический TTL ниже или равен набору значений с mysqlnd_ms_set_qos. Значение, которое передают к функции, устанавливает
максимальный возраст (секунды) поставленных данных. Чтобы вычислить фактический TTL оценивают задержку
репликации ведомым устройством, проверяется и вычитается из данного значения. Если, например, максимальный
возраст устанавливается в 60 секунд, и ведомое устройство сообщает о задержке 10 секунд, получающийся TTL
составляет 50 секунд. TTL вычисляется индивидуально для каждого кэшируемого запроса.
Пример 22.249. Считайте свои записи и кэширование объединенного
<?php$mysqli = new mysqli("myapp", "username", "password", "database");if (!$mysqli) /* 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)") || !$mysqli->query("INSERT INTO test(id) VALUES (1)")) die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));/* Explicitly allow eventual consistency and caching (TTL <= 60 seconds) */if (false == mysqlnd_ms_set_qos($mysqli, MYSQLND_MS_QOS_CONSISTENCY_EVENTUAL, MYSQLND_MS_QOS_OPTION_CACHE, 60)) { die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));}/* To make this example work, we must wait for a slave to catch up. Brute force style. */$attempts = 0;do { /* check if slave has the table */ if ($res = $mysqli->query("SELECT id FROM test")) { break; } else if ($mysqli->errno) { die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error)); } /* wait for slave to catch up */ usleep(200000);} while ($attempts++ < 10);assert($res);/* Query has been run on a slave, result is in the cache */var_dump($res->fetch_assoc());/* Served from cache */if (!($res = $mysqli->query("SELECT id FROM test"))) die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));var_dump($res->fetch_assoc());/* Update on master */if (!$mysqli->query("UPDATE test SET id = 2")) die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));/* Read your writes */if (false == mysqlnd_ms_set_qos($mysqli, MYSQLND_MS_QOS_CONSISTENCY_SESSION)) { die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));}/* Fetch latest data */if (!($res = $mysqli->query("SELECT id FROM test"))) die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));var_dump($res->fetch_assoc());?>
Качество службы может быть изменено в любое время, чтобы избежать дальнейшего использования кэша. Если нужно можно переключиться, чтобы считать Ваши записи (непротиворечивость сеанса). В этом случае кэш не будет использоваться, и новые данные читаются.
Copyright 1997-2012 PHP Documentation Group.
По умолчанию плагин не пытается перестать работать, если соединение с узлом перестало работать. Это предотвращает ловушки, связанные с состоянием соединения. Рекомендуется вручную обработать ошибки соединения в пути, подобном отказавшей транзакции. Следует зафиксировать ошибку, восстановить состояние соединения и запустить повторно Ваш запрос как показано ниже.
Если состояние соединения не является никакой проблемой Вам, можно альтернативно включить автоматическому и тихому failover. В зависимости от конфигурации автоматический и тихий failover или попытается перестать работать ведущему устройству прежде, чем выйти и ошибка или, попытаться соединиться с другими ведомыми устройствами, учитывая запрос allowes для этого, прежде, чем попытаться соединиться с ведущим устройством. Поскольку автоматический failover не является надежным, он не обсуждается в быстром запуске. Вместо этого детали даются в разделе понятий ниже.
Пример 22.250. Руководство failover, автоматический дополнительный
{ "myapp": { "master": { "master_0": { "host": "localhost", "socket": "\/tmp\/mysql.sock" } }, "slave": { "slave_0": { "host": "simulate_slave_failure", "port": "0" }, "slave_1": { "host": "127.0.0.1", "port": 3311 } }, "filters": { "roundrobin": [] } } }
Пример 22.251. Руководство failover
<?php$mysqli = new mysqli("myapp", "username", "password", "database");if (!$mysqli) /* Of course, your error handling is nicer... */ die(sprintf("[%d] %s\n", mysqli_connect_errno(), mysqli_connect_error()));$sql = "SELECT 1 FROM DUAL";/* error handling as it should be done regardless of the plugin */if (!($res = $link->query($sql))) { /* plugin specific: check for connection error */ switch ($link->errno) { case 2002: case 2003: case 2005: printf("Connection error - trying next slave!\n"); /* load balancer will pick next slave */ $res = $link->query($sql); break; default: /* no connection error, failover is unlikely to help */ die(sprintf("SQL error: [%d] %s", $link->errno, $link->error)); break; }}if ($res) { var_dump($res->fetch_assoc());}?>
Copyright 1997-2012 PHP Documentation Group.
Кластеризация базы данных делается по различным причинам. Кластеры могут улучшить доступность, отказоустойчивость, и увеличить производительность, применяя дележ и завоевать подход, поскольку работа распределяется по многим машинам. Кластеризация иногда объединяется с разделением и sharding, чтобы далее разбить большую сложную задачу в меньшие, более управляемые модули.
mysqlnd_ms плагин стремится поддерживать большое разнообразие кластеров базы данных MySQL. У некоторых разновидностей кластеров базы данных MySQL есть встроенные методы для разделения и sharding, который мог быть прозрачным, чтобы использовать. Плагин поддерживает два наиболее распространенных подхода: табличная фильтрация MySQL Replication, и Sharding (приложение базировало разделение).
MySQL Replication поддерживает разделение как фильтры, которые позволяют Вам создавать ведомые устройства,
которые тиражируют все или определенные базы данных ведущего устройства, или таблицы. Это находится тогда в
обязанности приложения выбрать ведомое устройство согласно правилам фильтра. Можно или использовать
mysqlnd_ms node_groups
фильтруйте, чтобы вручную поддерживать это, или использовать экспериментальный табличный фильтр.
Ручное разделение или sharding поддерживаются через фильтр группировки узла, и подсказки SQL с 1.5.0. Фильтр
node_groups позволяет Вам присваивать символьное имя группе основных и ведомых серверов. В примере, ведущем
устройстве master_0 и slave_0 сформируйте группу с
именем Partition_A. Полностью ваше дело решать то, что составляет группу.
Например, можно использовать группы узла для sharding, и использовать названия группы, чтобы адресовать
черепки как Shard_A_Range_0_100.
Пример 22.252. Группы узла кластера
{ "myapp": { "master": { "master_0": { "host": "localhost", "socket": "\/tmp\/mysql.sock" } }, "slave": { "slave_0": { "host": "simulate_slave_failure", "port": "0" }, "slave_1": { "host": "127.0.0.1", "port": 3311 } }, "filters": { "node_groups": { "Partition_A" : { "master": ["master_0"], "slave": ["slave_0"] } }, "roundrobin": [] } }}
Пример 22.253. Ручное разделение, используя подсказки SQL
<?phpfunction select($mysqli, $msg, $hint = '') { /* Note: weak test, two connections to two servers may have the same thread id */ $sql = sprintf("SELECT CONNECTION_ID() AS _thread, '%s' AS _hint FROM DUAL", $msg); if ($hint) { $sql = $hint . $sql; } if (!($res = $mysqli->query($sql))) { printf("[%d] %s", $mysqli->errno, $mysqli->error); return false; } $row = $res->fetch_assoc(); printf("%d - %s - %s\n", $row['_thread'], $row['_hint'], $sql); return true;}$mysqli = new mysqli("myapp", "user", "password", "database");if (!$mysqli) /* Of course, your error handling is nicer... */ die(sprintf("[%d] %s\n", mysqli_connect_errno(), mysqli_connect_error()));/* All slaves allowed */select($mysqli, "slave_0");select($mysqli, "slave_1");/* only servers of node group "Partition_A" allowed */select($mysqli, "slave_1", "/*Partition_A*/");select($mysqli, "slave_1", "/*Partition_A*/");?>
6804 - slave_0 - SELECT CONNECTION_ID() AS _thread, 'slave1' AS _hint FROM DUAL2442 - slave_1 - SELECT CONNECTION_ID() AS _thread, 'slave2' AS _hint FROM DUAL6804 - slave_0 - /*Partition_A*/SELECT CONNECTION_ID() AS _thread, 'slave1' AS _hint FROM DUAL6804 - slave_0 - /*Partition_A*/SELECT CONNECTION_ID() AS _thread, 'slave1' AS _hint FROM DUAL
По умолчанию плагин будет использовать все сконфигурированные основные и ведомые серверы для выполнения
запроса. Но если запрос начинается с подсказки SQL как /*node_group*/, плагин
будет только считать серверы перечисленными в node_group для выполнения
запроса. Таким образом, SELECT запросы, снабженные префиксом /*Partition_A*/ будет только выполняться на slave_0.