RussianLDP Рейтинг@Mail.ru
WebMoney: 
WMZ Z294115950220 
WMR R409981405661 
WME E134003968233 
Visa 
4274 3200 2453 6495 

Глава 7. MySQL Native Driver

MySQL Native Driver это замена для MySQL Client Library (libmysqlclient). MySQL Native Driver это часть официальных исходных текстов PHP с PHP 5.3.0.

Расширения базы данных MySQL mysqli и PDO MYSQL общаются с сервером MySQL. В прошлом это было сделано расширением, используя услуги, предоставленные MySQL Client Library. Расширения были собраны для MySQL Client Library, чтобы использовать ее протокол клиент-сервер.

С MySQL Native Driver есть теперь альтернатива, поскольку расширения базы данных MySQL могут быть собраны, чтобы использовать драйвер MySQL Native Driver вместо MySQL Client Library.

MySQL Native Driver написан на C как расширение PHP.

7.1. Обзор

Хотя MySQL Native Driver написан как расширение PHP, важно отметить, что это не предоставляет новый API PHP программисту. Программисту API для возможности соединения базы данных MySQL предоставляют расширения MySQL, mysqli и PDO MYSQL. Эти расширения могут теперь использовать услуги MySQL Native Driver, чтобы общаться с MySQL Server. Поэтому вы не должны думать о MySQL Native Driver как об API.

Почему это применяется?

Использование MySQL Native Driver предлагает много преимуществ перед пользованием MySQL Client Library.

MySQL Client Library написана MySQL AB (теперь куплена Oracle Corporation) и была открыта в соответствии с лицензией MySQL. Это в конечном счете поддержка MySQL, отключаемая по умолчанию в PHP. Однако, MySQL Native Driver был развит как часть проекта PHP и поэтому открыт в соответствии с лицензией PHP. Это удаляет проблемы лицензирования, которые были в прошлом.

Кроме того, в прошлом необходимо было построить расширения базы данных MySQL для MySQL Client Library. Это, как правило, означало, что необходимо было установить MySQL на машине, где вы строили исходный код PHP. Кроме того, когда работало ваше приложение PHP, расширения базы данных MySQL обращались к файлу MySQL Client library во время выполнения, таким образом, файл должен был быть установлен на вашей системе. С MySQL Native Driver это больше не имеет места, поскольку драйвер включен как часть стандартного дистрибутива. Таким образом, вам не нужен установленный MySQL, чтобы построить PHP или управлять приложениями базы данных PHP.

Так как MySQL Native Driver написан как расширение PHP, это сильно связано с работами PHP. Это приводит к росту эффективности, особенно когда дело доходит до использования памяти, поскольку драйвер использует систему управления памятью PHP. Это также поддерживает ограничения памяти PHP. Использование MySQL Native Driver приводит к сопоставимой или лучшей работе, чем MySQL Client Library, это всегда гарантирует наиболее эффективное использование памяти. Один пример эффективности памяти то, что, пользуясь MySQL Client Library, каждая строка сохранена в памяти дважды, тогда как с MySQL Native Driver только однажды.

Поскольку MySQL Native Driver использует систему управления памятью PHP, использование памяти может быть прослежено с помощью memory_get_usage. Это невозможно с libmysqlclient потому что он использует функцию C malloc().

Специальные функции

MySQL Native Driver также обеспечивает некоторые специальные функции, не доступные, когда расширения базы данных MySQL пользуются MySQL Client Library. Эти специальные функции упоминаются ниже:

Средство статистики может оказаться очень полезно в идентификации исполнительных узких мест.

MySQL Native Driver также допускает постоянные связи, когда используется с расширением mysqli.

Поддержка SSL

MySQL Native Driver понимает SSL с PHP version 5.3.3.

Поддержка сжатого протокола

С PHP 5.3.2 MySQL Native Driver поддерживает сжатый протокол клиент-сервера. MySQL Native Driver не поддерживал это в 5.3.0 и 5.3.1. Расширения вроде ext/mysql, ext/mysqli, которые настраиваются, чтобы использовать MySQL Native Driver, может также использовать в своих интересах эту особенность. Отметьте, что PDO_MYSQL НЕ поддерживает сжатие, когда используется вместе с mysqlnd.

Поддержка именованных каналов

Поддержка именованных каналов Windows была добавлена в PHP version 5.4.0.

7.2. Установка

Журнал изменений

Таблица 7.1. Журнал изменений

Версия Описание
5.3.0 MySQL Native Driver добавлен с поддержкой всех расширений MySQL (mysql, mysqli и PDO_MYSQL).
5.4.0 MySQL Native Driver теперь используется по умолчанию для всех расширений MySQL (mysql, mysqli and PDO_MYSQL).
5.5.0 Добавлена поддержка SHA-256 Authentication Plugin.

Установка в Unix

Расширения базы данных MySQL должны формироваться, чтобы пользоваться MySQL Client Library. Чтобы использовать MySQL Native Driver, PHP должен быть построен, определив, что расширения базы данных MySQL собраны с поддержкой MySQL Native Driver. Это сделано через параметры конфигурации до сборки исходного кода PHP.

Например, чтобы построить расширение MySQL mysqli или PDO MYSQL с MySQL Native Driver, следующая команда была бы дана:

./configure --with-mysql=mysqlnd \
            --with-mysqli=mysqlnd \
            --with-pdo-mysql=mysqlnd [other options]

Установка в Windows

В официальных дистрибутивах с PHP Windows с версии 5.3 MySQL Native Driver позволяют по умолчанию, таким образом, никакая дополнительная конфигурация не требуется, чтобы использовать его. Все расширения базы данных MySQL будут использовать MySQL Native Driver.

Поддержка SHA-256 Authentication Plugin

MySQL Native Driver требует, чтобы функциональность OpenSSL PHP была загружена и позволяла соединиться с MySQL через учетные записи, которые используют MySQL SHA-256 Authentication Plugin. Например, PHP мог формироваться, используя:

./configure --with-mysql=mysqlnd --with-mysqli=mysqlnd \
            --with-pdo-mysql=mysqlnd \
            --with-openssl [other options]

7.3. Конфигурация во время выполнения

Поведение этих функций затронуто параметрами настройки в php.ini.

Таблица 7.2. Опции MySQL Native Driver

ИмяПо умолчанию Изменяемая?Журнал изменений
mysqlnd.collect_statistics "1"PHP_INI_SYSTEMДоступно с PHP 5.3.0.
mysqlnd.collect_memory_statistics "0"PHP_INI_SYSTEMДоступно с PHP 5.3.0.
mysqlnd.debug ""PHP_INI_SYSTEMДоступно с PHP 5.3.0.
mysqlnd.log_mask0 PHP_INI_ALLДоступно с PHP 5.3.0
mysqlnd.mempool_default_size 16000PHP_INI_ALLДоступно с PHP 5.3.3
mysqlnd.net_read_timeout"86400" PHP_INI_ALLДоступно с PHP 5.3.0. До PHP 7.2.0 значение по умолчанию было "31536000" и настраивалось через PHP_INI_SYSTEM.
mysqlnd.net_cmd_buffer_size 5.3.0 - "2048", 5.3.1 - "4096" PHP_INI_SYSTEMДоступно с PHP 5.3.0.
mysqlnd.net_read_buffer_size"32768" PHP_INI_SYSTEMДоступно с PHP 5.3.0.
mysqlnd.sha256_server_public_key ""PHP_INI_PERDIRДоступно с PHP 5.5.0.
mysqlnd.trace_alloc"" PHP_INI_SYSTEMДоступно с PHP 5.5.0.
mysqlnd.fetch_data_copy0 PHP_INI_ALLДоступно с PHP 5.6.0.

Для получения дальнейшей информации и определения режимов PHP_INI_* см. http://www.php.net/manual/en/configuration.changes.modes.

Вот короткое объяснение конфигурационных директив.

mysqlnd.collect_statistics boolean

Позволяет сбор различной статистики клиента, к которой можно получить доступ через mysqli_get_client_stats, mysqli_get_connection_stats, mysqli_get_cache_stats и просмотр в разделе mysqlnd функции phpinfo.

Этот параметр конфигурации позволяет всю статистику MySQL Native Driver кроме того, что касается управления памятью.

mysqlnd.collect_memory_statistics boolean

Позвольте сбор различной статистики памяти, к которой можно получить доступ через mysqli_get_client_stats, mysqli_get_connection_stats, mysqli_get_cache_stats и в секции mysqlnd вывода функции phpinfo.

Этот параметр конфигурации позволяет статистику управления памятью в полном наборе MySQL Native Driver statistics.

mysqlnd.debug string

Писать данные всего использования расширений mysqlnd в указанный файл журнала.

Формат директивы mysqlnd.debug = "option1[,parameter_option1][:option2[,parameter_option2]]".

Возможности для строки формата следующие:

  • A[,file] - Прилагает вывод трассировки к указанному файлу. Также гарантирует, что данные сохранены после каждой записи. Это сделано, закрыв и вновь открыв файл трассировки (это медленно). Это помогает гарантировать, чтобы полный файл журнала был сохранен при сбое приложения.

  • a[,file] - Прилагает вывод трассировки к указанному файлу.

  • d - Позволяет вывод из макроса DBUG_<N> для текущего состояния. Может сопровождаться списком ключевых слов, который выбирает вывод только для макроса DBUG с тем ключевым словом. Пустой список ключевых слов подразумевает вывод для всего макроса.

  • f[,functions] - Ограничивает действия отладчика к указанному списку функций. Пустой список функций подразумевает, что все функции выбраны.

  • F - Отмечает каждую строку вывода отладчика названием исходного файла, содержащего макрос, вызывающий вывод.

  • i - Отмечает каждую строку вывода отладчика PID текущего процесса.

  • L - Отмечает каждую строку вывода отладчика номером строки исходного файла макроса, вызывающего вывод.

  • n - Отмечает каждую строку вывода отладчика текущей глубиной вложения функции.

  • o[,file] - Аналог a[,file], но переписывает старый файл.

  • O[,file] - Аналог A[,file], но переписывает старый файл.

  • t[,N] - Позволяет отслеживание потока управления функции. Максимальная глубина вложения определяется N и по умолчанию 200.

  • x - Этот выбор активирует профилирование.

  • m - Трассировка распределения и освобождения памяти данных.

Например:

d:t:x:O,/tmp/mysqlnd.trace

Эта особенность доступна только с отладочной сборкой PHP. Работает в Microsoft Windows, используя отладочную сборку PHP, если PHP был построен, используя Microsoft Visual C 9 и выше.

mysqlnd.log_mask integer

Определяет, какие запросы будут зарегистрированы. Умолчание 0, отключает регистрацию. Определите с использованием целого числа, а не констант PHP. Например, 48 (16 + 32) зарегистрирует медленные запросы, которые используют 'no good index' (SERVER_QUERY_NO_GOOD_INDEX_USED = 16) или или не используют никакой индекс вообще (SERVER_QUERY_NO_INDEX_USED = 32). Значение 2043 (1 + 2 + 8 + ... + 1024) зарегистрирует все типы медленного запроса.

Типы следующие: SERVER_STATUS_IN_TRANS=1, SERVER_STATUS_AUTOCOMMIT=2, SERVER_MORE_RESULTS_EXISTS=8, SERVER_QUERY_NO_GOOD_INDEX_USED=16, SERVER_QUERY_NO_INDEX_USED=32, SERVER_STATUS_CURSOR_EXISTS=64, SERVER_STATUS_LAST_ROW_SENT=128, SERVER_STATUS_DB_DROPPED=256, SERVER_STATUS_NO_BACKSLASH_ESCAPES=512 и SERVER_QUERY_WAS_SLOW=1024.

mysqlnd.mempool_default_size integer

Размер по умолчанию пула памяти, который используется наборами результатов.

mysqlnd.net_read_timeout integer

mysqlnd и MySQL Client Library, libmysqlclient используют различный сетевой API. mysqlnd использует потоки PHP, тогда как libmysqlclient использует собственную обертку вокруг операционных вызовов уровня сети. PHP по умолчанию устанавливает для потоков тайм-аут 60 секунд. Это установлено через php.ini, default_socket_timeout. Это относится ко всем потокам, которые не устанавливают никакое другое значение. mysqlnd не устанавливает никакое другое значение, и поэтому связи длительных запросов могут быть разъединены после default_socket_timeout секунд, приводя к сообщению об ошибке 2006 - MySQL Server has gone away. MySQL Client Library устанавливает тайм-аут 24 * 3600 секунд (1 день) и ждет других тайм-аутов, например, тайм-ауты TCP/IP. mysqlnd теперь использует тот же самый очень длинный тайм-аут. Значение конфигурируемо через новую опцию php.ini mysqlnd.net_read_timeout. mysqlnd.net_read_timeout используется любым расширением (ext/mysql, ext/mysqli, PDO_MySQL), которое использует mysqlnd. mysqlnd предписывает PHP Streams использовать mysqlnd.net_read_timeout. Обратите внимание на то, что могут быть тонкие различия между MYSQL_OPT_READ_TIMEOUT из MySQL Client Library и PHP Streams, Например, MYSQL_OPT_READ_TIMEOUT зарегистрирован, чтобы работать только на связи TCP/IP и, до MySQL 5.1.2, только для Windows. У потоков PHP может не быть этого ограничения. Пожалуйста, проверьте документацию потоков, если сомневаетесь.

mysqlnd.net_cmd_buffer_size integer

mysqlnd ассигнует внутренний буфер команд/сети mysqlnd.net_cmd_buffer_sizephp.ini) байт для каждой связи. Если команда протокола MySQL Client Server, например, COM_QUERY (нормальный запрос), не вписывается в буфер, mysqlnd вырастит буфер к размеру, требуемому для отправки команды. Каждый раз, когда буфер расширен для одной связи, command_buffer_too_small растет на единицу.

Если mysqlnd должен вырастить буфер вне его начального размера в mysqlnd.net_cmd_buffer_size байт для почти каждой связи, необходимо полагать, что увеличение размера по умолчанию позволит избегать перераспределений.

Размер буфера по умолчанию составляет 2048 байтов в PHP 5.3.0. В более поздних версиях умолчание составляет 4096 байтов.

Рекомендуется, чтобы размер буфера был установлен в не менее, чем 4096 байтов потому, что mysqlnd также использование это, читая определенный коммуникационный пакет от MySQL. В PHP 5.3.0 mysqlnd не вырастит буфер, если MySQL пошлет пакет, который больше, чем текущий размер буфера. Как следствие, mysqlnd не способен расшифровать пакет, и клиентское приложение получит ошибку. Есть только две ситуации, когда пакет может быть больше, чем 2048 байтов в mysqlnd.net_cmd_buffer_size в PHP 5.3.0: пакет транспортирует очень длинное сообщение об ошибке, или пакет содержит метаданные колонки от COM_LIST_FIELD (mysql_list_fields() и метаданные прибывают из колонки последовательности с очень длинным значением по умолчанию (>1900 байт).

С PHP 5.3.2 mysqlnd не позволяет устанавливать буфера меньшего размера, чем 4096 байтов.

Значение может также быть установлено, используя mysqli_options(link, MYSQLI_OPT_NET_CMD_BUFFER_SIZE, size).

mysqlnd.net_read_buffer_size integer

Максимальный прочитанный размер куска в байтах, читая тело пакета команд MySQL. Протокол клиент-сервера MySQL заключает в капсулу все свои команды в пакетах. Пакеты состоят из маленького заголовка и тела с фактическим полезным грузом. Размер тела закодирован в заголовке. mysqlnd читает тело кусками в MIN(header.size, mysqlnd.net_read_buffer_size) байт. Если тело пакета больше, чем mysqlnd.net_read_buffer_size байт, mysqlnd должен вызвать read() многократно.

Значение может также быть установлено, используя mysqli_options(link, MYSQLI_OPT_NET_READ_BUFFER_SIZE, size).

mysqlnd.sha256_server_public_key string

SHA-256 Authentication Plugin. Файл с публичным ключом RSA сервера MySQL.

Клиенты могут пропустить установку публичного ключа RSA, определяя ключ через этот параметр конфигурации PHP или устанавливать ключ при использовании во время выполнения mysqli_options. Если файл публичных ключей RSA не будет дан клиентом, то ключ будет получен как часть стандартной процедуры аутентификации SHA-256 Authentication Plugin.

mysqlnd.trace_alloc string

mysqlnd.fetch_data_copy integer

Выполнить копирование наборов результатов от внутренних буферов набора результатов в переменные PHP вместо того, чтобы использовать ссылку по умолчанию и логику copy-write. Пожалуйста, посмотрите подробности здесь.

Копирование наборов результатов вместо того, чтобы иметь ссылку переменных PHP позволяет освободить память, занятую для переменных PHP, раньше. В зависимости от кода API, фактических запросов базы данных и размера их наборов результатов, это может уменьшить объем потребляемой памяти mysqlnd.

Не устанавливайте, используя PDO_MySQL. PDO_MySQL еще не был обновлен, чтобы поддержать новый режим получения.

7.4. Несовместимости

MySQL Native Driver в большинстве случаев совместим с MySQL Client Library (libmysql). Эта секция несовместимости документов между этими библиотеками.

  • Значения типа данных bit возвращен как двоичные строки (например, "\0" или "\x1F") с libmysql или как десятичные последовательности (например, "0" или "31") с mysqlnd. Если вы хотите, чтобы код был совместим с обеими библиотеками, тогда всегда возвращайте битовые поля как числа из MySQL для запросов вроде этого: SELECT bit + 0 FROM table.

7.5. Постоянные связи

Используя постоянные связи

Если mysqli используется с mysqlnd, когда постоянная связь создается, она производит вызов COM_CHANGE_USER (mysql_change_user()). Это гарантирует, что переидентификация связи происходит.

Так как есть издержки, связанные с вызовом COM_CHANGE_USER, возможно выключить это во время компиляции. Многократное использование постоянной связи тогда произведет вызов COM_PING (mysql_ping) просто, чтобы проверить, можно ли повторно использовать связь.

Выключить COM_CHANGE_USER можно параметром компиляции MYSQLI_NO_CHANGE_USER_ON_PCONNECT:

shell# CFLAGS="-DMYSQLI_NO_CHANGE_USER_ON_PCONNECT"
shell# ./configure --with-mysql=/usr/local/mysql/ \
                   --with-mysqli=/usr/local/mysql/bin/mysql_config \
                   --with-pdo-mysql=/usr/local/mysql/bin/mysql_config \
                   --enable-debug && make clean && make -j6

Или:

shell# export CFLAGS="-DMYSQLI_NO_CHANGE_USER_ON_PCONNECT"
shell# configure --whatever-option
shell# make clean
shell# make

Отметьте, что только mysqli в mysqlnd применяет COM_CHANGE_USER. Другие драйверы применяют COM_PING на начальном использовании постоянной связи.

7.6. Статистика

Используя статистические данные

MySQL Native Driver содержит поддержку сбора статистики по связи между клиентом и сервером. Собранные статистические данные имеют два главных типа:

  • Статистика клиента.

  • Статистика связи.

При использовании mysqli эти статистические данные могут быть получены через два вызова API:

Статистические данные соединены среди всех расширений, которые используют MySQL Native Driver. Например, собирая ext/mysql и ext/mysqli с MySQL Native Driver, оба вызова функции ext/mysql и ext/mysqli изменят статистику. Нет никакого способа узнать, насколько определенный вызов API любого расширения, которое было собрано с MySQL Native Driver, повлиял на определенную статистическую величину. Можно формировать драйвер PDO MySQL, ext/mysql и ext/mysqli, чтобы произвольно использовать MySQL Native Driver. Делая так, все три расширения изменят статистику.

Доступ к статистике клиента

Для доступа к статистике клиента необходимо вызвать mysqli_get_client_stats. Вызов функции не требует никаких параметров.

Функция возвращает ассоциативный массив, который содержит название статистической величины как ключ и статистические данные как значение.

К статистике клиента можно также получить доступ, вызывая phpinfo.

Доступ к статистике связи

Для доступа к статистике связи вызовите mysqli_get_connection_stats. Это берет дескриптор соединения с базой данных в качестве параметра.

Функция возвращает ассоциативный массив, который содержит название статистической величины как ключ и статистические данные как значение.

Буферизованные и небуферизированные наборы результатов

Наборы результатов могут быть буферизованными или не буферизированными. Используя настройки по умолчанию, ext/mysql и ext/mysqli работают с буферизированными наборами результатов для нормальных (не подготовленных) запросов. Буферизированные наборы результатов кэшируются на клиенте. После выполнения запросов все результаты получены от MySQL Server и сохранены в кэше на клиенте. Большое преимущество буферизированных наборов результатов состоит в том, что они позволяют серверу освобождать все ресурсы, ассигнованные набору результатов, когда результаты были забраны клиентом.

Небуферизированные наборы результатов, с другой стороны, сохранены намного более длительно на сервере. Если вы хотите уменьшить потребление памяти на клиенте ценой увеличения нагрузки на сервер, используйте небуферизированные результаты. Если вы испытываете высокую нагрузку на сервера и число небуферизированных наборов результатов высоко, необходимо рассмотреть перемещение нагрузки клиентам. Клиенты, как правило, масштабируются лучше, чем серверы. Нагрузка относится не только к буферам памяти: сервер также должен сохранять другие ресурсы открытыми, например, дескрипторы файлов и потоки прежде, чем набор результатов сможет быть освобожден.

Подготовленные запросы используют небуферизированные наборы результатов по умолчанию. Однако, можно использовать mysqli_stmt_store_result, чтобы позволить буферизованные наборы результатов.

Статистика, возвращенная MySQL Native Driver

Следующие таблицы показывают список статистики, возвращенной функциями mysqli_get_client_stats и mysqli_get_connection_stats.

Таблица 7.3. Статистика mysqlnd: сеть

Значение Область действияОписание Примечания
bytes_sent ConnectionЧисло байтов, посланных PHP на сервер MySQL. Может использоваться, чтобы проверить эффективность протокола сжатия.
bytes_received ConnectionЧисло байтов, полученных от сервера MySQL. Может использоваться, чтобы проверить эффективность протокола сжатия.
packets_sent Connection Количество переданных пакетов протокола MySQL Client Server. Используется для отладки внедрения протокола Client Server.
packets_received Connection Количество полученных пакетов протокола MySQL Client Server. Используется для отладки внедрения протокола Client Server.
protocol_overhead_in Connection Издержки протокола MySQL Client в байтах для входящего трафика. В настоящее время только Packet Header (4 байта) рассматривают как издержки. protocol_overhead_in = packets_received * 4 Используется для отладки внедрения протокола Client Server.
protocol_overhead_out Connection Издержки протокола MySQL Client в байтах для исходящего трафика. В настоящее время только Packet Header (4 байта) рассматривают как издержки. protocol_overhead_out = packets_sent * 4 Используется для отладки внедрения протокола Client Server.
bytes_received_ok_packet Connection Полный размер в байтах протокола полученных пакетов OK протокола MySQL Client Server. OK-пакеты могут содержать сообщение о состоянии. Длина сообщения о состоянии может измениться, и таким образом размер пакета OK не фиксирован. Используется для отладки внедрения протокола Client Server. Обратите внимание на то, что полный размер в байтах включает размер заголовка пакета (4 байта, см. издержки протокола).
packets_received_ok Connection Количество принятых пакетов OK MySQL Client Server. Используется для отладки внедрения протокола Client Server. Обратите внимание на то, что полный размер в байтах включает размер заголовка пакета (4 байта, см. издержки протокола).
bytes_received_eof_packet Connection Полный размер в байтах принятых пакетов EOF MySQL Client Server. EOF может измениться по размеру в зависимости от версии сервера. Кроме того, EOF может транспортировать сообщение об ошибке. Используется для отладки внедрения протокола Client Server. Обратите внимание на то, что полный размер в байтах включает размер заголовка пакета (4 байта, см. издержки протокола).
packets_received_eof Connection Число принятых пакетов EOF MySQL Client Server. Как с другой статистикой пакетов, будет увеличено число пакетов, даже если PHP получит не ожидаемый пакет, а, например, сообщение об ошибке. Используется для отладки внедрения протокола Client Server. Обратите внимание на то, что полный размер в байтах включает размер заголовка пакета (4 байта, см. издержки протокола).
bytes_received_rset_header_packet Connection Полный размер в байтах пакетов заголовка набора результатов протокола MySQL Client Server. Размер пакетов варьируется в зависимости от полезного груза (LOAD LOCAL INFILE, INSERT, UPDATE, SELECT, сообщение об ошибке). Используется для отладки внедрения протокола Client Server. Обратите внимание на то, что полный размер в байтах включает размер заголовка пакета (4 байта, см. издержки протокола).
packets_received_rset_header Connection Количество пакетов заголовка набора результатов протокола MySQL Client Server. Используется для отладки внедрения протокола Client Server. Обратите внимание на то, что полный размер в байтах включает размер заголовка пакета (4 байта, см. издержки протокола).
bytes_received_rset_field_meta_packet Connection Полный размер в байтах пакетов метаданных набора результатов (полевая информация) протокола Client Server. Конечно, размер меняется в зависимости от полей в наборе результатов. Пакет может также транспортировать ошибку или пакет EOF в случае COM_LIST_FIELDS. Полезно для отладки внедрения протокола CS. Обратите внимание на то, что полный размер в байтах включает размер заголовка пакета (4 байта, см. издержки протокола).
packets_received_rset_field_meta Connection Количество пакетов метаданных набора результатов протокола MySQL Client Server (полевая информация). Полезно для отладки внедрения протокола CS. Обратите внимание на то, что полный размер в байтах включает размер заголовка пакета (4 байта, см. издержки протокола).
bytes_received_rset_row_packet Connection Полный размер в байтах пакетов данных о строках набора результатов протокола MySQL Client Server. Пакет может также транспортировать ошибку или пакет EOF. Можно узнать количество ошибок и пакетов EOF, вычтя rows_fetched_from_server_normal и rows_fetched_from_server_ps из bytes_received_rset_row_packet. Полезно для отладки внедрения протокола CS. Обратите внимание на то, что полный размер в байтах включает размер заголовка пакета (4 байта, см. издержки протокола).
packets_received_rset_row Connection Количество пакетов данных о строках набора результатов протокола MySQL Client Server и их полный размер в байтах. Полезно для отладки внедрения протокола CS. Обратите внимание на то, что полный размер в байтах включает размер заголовка пакета (4 байта, см. издержки протокола).
bytes_received_prepare_response_packet Connection Полный размер в байтах OK-пакетов протокола MySQL Client Server для пакетов инициализации подготовленных запросов. Пакет может также транспортировать ошибку. Размер пакета зависит от версии MySQL: 9 байтов с MySQL 4.1 и 12 байтов с MySQL 5.0. Нет никакого безопасного способа узнать, сколько ошибок произошло. Можно быть в состоянии предположить, что ошибка произошла, если, например, вы всегда соединяетесь с MySQL 5.0 или более новым, но bytes_received_prepare_response_packet != packets_received_prepare_response * 12. См. также ps_prepared_never_executed, ps_prepared_once_executed. Полезно для отладки внедрения протокола CS. Обратите внимание на то, что полный размер в байтах включает размер заголовка пакета (4 байта, см. издержки протокола).
packets_received_prepare_response Connection Количество OK-пакетов протокола MySQL Client Server для пакетов инициализации подготовленных запросов. Полезно для отладки внедрения протокола CS. Обратите внимание на то, что полный размер в байтах включает размер заголовка пакета (4 байта, см. издержки протокола).
bytes_received_change_user_packet Connection Полный размер в байтах пакетов COM_CHANGE_USER протокола MySQL Client Server. Пакет может также транспортировать ошибку или EOF. Полезно для отладки внедрения протокола CS. Обратите внимание на то, что полный размер в байтах включает размер заголовка пакета (4 байта, см. издержки протокола).
packets_received_change_user ConnectionКоличество пакетов COM_CHANGE_USER. Полезно для отладки внедрения протокола CS. Обратите внимание на то, что полный размер в байтах включает размер заголовка пакета (4 байта, см. издержки протокола).
packets_sent_command Connection Количество команд протокола MySQL Client Server, посланных PHP в MySQL. Нет никакого способа узнать, какие определенные команды и сколько их послали. Можно использовать его, чтобы проверить, послал ли PHP какие-либо команды в MySQL, чтобы узнать, можно ли рассмотреть отключение поддержки MySQL в двоичных модулях PHP. Нет также никакого способа узнать количество ошибок, которые, возможно, произошли, посылая данные в MySQL. Единственная ошибка, которая зарегистрирована, является command_buffer_too_small. Полезно для отладки внедрения протокола CS. Обратите внимание на то, что полный размер в байтах включает размер заголовка пакета (4 байта, см. издержки протокола).
bytes_received_real_data_normal Connection Число байтов полезного груза, принесенного клиентом PHP от mysqlnd с использованием текстового протокола. Это размер фактических данных, содержавшихся в наборах результатов, которые не происходят из подготовленных запросов и которые были получены клиентом PHP. Отметьте что, хотя полный набор результатов, возможно, вынули из MySQL через mysqlnd, эта статистическая величина считает только фактические данные из mysqlnd клиентом PHP. Пример кода, который увеличит значение:
$mysqli = new mysqli();
$res = $mysqli->query("SELECT 'abc'");
$res->fetch_assoc();
$res->close();

Каждая операция получения увеличит значение.

Статистическая величина не будет увеличена, если набор результатов будет только буферизован на клиенте, но не получен, как в следующем примере:

$mysqli = new mysqli();
$res = $mysqli->query("SELECT 'abc'");
$res->close();

Эта статистическая величина доступна с версии PHP 5.3.4.

bytes_received_real_data_ps Connection Число байтов полезного груза, принесенного клиентом PHP от mysqlnd с использованием протокола подготовленного запроса. Это размер фактических данных, содержавшихся в наборах результатов, которые происходят из подготовленных запросов и которые были принесены клиентом PHP. Значение не будет увеличено, если набор результатов не будет впоследствии прочитан клиентом PHP. Отметьте что, хотя полный набор результатов, возможно, получили из MySQL через mysqlnd, эта статистическая величина считает только фактические данные полученные из mysqlnd клиентом PHP. См. также bytes_received_real_data_normal. Эта статистическая величина доступна с версии PHP 5.3.4.

Набор результатов

Таблица 7.4. Возвращенная mysqlnd статистика: набор результатов

ИмяОбласть действия ОписаниеПримечания
result_set_queries Connection Количество запросов, которые произвели набор результатов. Примеры запросов, которые производят набор результатов: SELECT, SHOW. Статистическая величина не будет увеличена, если будет ошибка при чтении пакета заголовка набора результатов. Можно использовать в качестве косвенной меры для количества запросов, которые PHP послал в MySQL, например, чтобы опознать клиента, который вызывает высокую нагрузку базы данных.
non_result_set_queries Connection Количество запросов, которые не произвели набор результатов. Примеры запросов, которые не производят набор результатов: INSERT, UPDATE, LOAD DATA. Статистическая величина не будет увеличена, если будет ошибка при чтении пакета заголовка набора результатов. Можно использовать в качестве косвенной меры для количества запросов, которые PHP послал в MySQL, например, чтобы опознать клиента, который вызывает высокую нагрузку базы данных.
no_index_used Connection Количество запросов, которые произвели набор результатов, но не использовали индекс (см. также опцию запуска mysqld ─log-queries-not-using-indexes). Если вы хотите, чтобы эти запросы были сообщены, можно использовать mysqli_report(MYSQLI_REPORT_INDEX), чтобы заставить ext/mysqli бросить исключение. Если вы предпочитаете, чтобы было предупреждение вместо исключения, используйте mysqli_report(MYSQLI_REPORT_INDEX ^ MYSQLI_REPORT_STRICT).
bad_index_used Connection Количество запросов, которые произвели набор результатов и не использовали хороший индекс (см. также опцию запуска mysqld ─log-slow-queries). Если вы хотите, чтобы эти запросы были сообщены, можно использовать mysqli_report(MYSQLI_REPORT_INDEX), чтобы заставить ext/mysqli бросить исключение. Если вы предпочитаете, чтобы было предупреждение вместо исключения, используйте mysqli_report(MYSQLI_REPORT_INDEX ^ MYSQLI_REPORT_STRICT).
slow_queries Connection SQL-операторы, которые взяли больше, чем long_query_time секунд, чтобы выполниться и требуют по крайней мере min_examined_row_limit строк, которые будут исследованы. Не сообщается через mysqli_report.
buffered_sets Connection Количество буферизированных наборов результатов, возвращенное не подготовленными запросами в следующих примечаниях. Примеры вызовов API, которые буферизуют наборы результатов на клиенте: mysql_query, mysqli_query, mysqli_store_result, mysqli_stmt_get_result. Буферизование наборов результатов на клиенте гарантирует, что ресурсы сервера освобождены как можно скорее, и делает прокрутку набора результатов легче. Оборотная сторона дополнительное потребление памяти на клиенте для того, чтобы буферизовать данные. Обратите внимание на то, что mysqlnd (в отличие от MySQL Client Library) уважает предел памяти PHP, потому что это использует функции управления внутренней памятью PHP, чтобы ассигновать память. Это также причина почему memory_get_usage сообщает более высокое потребление памяти, используя mysqlnd вместо MySQL Client Library. memory_get_usage не измеряет потребление памяти MySQL Client Library вообще, потому что не использует функции управления внутренней памятью PHP!
unbuffered_sets Connection Количество небуферизированных наборов результатов, возвращенных нормальным (не подготовленным) запросом. Примеры вызовов API, которые не буферизуют наборы результатов на клиенте: mysqli_use_result.
ps_buffered_sets Connection Количество буферизированных наборов результатов, возвращенных подготовленными запросами. По умолчанию подготовленные запросы не буферизированы. Примеры вызовов API, которые буферизуют наборы результатов на клиенте: mysqli_stmt_store_result.
ps_unbuffered_sets Connection Количество небуферизированных наборов результатов, возвращенных подготовленными запросами. По умолчанию подготовленные запросы не буферизированы.
flushed_normal_sets Connection Количество наборов результатов от нормальных (не подготовленных) запросов с непрочитанными данными, которые тихо сброшены для вас. Это происходит только с небуферизированными наборами результатов. Небуферизированные наборы результатов должны быть полностью получены, прежде чем новым запросом можно управлять на связи, иначе MySQL бросит ошибку. Если приложение не приносит все строки от небуферизированного набора результатов, mysqlnd действительно неявно приносит набор результатов, чтобы очистить линию. См. также rows_skipped_normal, rows_skipped_ps. Некоторые возможные причины для неявного сброса:
  • Дефектное клиентское приложение.

  • Клиент прекратил читать после того, как нашел то, что искал, но заставил MySQL вычислить больше записей, чем необходимо.

  • Клиентское приложение неожиданно остановилось.

flushed_ps_sets Connection Количество наборов результатов из подготовленных запросов с непрочитанными данными, которые тихо сброшены. Это происходит только с небуферизированными наборами результатов. Небуферизированные наборы результатов должны быть полностью получены, прежде чем новым запросом можно управлять на связи, иначе MySQL бросит ошибку. Если приложение не приносит все строки от небуферизированного набора результатов, mysqlnd действительно неявно приносит набор результатов, чтобы очистить линию. См. также rows_skipped_normal, rows_skipped_ps. Некоторые возможные причины для неявного сброса:
  • Дефектное клиентское приложение.

  • Клиент прекратил читать после того, как нашел то, что искал, но заставил MySQL вычислить больше записей, чем необходимо.

  • Клиентское приложение неожиданно остановилось.

ps_prepared_never_executed Connection Количество подготовленных, но никогда не выполненных запросов. Подготовленные запросы занимают ресурсы сервера. Вы не должны готовить запрос, если вы не планируете выполнить его.
ps_prepared_once_executed Connection Количество подготовленных запросов, выполненных только один раз. Одна из идей подготовленных запросов то, что тот же самый запрос выполняется много раз (с различными параметрами) и некоторый парсинг и другая работа подготовки может быть сэкономлена, если выполнение запросы разделено на стадии подготовки и выполнения. Идея состоит в том, чтобы подготовить однажды и кэшировать результаты, например, дерево синтаксического анализа, которое будет снова использовано во время многократного выполнения запроса. Если вы выполняете подготовленный запрос только однажды, две стадии обработки могут быть неэффективными по сравнению с нормальными запросами, потому что все кэширование означает дополнительную работу, и это берет (ограниченные) ресурсы сервера, чтобы хранить информацию. Следовательно, подготовленные запросы, которые выполняются только однажды, могут вызвать вред для производительности.
rows_fetched_from_server_normal , rows_fetched_from_server_ps Connection Общее количество строк набора результатов успешно полученных от MySQL, независимо от того, потребляло их или нет клиентское приложение. Некоторые строки могли быть не получены клиентским приложением, но неявно сброшены. См. packets_received_rset_row.
rows_buffered_from_client_normal , rows_buffered_from_client_ps Connection Общее количество успешно буферизированных строк, происходящих из "нормального" запроса или подготовленного запроса. Это количество строк, которые были принесены от MySQL и буферизованы на клиенте. Обратите внимание на то, что есть два отличных статистических данных по строкам, которые были буферизованы (MySQL к mysqlnd внутреннему буферу) и буферизированные строки, которые были принесены клиентским приложением (внутренний буфер mysqlnd к клиентскому приложению). Если количество буферизированных строк выше, чем количество поученных буферизированных строк, это может означать, что клиентское приложение управляет запросами, которые вызывают большие наборы результатов, чем необходимо. Примеры запросов, которые буферизуют результаты: mysqli_query, mysqli_store_result.
rows_fetched_from_client_normal_buffered, rows_fetched_from_client_ps_buffered Connection Общее количество строк, принесенных клиентом от буферизированного набора результатов, созданного нормальным или подготовленным запросом.
rows_fetched_from_client_normal_unbuffered, rows_fetched_from_client_ps_unbuffered Connection Общее количество строк, принесенных клиентом от небуферизированного набора результатов, созданного "нормальным" или подготовленным запросом.
rows_fetched_from_client_ps_cursor Connection Общее количество строк, полученных клиентом от курсора, созданного подготовленным запросом.
rows_skipped_normal, rows_skipped_ps Connection Зарезервировано для будущего использования (в настоящее время не поддержано).
copy_on_write_saved, copy_on_write_performed Process С mysqlnd переменные, возвращенные расширениями, указывают в mysqlnd буфера результата внутренней сети. Если вы не замените переменные, принесенные данные будут сохранены только однажды в памяти. Если вы заменяете переменные, mysqlnd должен выполнить copy-write, чтобы защитить буферы результата внутренней сети от изменения. С MySQL Client Library вы всегда храните принесенные данные дважды в памяти. Один раз во внутренних буферах MySQL Client Library и один раз в переменных, возвращенных расширениями. В теории mysqlnd может сэкономить 40% памяти. Однако, обратите внимание на то, что экономия памяти не может быть измерена, используя memory_get_usage.
explicit_free_result, implicit_free_result Connection, Process (только во время очистки подготовленных запросов). Общее количество освобожденных наборов результатов. Освобжденные наборы результатов, но для наборов результатов, созданных командой init, например, mysqli_options(MYSQLI_INIT_COMMAND, ...) .
proto_text_fetched_null, proto_text_fetched_bit, proto_text_fetched_tinyint proto_text_fetched_short, proto_text_fetched_int24, proto_text_fetched_int proto_text_fetched_bigint, proto_text_fetched_decimal, proto_text_fetched_float proto_text_fetched_double, proto_text_fetched_date, proto_text_fetched_year proto_text_fetched_time, proto_text_fetched_datetime, proto_text_fetched_timestamp proto_text_fetched_string, proto_text_fetched_blob, proto_text_fetched_enum proto_text_fetched_set, proto_text_fetched_geometry, proto_text_fetched_other Connection Общее количество колонок определенного типа, принесенных от нормального запроса (текстовый протокол MySQL). Отображение C API/метаданных MySQL к имени статистики:
  • MYSQL_TYPE_NULL - proto_text_fetched_null

  • MYSQL_TYPE_BIT - proto_text_fetched_bit

  • MYSQL_TYPE_TINY - proto_text_fetched_tinyint

  • MYSQL_TYPE_SHORT - proto_text_fetched_short

  • MYSQL_TYPE_INT24 - proto_text_fetched_int24

  • MYSQL_TYPE_LONG - proto_text_fetched_int

  • MYSQL_TYPE_LONGLONG - proto_text_fetched_bigint

  • MYSQL_TYPE_DECIMAL, MYSQL_TYPE_NEWDECIMAL - proto_text_fetched_decimal

  • MYSQL_TYPE_FLOAT - proto_text_fetched_float

  • MYSQL_TYPE_DOUBLE - proto_text_fetched_double

  • MYSQL_TYPE_DATE, MYSQL_TYPE_NEWDATE - proto_text_fetched_date

  • MYSQL_TYPE_YEAR - proto_text_fetched_year

  • MYSQL_TYPE_TIME - proto_text_fetched_time

  • MYSQL_TYPE_DATETIME - proto_text_fetched_datetime

  • MYSQL_TYPE_TIMESTAMP - proto_text_fetched_timestamp

  • MYSQL_TYPE_STRING, MYSQL_TYPE_VARSTRING, MYSQL_TYPE_VARCHAR - proto_text_fetched_string

  • MYSQL_TYPE_TINY_BLOB, MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB, MYSQL_TYPE_BLOB - proto_text_fetched_blob

  • MYSQL_TYPE_ENUM - proto_text_fetched_enum

  • MYSQL_TYPE_SET - proto_text_fetched_set

  • MYSQL_TYPE_GEOMETRY - proto_text_fetched_geometry

  • Любые не перечисленные здесь типы MYSQL_TYPE_* (не должно быть ни одного) - proto_text_fetched_other

Обратите внимание на то, что константы MYSQL_* не могут быть связаны с теми же самыми типами столбца SQL в каждой версии MySQL.

proto_binary_fetched_null, proto_binary_fetched_bit, proto_binary_fetched_tinyint proto_binary_fetched_short, proto_binary_fetched_int24, proto_binary_fetched_int, proto_binary_fetched_bigint, proto_binary_fetched_decimal, proto_binary_fetched_float, proto_binary_fetched_double, proto_binary_fetched_date, proto_binary_fetched_year, proto_binary_fetched_time, proto_binary_fetched_datetime, proto_binary_fetched_timestamp, proto_binary_fetched_string, proto_binary_fetched_blob, proto_binary_fetched_enum, proto_binary_fetched_set, proto_binary_fetched_geometry, proto_binary_fetched_other Connection Общее количество колонок определенного типа, принесенных из подготовленного запроса (протокол двоичной синхронной передачи данных MySQL). Для отображения типов см. proto_text_* выше.

Таблица 7.5. Возвращенная mysqlnd статистика: Connection

ИмяОбласть действия ОписаниеПримечания
connect_success, connect_failure Connection Общее количество успешных/неудачных попыток подключения. Включены снова использованные связи и все другие виды связей.
reconnect Process Общее количество попыток (real_)connect, предпринятых на уже открытом дескрипторе связи. Кодовая последовательность $link = new mysqli(...); $link->real_connect(...) вызовет повторно подключение. Но $link = new mysqli(...); $link->connect(...) не вызовет, потому что $link->connect(...) явно закроет существующую связь, прежде чем новая связь будет установлена.
pconnect_success Connection Общее количество успешных постоянных попыток подключения. Заметьте, что connect_success хранит сумму успешных постоянных и непостоянных попыток подключения. Количество успешных непостоянных попыток подключения это connect_success - pconnect_success.
active_connections Connection Общее количество активных постоянных и непостоянных связей.
active_persistent_connections Connection Общее количество активных постоянных связей. Общее количество активных непостоянных связей это active_connections - active_persistent_connections.
explicit_close Connection Общее количество явно закрытых связей (только в ext/mysqli). Примеры фрагментов кода, которые вызывают явное завершение:
$link = new mysqli(...); $link->close(...)
$link = new mysqli(...); $link->connect(...)
implicit_close Connection Общее количество неявно закрытых связей (только ext/mysqli). Примеры фрагментов кода, которые вызывают неявное завершение:
  • $link = new mysqli(...); $link->real_connect(...)

  • unset($link)

  • Постоянная связь: объединенная связь была создана с real_connect и может быть неизвестный набор опций. Закрыта неявно, чтобы избежать возврата связи с неизвестными опциями.

  • Постоянная связь: ping/change_user терпит неудачу и ext/mysqli закрывает связь.

  • Конец выполнения скрипта: закрываются связи, которые не были закрыты пользователем.

disconnect_close Connection Неудачи связи обозначаются вызовом C API mysql_real_connect во время попытки установить связь. Это вызывает disconnect_close потому что дескриптор связи, переданный вызову C API, будет закрыт.
in_middle_of_command_close Process Связь была закрыта посреди выполнения команды (наборы результатов не получены после отправки запроса, прежде, чем получить ответ во время получения данных, передавая данные с LOAD DATA). Если вы не используете асинхронные запросы, это должно произойти только, если ваш скрипт неожиданно останавливается, и PHP закрывает связи.
init_command_executed_count Connection Общее количество выполненных команд init, например, mysqli_options(MYSQLI_INIT_COMMAND, ...). Количество успешного выполнения init_command_executed_count - init_command_failed_count.
init_command_failed_count Connection Общее количество неудавшихся команд init.

Таблица 7.6. Возвращенная mysqlnd статистика: команды COM_*

Имя Область действияОписание Примечания
com_quit, com_init_db, com_query, com_field_list, com_create_db, com_drop_db, com_refresh, com_shutdown, com_statistics, com_process_info, com_connect, com_process_kill, com_debug, com_ping, com_time, com_delayed_insert, com_change_user, com_binlog_dump, com_table_dump, com_connect_out, com_register_slave, com_stmt_prepare, com_stmt_execute, com_stmt_send_long_data, com_stmt_close, com_stmt_reset, com_stmt_set_option, com_stmt_fetch, com_daemon Connection Общее количество попыток послать определенную команду COM_* из PHP в MySQL.

Статистические данные увеличены после проверки связи и немедленно прежде, чем послать соответствующий пакет протокола клиент-сервера MySQL. Если mysqlnd не пошлет пакет, то статистика не будет уменьшена. В случае неудачи mysqlnd выпускает PHP-предупреждение Error while sending %s packet. PID=%d.

Примеры использования:

  • Проверьте, посылает ли PHP определенные команды в MySQL, например, проверка, что клиент посылает COM_PROCESS_KILL.

  • Вычислите среднее количество выполненных подготовленных запросов, сравнив COM_EXECUTE и COM_PREPARE.

  • Проверьте, управлял ли PHP какими-либо неподготовленными SQL-операторами, проверяя, что COM_QUERY = 0.

  • Определите скрипты PHP, которые управляют чрезмерным количеством SQL-операторов, проверяя COM_QUERY и COM_EXECUTE.

Прочее

Таблица 7.7. Возвращенная mysqlnd статистика: Miscellaneous

Имя Область действияОписание Примечания
explicit_stmt_close, implicit_stmt_close Process Общее количество закрытых подготовленных запросов.
mem_emalloc_count, mem_emalloc_ammount, mem_ecalloc_count, mem_ecalloc_ammount, mem_erealloc_count, mem_erealloc_ammount, mem_efree_count, mem_malloc_count, mem_malloc_ammount, mem_calloc_count, mem_calloc_ammount, mem_realloc_count, mem_realloc_ammount, mem_free_count Process Вызовы управления памятью. Только для разработчиков.
command_buffer_too_small Connection Количество сетевых расширений буфера команд, посылая команды от PHP в MySQL.

mysqlnd ассигнует внутренний буфер команд/сети в mysqlnd.net_cmd_buffer_size (php.ini) байт для каждой связи. Если команда протокола MySQL Client Server, например, COM_QUERY (нормальный запрос), не вписывается в буфер, mysqlnd вырастит буфер к тому, что необходимо для отправки команды. Каждый раз, когда буфер расширен для одной связи command_buffer_too_small будет увеличен на единицу.

Если mysqlnd должен вырастить буфер вне своего начального размера mysqlnd.net_cmd_buffer_size (php.ini) байт для почти каждой связи, необходимо рассмотреть, чтобы увеличить размер по умолчанию, чтобы избежать перераспределений.

Размер буфера по умолчанию составляет 2048 байтов в PHP 5.3.0. В будущих версиях размер составит 4 КБ или больше. Умолчание может изменяться через настройки в php.ini mysqlnd.net_cmd_buffer_size или через mysqli_options(MYSQLI_OPT_NET_CMD_BUFFER_SIZE, int size).

Рекомендуется установить размер буфера в не менее, чем 4096 байтов, потому что mysqlnd также использует его, читая определенный коммуникационный пакет от MySQL. В PHP 5.3.0 mysqlnd не вырастит буфер, если MySQL пошлет пакет, который больше, чем текущий размер буфера. Как следствие mysqlnd не способен декодировать пакет и клиентское приложение получит ошибку. Есть только две ситуации, когда пакет может быть больше, чем 2048-байтовое умолчание mysqlnd.net_cmd_buffer_size в PHP 5.3.0: пакет транспортирует очень длинное сообщение об ошибке, или пакет содержит метаданные колонки от COM_LIST_FIELD ( mysql_list_fields) и метаданные прибывают из колонки последовательности с очень длинным значением по умолчанию (>1900 байт). Никакого отчета об ошибках на этом не существует: это должно редко происходить.

С PHP 5.3.2 mysqlnd не позволяет устанавливать буфера, меньшего размера, чем 4096 байтов.

connection_reused

7.7. Примечания

Эта секция обеспечивает коллекцию разных примечаний по использованию MySQL Native Driver.

  • Использование mysqlnd означает применение потоков PHP в основе возможности соединения. Для mysqlnd и потоков PHP нужно консультироваться с документацией на (http://www.php.net/manual/en/book.stream) относительно таких деталей, как параметры настройки тайм-аута.

7.8. Управление памятью

Введение

MySQL Native Driver управляет памятью не так, как MySQL Client Library. Библиотеки отличаются по способу, которым память ассигнована и освобождена, как память ассигнуется в кусках, читая результаты из MySQL, какие опции отладки существуют и как результаты, прочитанные из MySQL, связаны с пользовательскими переменными PHP.

Следующие примечания предназначаются как введение и резюме пользователям, заинтересованным в понимании MySQL Native Driver на кодовом уровне C.

Функции управления памятью

Все выделение памяти и освобождение сделаны, используя функции управления памятью PHP. Поэтому потребление памяти mysqlnd может быть прослежено, используя вызовы API PHP, например, memory_get_usage. Поскольку память ассигнуется и освобождается с использованием управления памятью PHP, изменения могут не стать немедленно видимыми на уровне операционной системы. Управление памятью PHP действует как полномочие, которое может задержать возврат памяти системе. Из-за этого сравнение использования памяти MySQL Native Driver и MySQL Client Library трудное. MySQL Client Library использует требования управления памятью операционной системы непосредственно, следовательно эффекты могут немедленно наблюдаться на уровне операционной системы.

Любой предел памяти, проведенный в жизнь PHP, также затрагивает MySQL Native Driver. Это может вызвать ошибки памяти, получая большие наборы результатов, которые превышают размер объема оставшейся памяти, сделанного доступным для PHP. Поскольку MySQL Client Library не использует функции управления памятью PHP, она не соответствует никакому пределу памяти PHP. Пользуясь MySQL Client Library, в зависимости от модели развертывания, объем потребляемой памяти процесса PHP может вырасти вне предела памяти PHP. Но также и скрипты PHP могут быть в состоянии обработать большие наборы результатов, поскольку части памяти, ассигнованной, чтобы хранить наборы результатов, находятся вне контроля PHP.

Функции управления памятью PHP призваны MySQL Native Driver через легкую обертку. Среди прочего обертка делает отладку легче.

Обработка наборов результатов

Различные MySQL Server и клиентские API дифференцируются между буферизированными и небуферизированными наборами результатов. Небуферизированные наборы результатов переданы построчно от MySQL клиенту, поскольку клиент итерирует по результатам. Буферизированные результаты получены полностью библиотекой клиента перед передачей их клиенту.

MySQL Native Driver использует PHP Streams для сетевой связи с MySQL Server. Результаты, посланные MySQL, принесены от буферов сети PHP Streams в буфер результата mysqlnd. Буфер результата сделан на zvals. Во втором шаге результаты сделаны доступными для скрипта PHP. Эта заключительная передача от буфера результата в переменные PHP влияет на потребление памяти.

По умолчанию MySQL Native Driver пытается избежать хранить буферизованные результаты дважды в памяти. Результаты сохранены только однажды во внутренних буферах результата и zval. Когда результаты будут получены в переменные скрипта PHP, переменные сошлются на внутренние буферы результата. Результаты запроса базы данных не скопированы и сохранены в памяти только однажды. Если пользователь изменяет содержание переменной, содержащей результаты базы данных, копирование при записи должно быть выполнено, чтобы избежать изменения внутреннего буфера результата, на который ссылаются. Содержание буфера не должно быть изменено, потому что пользователь может решить прочитать набор результатов во второй раз. Механизм копирования осуществляется, используя дополнительный справочный список управления и счетчики ссылок zval. Это должно быть также сделано, если пользователь читает набор результатов в переменные PHP и освобождает набор результатов, прежде чем переменные будут сброшены.

Вообще говоря, этот образец работает хорошо на скриптах, которые читают набор результатов однажды и не изменяют переменные, содержащие результаты. Его главный недостаток это издержки памяти, вызванные дополнительным управлением ссылками, которое происходит, прежде всего, из-за того, что пользовательские переменные, содержащие результаты, не могут быть полностью освобождены, пока mysqlnd не прекращает ссылаться на них. MySQL Native driver удаляет ссылку на пользовательские переменные, когда набор результатов освобожден, или выполняется copy-write. Наблюдатель будет видеть, что потребление общей памяти растет, пока набор результатов не будет освобожден. Используйте статистику, чтобы проверить, освобождает ли скрипт действительно наборы результатов явно, или драйвер делает неявные освобождения и таким образом память какое-то время используется дольше, чем необходимо. Статистические данные также помогают видеть, сколько произошло копий на операциях записи.

Скрипт PHP, читая много маленьких строк буферизированного набора результатов, используя фрагмент кода, равный или эквивалентный while ($row = $res->fetch_assoc()) { ... }, может оптимизировать потребление памяти, прося копии вместо ссылок. Хотя требование копий означает держать результаты дважды в памяти, оно позволяет PHP освобождать копию, содержавшуюся в $row когда набор результатов повторяется и до освобождения самого набора результатов. На нагруженном сервере, оптимизация пикового использования памяти может помочь улучшению полной производительности системы, хотя для отдельного скрипта подход копирования может привести к замедлению из-за дополнительных ассигнований и операций копирования в памяти.

Способ копии может быть проведен в жизнь, установив mysqlnd.fetch_data_copy=1.

Контроль и отладка

Есть многократные способы отследить использование памяти MySQL Native Driver. Если цель состоит в том, чтобы получить быстрый обзор высокого уровня или проверить эффективность памяти скриптов PHP, проверьте статистику, собранную библиотекой. Статистические данные позволяют вам, например, ловить SQL-операторы, которые производят больше результатов, чем обрабатывается скриптом PHP.

Трассировка отладки может формироваться, чтобы сделать запись управления памятью. Это помогает видеть, когда память ассигнуется или освобождается. Однако размер требуемых кусков памяти не может быть перечислен.

Некоторые последние версии MySQL Native Driver показывают эмуляцию случайных ситуаций с памятью. Эта особенность предназначается, чтобы использоваться разработчиками библиотеки C или mysqlnd plugin. Пожалуйста, ищите исходный код соответствующих параметров конфигурации PHP и более подробную информацию. Особенность считают частной и могут изменить в любое время без предшествующего уведомления.

7.9. MySQL Native Driver Plugin API

MySQL Native Driver Plugin API является особенностью MySQL Native Driver или mysqlnd. Плагины Mysqlnd работают в слое между запросами PHP и сервером MySQL. Это сопоставимо с MySQL Proxy. MySQL Proxy работает в слое между любым клиентским приложением MySQL, например, запросом PHP и сервером MySQL. Плагины Mysqlnd могут предпринять типичные задачи MySQL Proxy, такие как выравнивание нагрузки, контроль и исполнительная оптимизация. Из-за различной архитектуры и местоположения, у плагинов mysqlnd нет некоторых недостатков MySQL Proxy. Например, у плагинов нет никакого единственного пункта сбоя, никакого выделенного прокси-сервера и никакого нового языка программирования.

Плагин mysqlnd может считаться расширением mysqlnd. Плагины могут перехватить большинство функций mysqlnd. Функции mysqlnd вызваны расширениями PHP MySQL, такими как ext/mysql, ext/mysqli и PDO_MYSQL. В результате возможно для плагина mysqlnd перехватить все вызовы, сделанные к этим расширениям из клиентского приложения.

Внутренние вызовы функций mysqlnd могут также быть перехвачены или заменены. Нет никаких ограничений на управление внутренними таблицами функций mysqlnd. Возможно настроить вещи так, чтобы, когда функции mysqlnd вызваны расширениями, то использовался mysqlnd, если вызов направлен к соответствующей функции в mysqlnd. Способность управлять внутренними таблицами функций mysqlnd таким образом позволяют максимальную гибкость для плагинов.

Плагины Mysqlnd на самом деле расширения PHP, написанные на C, они используют mysqlnd plugin API (который встроен в MySQL Native Driver, mysqlnd). Плагины могут быть сделаны 100% очевидными для запросов PHP. Никакие изменения приложений не необходимы, потому что плагины воздействуют на другой слой. Плагин mysqlnd может считаться работающим в слое ниже mysqlnd.

Следующий список представляет некоторые возможные применения плагинов mysqlnd.

  • Выравнивание нагрузки.

    • Разделение чтения-записи. Пример этого: расширение PECL/mysqlnd_ms (Master Slave). Это расширение разделяет запросы чтения-записи для репликации.

    • Отказоустойчивость.

    • Циклический алгоритм уменьшения нагрузки.

  • Контроль.

    • Регистрация запроса.

    • Анализ запроса.

    • Ревизия запроса. Пример этого: расширение PECL/mysqlnd_sip (SQL Injection Protection). Это расширение осматривает запросы и выполняет только те, которые разрешены, согласно правилам.

  • Производительность.

    • Кэширование. Пример этого: расширение PECL/mysqlnd_qc (Query Cache).

    • Разделение. Пример этого: расширение PECL/mysqlnd_mc (Multi Connect). Это расширение попытается разделить оператор SELECT на n частей, применяя SELECT ... LIMIT part_1, SELECT LIMIT part_n. Это посылает запросы различным серверам MySQL и сливает результат в клиенте.

Доступные плагины MySQL Native Driver

Есть много уже доступных плагинов mysqlnd. Они включают:

  • PECL/mysqlnd_mc - Multi Connect.

  • PECL/mysqlnd_ms - Master Slave.

  • PECL/mysqlnd_qc - Query Cache.

  • PECL/mysqlnd_pscache - Prepared Statement Handle Cache.

  • PECL/mysqlnd_sip - SQL Injection Protection.

  • PECL/mysqlnd_uh - User Handler.

7.9.1. Сравнение плагинов mysqlnd с MySQL Proxy

Плагины Mysqlnd и MySQL Proxy это различные технологии, использующие разные подходы. Обе это хорошие инструменты для решения множества общих задач, таких как выравнивание нагрузки, контроль и улучшения производительности. Важное различие: MySQL Proxy работает со всеми клиентами MySQL, тогда как плагины mysqlnd определены для запросов PHP.

Как PHP Extension, плагин mysqlnd устанавливается на сервере приложений PHP, вместе с остальной частью PHP. MySQL Proxy можно управлять на сервере приложений PHP или можно установить на выделенной машине, чтобы обращаться с многими серверами приложений PHP.

У развертывания MySQL Proxy на сервере приложений есть два преимущества:

  1. Никакого единственного пункта сбоя.

  2. Легко масштабировать систему.

MySQL Proxy (и плагины mysqlnd) может легко решить проблемы, которые иначе потребовали бы изменений существующих приложений.

Но у MySQL Proxy есть некоторые недостатки:

  • MySQL Proxy новый компонент.

  • MySQL Proxy требует знания языка Lua.

MySQL Proxy может быть настроен программированием на C и Lua. Lua предпочтительный язык MySQL Proxy. Для большинства экспертов PHP Lua новый язык. Плагин mysqlnd может быть написан на C. Также возможно написать плагины на PHP, используя PECL/mysqlnd_uh.

MySQL Proxy работает как демон, фоновый процесс. MySQL Proxy может вспомнить более ранние решения, поскольку все состояние может быть сохранено. Однако, плагин mysqlnd связан с основанным на запросе жизненным циклом PHP. MySQL Proxy может также разделить одноразовые вычисленные результаты среди многократных серверов приложений. Плагин mysqlnd должен был бы хранить данные в постоянной среде, чтобы быть в состоянии сделать это. Другой демон должен был бы использоваться с этой целью, например, Memcache. Это дает MySQL Proxy преимущество в этом случае.

MySQL Proxy работает поверх проводного протокола. С MySQL Proxy необходимо разобрать и перепроектировать протокол MySQL Client Server. Действия ограничиваются теми, которые могут быть достигнуты, управляя протоколом связи. Если проводной протокол изменяется (что происходит очень редко), скрипты MySQL Proxy должны были бы быть изменены также.

Плагины Mysqlnd работают поверх C API, который отражает libmysqlclient. C API в основном обертка вокруг протокола MySQL Client Server или проводного протокола, как это иногда называют. Можно перехватить все вызовы C API. PHP использует C API, поэтому можно зацепить все вызовы PHP без потребности программировать на уровне проводного протокола.

Mysqlnd осуществляет проводной протокол. Плагины могут поэтому разобрать, перепроектировать, управлять и даже заменить протокол связи. Однако, это обычно не требуется.

Поскольку плагины позволяют вам создавать внедрения, которые используют два уровня (C API и проводной протокол), у них есть большая гибкость, чем у MySQL Proxy. Если плагин mysqlnd осуществляется, используя API C, любые последующие изменения проводного протокола не требуют изменений самого плагина.

7.9.2. Получение mysqlnd plugin API

mysqlnd plugin API просто часть PHP-расширения MySQL Native Driver, ext/mysqlnd. Это развито как часть хранилища исходного текста PHP и доступна общественности через Git или посредством загрузки снимка исходных текстов.

Следующая таблица показывает версии PHP и соответствующие версии mysqlnd.

Таблица 7.8. Связанная версия mysqlnd в выпуске PHP

PHP Version MySQL Native Driver
5.3.05.0.5
5.3.15.0.5
5.3.25.0.7
5.3.35.0.7
5.3.45.0.7

Разработчики плагинов могут определить версию mysqlnd посредством доступа к MYSQLND_VERSION, которая является последовательностью формата mysqlnd 5.0.7-dev - 091210 - $Revision: 300535 или через MYSQLND_VERSION_ID, который является целым числом, например, 50007. Разработчики могут вычислить номер версии следующим образом:

Таблица 7.9. Таблица расчета MYSQLND_VERSION_ID

Version (часть) Пример
Major*100005*10000 = 50000
Minor*1000*100 = 0
Patch7 = 7
MYSQLND_VERSION_ID 50007

Во время развития разработчики должны обратиться к номеру версии mysqlnd для совместимости и тестов версий, так как несколько итераций mysqlnd могло произойти в течение разработки PHP с единственным номером версии PHP.

7.9.3. Архитектура MySQL Native Driver Plugin

Эта секция предоставляет обзор архитектуры mysqlnd.

Обзор MySQL Native Driver

Перед разработкой плагина mysqlnd полезно знать, как устроен mysqlnd. Mysqlnd состоит из следующих модулей:

Таблица 7.10. Модульная структура mysqlnd

Статистика mysqlnd_statistics.c
Связьmysqlnd.c
Набор результатовmysqlnd_result.c
Метаданные набора результатов mysqlnd_result_meta.c
Запросmysqlnd_ps.c
Сетьmysqlnd_net.c
Проводной протокол mysqlnd_wireprotocol.c

Объектно-ориентированная парадигма C

На кодовом уровне mysqlnd использует образец C для осуществления ориентации объекта.

В C вы используете struct, чтобы представлять объект. Члены структуры представляют свойства объектов. Участники структуры, указывающие на функции, представляют методы.

В отличие от этого, с другими языками, такими как C++ или Ява, нет никаких закрепленных правил о наследовании в объектно-ориентированной парадигме C. Однако, есть некоторые соглашения, которые должны выполняться.

Жизненный цикл PHP

Рассматривая жизненный цикл PHP, есть два основных цикла:

  • Запуск и завершение PHP.

  • Цикл запроса.

Когда PHP запускается, он вызовет инициализацию модуля (MINIT) каждого зарегистрированного расширения. Это позволяет каждому модулю установить переменные и ассигновать ресурсы, которые будут существовать все время работы PHP. При завершении работы PHP, он вызовет закрытие модуля (MSHUTDOWN) для каждого расширения.

В течение работы PHP это получит много запросов. Каждый запрос составляет другой жизненный цикл. По каждому запросу PHP вызовет функцию инициализации запроса каждого расширения. Расширение может выполнить любую установку переменных и распределение ресурсов, требуемое для обработки запросов. Поскольку цикл запроса заканчивает закрытие запроса (RSHUTDOWN) каждого расширения, таким образом, расширение может выполнить любую требуемую очистку.

Как работает плагин

Плагин mysqlnd работает перехватывая вызовы mysqlnd, сделанные к расширению mysqlnd. Это достигается, получая таблицу функций mysqlnd, резервируя ее и заменяя своей таблицей функций, которая вызывает функции плагина как требуется.

Следующий код показывает, как таблица функций mysqlnd заменяется:

/* a place to store original function table */
struct st_mysqlnd_conn_methods org_methods;
void minit_register_hooks(TSRMLS_D)
{
  /* active function table */
  struct st_mysqlnd_conn_methods * current_methods
  = mysqlnd_conn_get_methods();
  /* backup original function table */
  memcpy(&org_methods, current_methods,
  sizeof(struct st_mysqlnd_conn_methods);
  /* install new methods */
  current_methods->query = MYSQLND_METHOD(my_conn_class, query);
}

Манипуляции таблицы функции связи должны быть сделаны во время инициализации модуля (MINIT). Таблица функций это глобальный совместно используемый ресурс. В многопоточной окружающей среде с TSRM манипуляция глобальным совместно используемым ресурсом во время обработки запросов почти наверняка приведет к конфликтам.

Не используйте логику фиксированного размера, управляя таблицей функций mysqlnd: новые методы могут быть добавлены в конце таблицы функций. Таблица функций может измениться в любое время в будущем.

Запрос родительских методов

Если оригинальные записи таблицы функций поддерживаются, все еще возможно вызвать оригинальные записи таблицы функций, родительские методы.

В некоторых случаях, например, Connection::stmt_init(), жизненно важно вызвать родительский метод до любой другой деятельности в полученном методе.

MYSQLND_METHOD(my_conn_class, query)(MYSQLND *conn,
               const char *query, unsigned int query_len TSRMLS_DC)
{
  php_printf("my_conn_class::query(query = %s)\n", query);
  query = "SELECT 'query rewritten' FROM DUAL";
  query_len = strlen(query);
  return org_methods.query(conn, query, query_len);
  /* return with call to parent */
}

Распространение свойств

Объект mysqlnd представляется структурой C. Невозможно добавить участника к структуре C во время выполнения. Пользователи объектов mysqlnd не могут просто добавить свойства к объектам.

Произвольные данные (свойства) могут быть добавлены к объектам mysqlnd, используя соответствующую функцию mysqlnd_plugin_get_plugin_<object>_data(). Ассигнуя объект mysqlnd, делают интервалы в конце объекта для хранения указателя void * на произвольные данные. mysqlnd делает интервал для одного указателя void * на плагин.

Следующая таблица показывает, как вычислить положение указателя для определенного плагина:

Таблица 7.11. Расчет указателя для mysqlnd

Адрес памяти Контент
0 Начало структуры объекта C mysqlnd.
n Конец структуры объекта C mysqlnd.
n + (m x sizeof(void*)) void* к данным объектов плагина m.

Если вы планируете подклассифицировать какой-либо из конструкторов объекта mysqlnd, необходимо иметь это в виду!

Следующий код показывает расширение свойств:

/* any data we want to associate */
typedef struct my_conn_properties {
  unsigned long query_counter;
} MY_CONN_PROPERTIES;

/* plugin id */
unsigned int my_plugin_id;
void minit_register_hooks(TSRMLS_D) {
  /* obtain unique plugin ID */
  my_plugin_id = mysqlnd_plugin_register();
  /* snip - see Extending Connection: methods */
}

static MY_CONN_PROPERTIES** get_conn_properties(const MYSQLND *conn TSRMLS_DC)
{
  MY_CONN_PROPERTIES** props;
  props = (MY_CONN_PROPERTIES**)mysqlnd_plugin_get_plugin_connection_data(
           conn, my_plugin_id);
  if (!props || !(*props))
  {
     *props = mnd_pecalloc(1, sizeof(MY_CONN_PROPERTIES), conn->persistent);
     (*props)->query_counter = 0;
  }
  return props;
}

Разработчик ответственен за управление памятью данных.

Использование распределителя памяти mysqlnd рекомендуют для данных. Эти функции вызывают, используя соглашение: mnd_*loc(). У распределителя mysqlnd есть некоторые полезные особенности, такие как способность использовать распределитель отладки в неотладочной сборке.

Таблица 7.12. Когда и как подклассифицировать

Когда подклассифицировать? У каждого экземпляра есть своя собственная таблица функций? Как подклассифицировать?
Connection (MYSQLND)MINIT Нетmysqlnd_conn_get_methods()
Resultset (MYSQLND_RES) MINIT или позже.Да mysqlnd_result_get_methods() или работа с таблицами функций метода объекта.
Resultset Meta (MYSQLND_RES_METADATA) MINITНет mysqlnd_result_metadata_get_methods()
Statement (MYSQLND_STMT) MINITНет mysqlnd_stmt_get_methods()
Network (MYSQLND_NET) MINIT или позже.Да mysqlnd_net_get_methods() или работа с таблицами функций метода объекта.
Wire protocol (MYSQLND_PROTOCOL) MINIT или позже.Да mysqlnd_protocol_get_methods() или работа с таблицами функций метода объекта.

Вы не должны управлять таблицами функций никогда позже, чем MINIT, если это не позволено, согласно вышеупомянутой таблице.

Некоторые классы содержат указатель на таблицу функций метода. Все экземпляры такого класса разделяют ту же самую таблицу функций. Чтобы избежать хаоса, в особенности в переплетенной среде, такими таблицами функций нужно управлять только во время MINIT.

Другие классы используют копии глобальной общей таблицы функций. Копия таблицы функций класса создается вместе с объектом. Каждый объект использует свою собственную таблицу функций. Это дает вам два варианта: можно управлять таблицей функций по умолчанию объекта в MINIT, и можно дополнительно усовершенствовать методы объекта, не влияя на другие экземпляры того же самого класса.

Преимущество общего подхода таблицы функции: производительность. Нет никакой потребности копировать таблицу функций для каждого объекта.

Таблица 7.13. Статус конструктора

Тип Распределение, создание, перезагрузка Можно модифицировать? Caller
Connection (MYSQLND) mysqlnd_init()Нетmysqlnd_connect()
Resultset(MYSQLND_RES)

Распределение:

  • Connection::result_init()

Перезагрузка и повторная инициализация во время:

  • Result::use_result()

  • Result::store_result

Да, но родитель должен быть вызван!
  • Connection::list_fields()

  • Statement::get_result()

  • Statement::prepare() (только Metadata)

  • Statement::resultMetaData()

Resultset Meta (MYSQLND_RES_METADATA) Connection::result_meta_init() Да, но родитель должен быть вызван! Result::read_result_metadata()
Statement (MYSQLND_STMT) Connection::stmt_init() Да, но родитель должен быть вызван! Connection::stmt_init()
Network (MYSQLND_NET) mysqlnd_net_init()Нет Connection::init()
Wire protocol (MYSQLND_PROTOCOL) mysqlnd_protocol_init()Нет Connection::init()

Сильно рекомендуется, чтобы вы действительно не полностью заменили конструктор. Конструкторы выполняют выделения памяти. Выделения памяти жизненно важны для mysqlnd plugin API и логики объекта mysqlnd. Если вы не заботитесь о предупреждениях и настаиваете на том, чтобы менять конструктор, необходимо, по крайней мере, вызвать родительский конструктор прежде, чем сделать что-либо в своем конструкторе.

Независимо от всех предупреждений это может быть полезно для конструкторов подкласса. Конструкторы это прекрасное место для изменения таблиц функций объектов с таблицами необщего объекта, такими как Resultset, Network, Wire Protocol.

Таблица 7.14. Статус деструктора

Тип Полученный метод должен вызвать родителя? Destructor
Connection Да, после выполнения метода. free_contents(), end_psession()
Resultset Да, после выполнения метода. free_result()
Resultset Meta Да, после выполнения метода. free()
Statement Да, после выполнения метода. dtor(), free_stmt_content()
Network Да, после выполнения метода. free()
Wire protocol Да, после выполнения метода. free()

Деструкторы это соответствующее место, чтобы освободить свойства, mysqlnd_plugin_get_plugin_ <object>_data().

Перечисленные деструкторы могут не быть эквивалентны фактическому методу mysqlnd, освобождая сам объект. Однако они самое лучшее место для вас, чтобы освободить ваши данные. Как с конструкторами, можно заменить методы полностью, но это не рекомендуется. Если многочисленные методы будут перечислены в вышеупомянутой таблице, то необходимо будет зацепить все перечисленные методы и освободить данные в том методе, который вызывает первым mysqlnd.

Рекомендуемый метод для плагинов должен просто перехватить методы, освободить вашу память и немедленно вызвать родительскую реализацию после этого.

Из-за ошибки в версиях PHP 5.3.0 и 5.3.3 плагины не связывают данные с постоянной связью. Это потому, что ext/mysql и ext/mysqli не вызывают все необходимые вызовы метода mysqlnd end_psession() и плагины могут поэтому пропустить память. Это было исправлено в PHP 5.3.4.

7.9.4. mysqlnd plugin API

Ниже представлен список функций, обеспеченных в mysqlnd plugin API:

  • mysqlnd_plugin_register()

  • mysqlnd_plugin_count()

  • mysqlnd_plugin_get_plugin_connection_data()

  • mysqlnd_plugin_get_plugin_result_data()

  • mysqlnd_plugin_get_plugin_stmt_data()

  • mysqlnd_plugin_get_plugin_net_data()

  • mysqlnd_plugin_get_plugin_protocol_data()

  • mysqlnd_conn_get_methods()

  • mysqlnd_result_get_methods()

  • mysqlnd_result_meta_get_methods()

  • mysqlnd_stmt_get_methods()

  • mysqlnd_net_get_methods()

  • mysqlnd_protocol_get_methods()

Нет никакого формального определения того, что такое плагин и как работает его механизм.

Компоненты, часто находимые в механизмах плагинов:

  • Менеджер плагинов.

  • plugin API.

  • Прикладные службы (или модули).

  • Прикладная служба API (или модуль API).

Понятие плагина mysqlnd использует эти особенности и дополнительно обладает открытой архитектурой.

Отсутствие ограничений

У плагина есть полный доступ к внутренним работам mysqlnd. Нет никаких ограничений или пределов безопасности. Все может быть переписано, чтобы осуществить дружественные или враждебные алгоритмы. Рекомендуется, чтобы вы развернули плагины только от надежного источника.

Как обсуждено ранее, плагины могут использовать указатели свободно. Эти указатели не ограничиваются ни в каком случае и могут указать в данные другого плагина. Простая арифметика может использоваться, чтобы прочитать данные другого плагина.

Рекомендуется, чтобы вы всегда вызывали родительский метод. Плагины должны всегда сотрудничать с mysqlnd самостоятельно.

Таблица 7.15. Проблемы: пример формирования цепочки и сотрудничества

Расширение Указатель mysqlnd.query() Стек вызовов, вызывая родителя
ext/mysqlnd mysqlnd.query()mysqlnd.query
ext/mysqlnd_cachemysqlnd_cache.query()
  1. mysqlnd_cache.query()

  2. mysqlnd.query

ext/mysqlnd_monitor mysqlnd_monitor.query()
  1. mysqlnd_monitor.query()

  2. mysqlnd_cache.query()

  3. mysqlnd.query

Здесь кэш (ext/mysqlnd_cache) и монитор (ext/mysqlnd_monitor) загружены. Оба имеют подкласс Connection::query(). Регистрация плагина происходит в MINIT, с использованием логики, показанной ранее. PHP вызывает расширения в алфавитном порядке по умолчанию. Плагины не знают друг о друге и не устанавливают дополнительные зависимости.

По умолчанию плагины вызывают родительскую реализацию метода запроса в их полученной версии метода.

Резюме расширения PHP

Это резюме того, что происходит, используя плагин в качестве примера, ext/mysqlnd_plugin, который выставляет mysqlnd C plugin API в PHP:

  • Любое приложение PHP MySQL пытается установить связь с 192.168.2.29.

  • Приложение PHP будет использовать ext/mysql, ext/mysqli или PDO_MYSQL. Все три расширения PHP MySQL применяют mysqlnd, чтобы установить связь с 192.168.2.29.

  • Mysqlnd вызывает метод connect, который был подклассифицирован ext/mysqlnd_plugin .

  • ext/mysqlnd_plugin вызывает перехватчик пространства пользователя proxy::connect(), зарегистрированный пользователем.

  • Перехватчик пространства пользователя изменяет хост связи IP с 192.168.2.29 на 127.0.0.1 и возвращает связь, установленную parent::connect().

  • ext/mysqlnd_plugin выполняет эквивалент parent::connect(127.0.0.1), вызывая изначальный метод mysqlnd для установления связи.

  • ext/mysqlnd устанавливает связь и возвращается к ext/mysqlnd_plugin. ext/mysqlnd_plugin тоже возвращается.

  • Независимо от того, какое расширение PHP MySQL использовалось, приложение получает связь с 127.0.0.1. Само расширение PHP MySQL возвращается к применению PHP. Круг закрывается.

7.9.5. Введение в написание плагинов mysqlnd

Важно помнить, что плагин mysqlnd это самостоятельное расширение PHP.

Следующий код показывает базовую структуру функции MINIT, которая будет использоваться в типичном плагине mysqlnd:

/* my_php_mysqlnd_plugin.c */
static PHP_MINIT_FUNCTION(mysqlnd_plugin)
{
  /* globals, ini entries, resources, classes */
  /* register mysqlnd plugin */
  mysqlnd_plugin_id = mysqlnd_plugin_register();
  conn_m = mysqlnd_get_conn_methods();
  memcpy(org_conn_m, conn_m, sizeof(struct st_mysqlnd_conn_methods));
  conn_m->query = MYSQLND_METHOD(mysqlnd_plugin_conn, query);
  conn_m->connect = MYSQLND_METHOD(mysqlnd_plugin_conn, connect);
}
/* my_mysqlnd_plugin.c */
enum_func_status MYSQLND_METHOD(mysqlnd_plugin_conn, query)(/* ... */)
{
/* ... */
}
enum_func_status MYSQLND_METHOD(mysqlnd_plugin_conn, connect)(/* ... */)
{
/* ... */
}

Анализ задач: от C до пространства пользователя

class proxy extends mysqlnd_plugin_connection
{
  public function connect($host, ...) { .. }
}
mysqlnd_plugin_set_conn_proxy(new proxy());

Процесс:

  1. PHP: пользователь регистрирует отзыв плагина.

  2. PHP: пользователь вызывает любой PHP MySQL API, чтобы соединиться с MySQL.

  3. C: ext/*mysql* вызывает метод mysqlnd.

  4. C: mysqlnd заканчивается в ext/mysqlnd_plugin.

  5. C: ext/mysqlnd_plugin

    1. Вызывает отзыв пространства пользователя.

    2. Или оригинальный метод mysqlnd, если отзыв пространства пользователя не задан.

Необходимо выполнить следующее:

  1. Написать на С класс "mysqlnd_plugin_connection".

  2. Принять и зарегистрировать объект прокси через "mysqlnd_plugin_set_conn_proxy()".

  3. Вызвать методы прокси пространства пользователя из C (оптимизация: zend_interfaces.h).

Методы объекта пространства пользователя можно вызвать, используя call_user_function() или можно действовать на уровне ближе к Zend Engine и использовать zend_call_method().

Оптимизация: вызов методов из C, используя zend_call_method

Следующий фрагмент кода показывает прототип для функции zend_call_method, взятый из zend_interfaces.h.

ZEND_API zval* zend_call_method(zval **object_pp, zend_class_entry *obj_ce,
                                zend_function **fn_proxy,
                                char *function_name, int function_name_len,
                                zval **retval_ptr_ptr, int param_count,
                                zval* arg1, zval* arg2 TSRMLS_DC);

Zend API поддерживает только два аргумента. Вам, возможно, понадобится больше, например:

enum_func_status (*func_mysqlnd_conn__connect)
                 (MYSQLND *conn, const char *host,
                  const char * user, const char * passwd,
                  unsigned int passwd_len, const char * db,
                  unsigned int db_len, unsigned int port,
                  const char * socket, unsigned int mysql_flags TSRMLS_DC);

Чтобы обойти эту проблему, необходимо будет сделать копию zend_call_method() и добавить средство для дополнительных параметров. Можно сделать это, создав макрос MY_ZEND_CALL_METHOD_WRAPPER.

Запрос пространства пользователя PHP

Этот фрагмент кода показывает оптимизированный метод для того, чтобы вызвать функцию пространства пользователя из C:

/* my_mysqlnd_plugin.c */
MYSQLND_METHOD(my_conn_class,connect) (MYSQLND *conn, const char *host
               /* ... */ TSRMLS_DC)
{
  enum_func_status ret = FAIL;
  zval * global_user_conn_proxy = fetch_userspace_proxy();
  if (global_user_conn_proxy)
  {
     /* call userspace proxy */
     ret = MY_ZEND_CALL_METHOD_WRAPPER(global_user_conn_proxy, host, /*...*/);
  } else {
    /* or original mysqlnd method = do nothing, be transparent */
    ret = org_methods.connect(conn, host, user, passwd,
                              passwd_len, db, db_len, port,
                              socket, mysql_flags TSRMLS_CC);
  }
  return ret;
}

Запрос пространства пользователя: простые аргументы

/* my_mysqlnd_plugin.c */
MYSQLND_METHOD(my_conn_class,connect) (/* ... */, const char *host, /* ...*/)
{
  /* ... */
  if (global_user_conn_proxy)
  {
     /* ... */
     zval* zv_host;
     MAKE_STD_ZVAL(zv_host);
     ZVAL_STRING(zv_host, host, 1);
     MY_ZEND_CALL_METHOD_WRAPPER(global_user_conn_proxy, zv_retval, zv_host
                                 /*, ...*/);
     zval_ptr_dtor(&zv_host);
     /* ... */
  }
  /* ... */
}

Запрос пространства пользователя: структуры как аргументы

/* my_mysqlnd_plugin.c */
MYSQLND_METHOD(my_conn_class, connect) (MYSQLND *conn, /* ...*/)
{
  /* ... */
  if (global_user_conn_proxy)
  {
     /* ... */
     zval* zv_conn;
     ZEND_REGISTER_RESOURCE(zv_conn, (void *)conn, le_mysqlnd_plugin_conn);
     MY_ZEND_CALL_METHOD_WRAPPER(global_user_conn_proxy, zv_retval, zv_conn,
                                 zv_host /*, ...*/);
     zval_ptr_dtor(&zv_conn);
     /* ... */
  }
  /* ... */
}

Первый аргумент многих методов mysqlnd это что-то из C. Например, первым аргументом метода connect() является указатель на MYSQLND. Структура MYSQLND представляет объект связи mysqlnd.

Указатель объекта связи mysqlnd может сравниться со стандартным дескриптором файла I/O. Как стандартный дескриптор файла I/O, объект связи mysqlnd должен быть связан с пространством пользователя, используя тип переменной ресурса PHP.

Из C до пространства пользователя и назад

class proxy extends mysqlnd_plugin_connection
{
  public function connect($conn, $host, ...)
  {
    /* "pre" hook */
    printf("Connecting to host = '%s'\n", $host);
    debug_print_backtrace();
    return parent::connect($conn);
  }

  public function query($conn, $query)
  {
    /* "post" hook */
    $ret = parent::query($conn, $query);
    printf("Query = '%s'\n", $query);
    return $ret;
  }
}
mysqlnd_plugin_set_conn_proxy(new proxy());

Пользователи PHP должны быть в состоянии вызвать родительскую реализацию переписанного метода.

В результате подклассификации возможно усовершенствовать только выбранные методы, и вы можете иметь "pre" или "post" перехватчики.

Встроенный класс: mysqlnd_plugin_connection::connect()

/*my_mysqlnd_plugin_classes.c */
PHP_METHOD("mysqlnd_plugin_connection", connect)
{
  /* ... simplified! ... */
  zval* mysqlnd_rsrc;
  MYSQLND* conn;
  char* host; int host_len;
  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs",
      &mysqlnd_rsrc, &host, &host_len) == FAILURE)
  {
     RETURN_NULL();
  }
  ZEND_FETCH_RESOURCE(conn, MYSQLND* conn, &mysqlnd_rsrc, -1,
                      "Mysqlnd Connection", le_mysqlnd_plugin_conn);
  if (PASS == org_methods.connect(conn, host, /* simplified! */ TSRMLS_CC))
     RETVAL_TRUE;
  else RETVAL_FALSE;
}

Поиск

 

Найди своих коллег!

Вы можете направить письмо администратору этой странички, Алексею Паутову. mailto:alexey.v.pautov@mail.ru