Подписка

Асинхронные MySQL запросы в HipHop PHP

Большим недостатком стандартной реализации MySQL клиента является отсутствие поддержки асинхронных запросов, выполняющихся в отдельном потоке не блокируя основной. Такие запросы отлично подходят для операций не нуждающихся в ответе сервера, как например обновление статистики, логирование и т.д. Особенно если операции работают с большими объемами данных и занимают много времени (например добавления строки в таблицу статистики вызывает триггер пересчета общей статистики для всех пользователей).

Для обхода этого ограничения MySQL клиента, приходиться придумывать разнообразные костыле-методы позволяющие выполнять запросы не блокируя выполнение приложения.

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

Ниже речь пойдет о похожем, но более красивом методе, использующем встроенный в HipHop сервер сообщений XBox.

Xbox - простой сервер сообщений, для работы с которым достаточно 3 функций:

xbox_post_message
отправка сообщения без блокирования основного потока
xbox_send_message
отправка сообщение с блокированием основного потока пока сообщение не будет обработано (или до истечения таймаута)
xbox_process_message
обработка сообщения

Для нашей задачи интересна функция xbox_post_message.

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

Начнем с определения функции обработчика сообщений. Для упрощения, в сообщении будем отправлять только sql запрос, поэтому все что нужно сделать в обработчике - выполнить полученное сообщение.

function xbox_process_message($message) {
     sleep(5);
     mysql_connect('127.0.0.1', 'root', '');
     mysql_query($message);
     echo "Async: ".$message."\n";
}

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

Для того чтобы добавить запрос в очередь нужно выполнить:

xbox_post_message($sqlQuery)

первый параметр функции содержит текст сообщения, который в нашем случае является sql запросом.

После выполнения xbox_post_message запрос будет добавлен в очередь и как только один из XBox серверов освободится - выполнен.

Как видите просто и продуктивно.

Напишем небольшой тестовый скрипт, чтобы убедиться что асинхронные запросы работают:


mysql_connect('127.0.0.1', 'root', '');
echo "Started\n";

function xbox_process_message($message) {
     sleep(5);
     mysql_connect('127.0.0.1', 'root', '');
     mysql_query($message);
     echo 'Async: '.$message."\n";
}
function query($sql) {
    mysql_query($sql);
    echo 'Sync: '.$sql."\n"; 
}
function async_query($sql) {
     xbox_post_message($sql);
}

async_query("SELECT 10");
query("SELECT 1");

while(true) {
     sleep(1);
}

Выполним:

hphp -k 1 --log=3 test_async.php

Получим:

Sync: SELECT 1
Async: SELECT 10

Как видно с результата, сначала был выполнен синхронный запрос (хотя он был вызван вторым), а после него асинхронный. И сложная обработка данных (в нашем случае сэмулированная sleep(5)) выполняясь не блокируя основной поток, чего мы и хотели добиться.

Бесконечный цикл в конце скрипта не обязателен (добавил его только для того чтобы было куда выводить echo), так как асинхронные сообщения Xbox'а обрабатываются отдельно от главного потока, поэтому нет необходимости управлять их выполнением. Если в данном примере убрать цикл, запрос выполниться, но сообщение "Async: SLEEP(10)" выводить будет некуда.

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

В тему:

Если пост понравился - нажмите на +1 - мне будет приятно.

@kkooler

@kkooler

Занимаюсь разработкой высоконагруженных проектов и распределенных систем на PHP.
В свободное время разрабатываю нано-проекты:

Следить за блогом

RSS канал Twitter