Возожности mysqlnd в PHP/5.3

01 August 2009 php mysql

Если вы не знаете, то с PHP/5.3 поставляется новый mysql драйвер — mysqlnd. У него есть несколько особенностей и воможностей, которые отличают его от libmysql.

Первое не очень интерестно. Теперь при fetch’e результата не происходит копирования из памяти libmysql в память, находящуюся под управлением zend engine. Фактически весь result set находится в памяти zend engine. Это значит что выборки превышающие по размеру memory limit теперь таки будут генерировать out of memory. Наверное, это представляет ценность для владельцев shared хостинга, но для тех у кого выделенный сервер это имеет мало пользы.

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

Распараллеливание записи может быть полезным, когда логическая операция записи физически приводит к обновлению информации хранящейся на нескольких серверах. Особенно это может быть выгодно, когда ваш процесс большую часть времени занят ожиданием подтверждения от БД об этой самой записи (i/o bound). Потребность “писать сразу в несколько мест” может возникнуть, например, в случае, если вы делаете программное зеркало вашей базы данных. На первый взгляд это может показатся глупостью, почему бы просто не настроить репликацию? Тем не менее, существуют ситуации когда application layer репликация имеет преимущества над mysql-репликацией. Также распараллеливание записи может быть полезно в случае осуществления сложных механизмов sharding’а. Иногда объект должен быть записан не в один shard, а в несколько (это уже не совсем зеркало). Такие операции записи хорошие кандидаты для распараллеливание (по-крайней, мере до тех пор пока shard’ы находятся на физически разных серверах).

Распараллеливание чтения может быть полезно в случае реализации scatter-gather. Если у вас сложное разбиение данных по серверам, то может возникнуть ситуация когда при построении SELECT запроса неизвестно какому серверу его адресовать (представьте что вы пытаетесь извлечь данные с фильтрацией по полю, которое не учавствует в критериях разбивки) — соответствующие данные “распылены” по всем серверам. В этом случае необходимо послать SELECT запрос всем серверам (scatter) и затем обьединить все результаты в один result set (gather). Вообще, эта техника очень дорога и лучше делать так, чтобы вам не приходилось ее использовать. Например, выбрать разбиение, которое позволит обращатся только к одному серверу. Тем самым вы увеличите data locality и благотворно повлияете на availability, так как теперь для обслуживания запроса вам нужны не все сервера, а всего один. Но если уж без scatter-gather не обойтись, то будет неплохо хотя бы отправлять запросы серверам параллельно, а не последовательно. В этом случае общее время ожидения ответа будет равно времени ожидания самого медленного сервера, а не сумме времени ожидания всех серверов.

И конечно же SLA. Лично нам этого очень сильно нехватало. Если запрос нас не блокирует, то технически мы можем и не ждать результатов его выполнения. Совсем не ждать смысла конечно нет, а вот не ждать дольше чем строго определенное количество времени, бывает очень полезно. Я уже писал раньше про fail fast. Всякий раз когда вы делаете более менее сложный запрос к БД вы не можете быть уверены сколько времени займет выполнение этого запроса. А пользователи ждать не любят. Все наверное были свидетелями как БД при растущей нагрузке все медленее и медленее обрабатывает существующие запросы. В такой ситуации новые запросы дают эффект снежного кома. С другой стороны, вполне возможно, что результат нам не так уж и нужен. Ну подумаешь не покажем пользователю на странице поиска сколько у него новых сообщений в “личке”, — он не для этого поиск инициировал. Неблокирующие запросы позволяют реализовать поведение когда мы спрашиваем у БД: “сколько у пользователя личных сообщений?” и недождавшись ответа в оговоренный timeout как бы говорим: “не очень-то и хотелось” и просто скрываем блок с личными сообщениями. Более того, можно реализовать схему в которой клиент не дождавшись ответа, через отдельный control connection, прибьет свой собственный запрос, чтобы он не генерировал дополнительную нагрузку на БД, — ей судя по всему и так не сладко, раз она не успела ответить вовремя (конечно, все это не работает с DML запросами).

Это все. Остальноесомнительные мелочи.