История одного просветления, произошедшего уже несколько лет назад

Dec 15, 2017 01:53

Надо запротоколировать - прикольная история.

Когда я на это напоролся, у меня было, собственно, открытие - я полностью прочувствовал, что PHP по дефолту не умеет обрабатывать 2 параллельных запроса от одного юзера.)))

Суть такая: в PHP сделано тупое, но надёжное решение для исключения параллельной записи данных одной сессии двумя процессами - сессия тупо блокируется на весь период от её открытия до закрытия. А открывается она обычно в начале запроса - а закрывается в конце.))

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

Оно понятно, зачем сделано - если не блокировать, то что окажется в итоге в сессии - неизвестно - два процесса могут писать в сессию параллельно и один может перезаписать данные другого. И оно обычно как бы не страшно, так как да, действительно сайтики редко кто так насилует, а если и насилует, то типа нефиг же - типа, тоже мне кулхацкер, у нас тут и так 100500 юзеров параллельно, а ты ещё и свои запросы хочешь в параллель пускать, падла?!

И видимо, когда народ в PHP переключает сессию на redis и говорит, что всё стало «летать» - летать оно начинает именно потому, что redis хранилище сессий в пхп не делает блокировку - не то что это его фича - просто не умеет оно в блокировки :)

А вот теперь история, как я на это напоролся:

Ставил я VisualEditor (визуальный редактор для MediaWiki) и хотел его подружить с нашими правами (IntraACL). Для справки - в VisualEditor википеды же тоже прилично извратились - конфигурация там такая - сама вики на PHP, но рядом, чисто для VisualEditor’а, на сервер ставится node.js.

В котором выполняется parsoid, служащий бэкендом к VisualEditor’у. Parsoid - это частично переписанный на js парсер медиавики - полностью не осилили и не осилят никогда, уж больно там говнокода много на него завязано.

И запросы идут через такую жопу: браузер -> PHP -> node.js -> (а дальше нода же хочет получить текст страницы, которую правишь) -> обратно запрос в PHP.

И по дефолту на втором запросе к PHP они его сессионную Cookie ему обратно не передавали. Соответственно, у нас из-за прав доступа отредактировать страницу не удавалось - но зато эта конструкция вообще работала! :)

А когда я включил передачу куки юзера на этом запросе, чтобы нода читала текст страницы с учётом прав - вся эта конструкция стала радостно повисать. Я чуть башку не сломал, а оказывается, это была как раз блокировка сессии. Второй запрос же «вложен» в первый и запускается в той же сессии => 2 ждёт, пока кончится 1, а 1 ждёт, когда закончится 2. Дедлок.

Вот тогда у меня и случилось просветление.))

А после внедрения в медиавики неблокирующей работы с сессией, естественно, попёрли гонки и стала иногда отваливаться авторизация. Причём, почему-то, в том числе при вызове из скрипта репликации, который вообще однопоточный - там до сих пор гонка бывает, я так и не понял пока, откуда она там - для обычных-то юзеров поправили, конечно.

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

Короче: какая-то, с*ка, светлая голова в SemanticMediaWiki впилила для пересчёта какой-то очередной внутренней хрени обработчик очереди. Стандартной медиавиковской очереди - есть у неё в ядре очередь задач, и можно туда свои задачи пихать.

Но так как стандартная обработка заданий идёт в том числе потихоньку в конце каждого запроса, после отдачи страницы юзеру (ну, типа, чтобы работало даже там, где демона не запустишь) - эта, с*ка, светлая голова решила, что это же будет тормозить! И реализовала обработку самого задания через дополнительный запрос с сервера на самого себя, к URLу который фактически обрабатывает задание.

И оно как-то большей частью даже прокатывало… пока пользователь не открывал 2 вкладки одновременно - после чего висло нафиг 2 процесса сервера, а после N повторов висли все доступные процессы сервера и вики переставала отзываться. Причём все такие спокойные - загрузки CPU нет, никто ничем не занят, а вики висит - все в дедлоках.

Сами википеды на свои сессии тоже вроде потом напоролись, но уже после меня (после 1.26) - и то ли в 1.27, то ли в 1.28, вроде, переосмыслили своё поведение.
Previous post Next post
Up