Pull to refresh

Опрос: как у вас решается проблема синхронизации параллельных запросов на PHP?

Reading time4 min
Views19K
Долгое время я пытаюсь понять, сколько места отведено вопросам параллельности и конкурентности выполнения кода в повседневной практике среднестатистического PHP-программиста. С одной стороны, разрабатывая серверное приложение, программист автоматически пишет код, который будет выполняться параллельно. С другой, на практике в PHP все проблемы этой области решались инструментами, которыми все пользовались — веб-сервер, сессия и СУБД.

Обращают ли на ваших проектах внимание на на проблемы синхронизации параллельно обрабатывающихся HTTP-запросов? Они решаются через транзакции, блокировки? Какие способы блокирования вы используете? Да и вообще, нужно об этом париться, или тема бесполезная? Узнаем мнение аудитории. Этот пост не дает ответов на вопросы. Здесь ведется разведка.


***

В мире PHP исторически принято не обращать много внимания на параллельность выполнения кода. Под многопоточность не заточен сам PHP (нет потокобезопасности внутри движка). Я ни разу не встречал проекты или программистов, которые использовали pthreads (а вы встречали? тогда расскажите об этом в коменнтах). И не очень-то именно многопоточность нужна на практике в веб-приложениях, где параллельно нужно выполнять прежде всего запросы, а не отдельные части кода в рамках одного запроса. А так как параллельное выполнение входящих запросов в отдельных процессах организуется сервером приложений (php-fpm или apache), программисту об этом думать не нужно — все работает из коробки.

В PHP есть механизм сессий, которым пользуются в подавляющем большинстве случаев. А сессия с дефолтовыми настройками блокирует параллельное выполнение запросов в рамках одной сессии. Это «прикрывает» некоторые дыры и приводит к тому, что на практике можно никогда и не столкнуться с явными проблемами. Т.е. пока пользователь не начнет хакерить, работая, например, в двух браузерах одновременно, ничего не сломается из-за отсутствия блокировок и транзакций.

К тому же вероятность коллизий из-за параллельности очень мала для сайтов с пиковым количеством запросов меньше чем 2 в секунду (исходя из того, что время генерации ответа не превышает секунду).

Ну и, наконец, если какие-то проблемы параллельности все же всплывают, то самый простой способ их решения — транзакция в БД с достаточным уровнем изоляции. Так как почти все сайты, которые разрабатываются на PHP, используют в качестве хранилища транзакционную СУБД, достаточно просто начать использовать транзакции для решения проблем конкуренции выполнения запросов, которые приводят к неконсистентности данных. Даже не вникая глубоко в тему синхронизации процессов, просто используя транзакции, проблему можно решить.

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

Отчасти все это и хорошо — низкий порог вхождения, что и является одним из главных преимуществ PHP. Быстрая разработка за счет экономии времени на проработку всех узким мест. Но рано или поздно, многие начинают сталкиваться с проблемой синхронизации процессов лицом к лицу. А разработка надежных, а не рассчитанных на обстоятельства, приложений требует определенного уровня изучения этого вопроса.

Самый простой пример, когда не поможет транзакция, — прогрев кэша. Чтобы данные, которые кэшируются, не генерировались параллельно, конкурентные запросы нужно блокировать, дав заполнить кэш тому запросу, который начал это делать первым. Без блокировки тут не обойтись. Причем, если серверов несколько, блокировка должна быть централизованной. Другой пример, файловый хостинг. У пользователя ограничено количество файлов, которые он может закачать. При добавлении файла нужно сравнить количество закачанных файлов с лимитом и принять файл, если лимит не исчерпан. Хотя тут можно сделать финт ушами и обойтись без блокировок, проще всего будет заблокироваться перед проверкой по пользователю, проверить счетчик, занять слот под файл, снять блокировку, после чего принять само тело файла.

И с использованием транзакций тоже есть свои проблемы. Как минимум то, что их надо несколько раз рестартовать, если присутствует race-condition и транзакция откатывается по причине коллизии. Есть вопросы при работе с внешними для БД ресурсами — файлами, кэшем, запросами к удаленному API.

***

На самом деле все PHP-программисты пишут код, который работает в конкурентной среде. Зачастую даже в очень выскоконкурентной. И доступ к общим ресурсам из параллельно выполняющихся процессов синхронизировать приходится. Я думаю, что многим, как и мне, будет интересно узнать, как на эту проблему смотрят коллеги по цеху. Как на ваших проектах решают проблему синхронизации доступа к общим ресурсам?

Как эта проблема решается у нас?
У нас используются транзацкии и блокировки. Транзакции помогают сохранить консистентность данных, если выполнение задачи сводится к серии запросов в БД. Когда же нужно синхронизировать код, который работает не только с базой, или вообще с ней не работает, мы используем блокировки через мою библиотеку абстракции над способом блокировки. Если бэкэнд работает на одном сервере, достаточно использовать драйвер для flock(), если нужно блокироваться распределенно, то можно использовать драйвера для Redis или Memcache.


Если у вас есть хорошие материалы по этой теме, делитесь ссылками в комментах.

P.S. Любителям других языков программирования: если вы хотите рассказать, как проблема успешно решается в вашем языке/фреймворке, you are welcome. В противном случае, обратите внимание на хаб, в котором размещена публикация.
Only registered users can participate in poll. Log in, please.
Вы программируете серверную часть приложения:
59.93% только на PHP498
27.08% на PHP и других языках (JS, Python, Ruby, .NET, ...) одновременно225
13% только на одном или нескольких других языках108
831 users voted. 176 users abstained.
Only registered users can participate in poll. Log in, please.
Актуальны ли по вашему мнению вопросы межпроцессного взаимодействия и синхронизации для PHP-программиста?
14.91% Да, но не для меня (нет времени или желания разобраться)102
46.78% Да, я хочу в этом разобраться320
15.79% Да, я в этом уже разорбрался108
8.04% Нет, это не нужно никому, и я в этом не разбираюсь55
14.47% Нет, это не нужно никому, но я в этом уже разбираюсь (хотя бы в общих чертах)99
684 users voted. 230 users abstained.
Only registered users can participate in poll. Log in, please.
Актуален ли на вашем проекте (на работе) вопрос синхронизации параллельных запросов (процессов)?
49.78% У нас этот вопрос вообще никак не стоит344
24.02% У нас этот вопрос актуален, но не решен166
26.19% У нас этот вопрос был актуален, но уже решен181
691 users voted. 203 users abstained.
Only registered users can participate in poll. Log in, please.
Какие способы синхронизации вы используете?
9.42% Блокировки на файлах без flock()49
19.23% Блокировки через flock()100
15.58% Блокировки через специальные объекты синхронизации ОС (мьютекс, семафор, ...)81
33.46% Блокировки через Memcached, Redis,…174
67.69% Транзакции в СУБД352
25.38% Явные блокировки в СУБД132
17.5% Другие варианты91
520 users voted. 338 users abstained.
Tags:
Hubs:
+12
Comments47

Articles