Обнаружил баг в Apache/PHP.
Проявляется в том, что некоторые запросы переходят в keepalive state (т.е. ждут продолжения запроса после окончания предыдущего на том же сокете) и остаются там навечно. Таким образом, постепенно все процессы Apache попадают в это состояние, если keealive включен, а так как выйти из него у них не получается - сервер постепенно задыхается. Причём таймаут, который у апача есть для избежания таких ситуаций, не работает. Собственно, с этого всё и началось - сервер наш начал вдруг необьяснимо дохнуть, притом что ни нагрузки процессора, ни наплыва посетителей особого не наблюдалось.
По расследованию оказалось, что функция, которая должна работать по таймауту, не вызывается. А не вызывается она потому, что есть такой флаг alarms_blocked, который блокирует обработку сигналов. Когда обработка сигналов неуместна, вызывается ap_block_alarms(), которая делает ++alarms_blocked, а когда снова можно - ap_unblock_alarms(), в которой написано вот что:
--alarms_blocked;
if (alarms_blocked == 0) {
и далее обрабатываются случаи, видимо, когда в период, что сигналы были заблокированы, был сигнал и теперь пора его отработать.
Постфактум я думаю, что уже увидя этот код, я должен был заподозрить неладное. Но с первого раза я не понял, в чём дело. Запустил отладчик и посмотрел значение alarms_blocked в зависших процессах. И оно оказалось - -1, -2 и т.п. Тут до меня дошло - а что будет, если какой-то кривой код вызовет ap_unblock_alarms(), не вызывая перед этим block()? А то и будет, что с этого момента не судьба этому процессу больше принимать сигналы по таймауту - то есть судьба, но ровно тогда, когда кто-нибудь ему это _запретит_.
Завтра буду искать, кто же это такой умный этот флаг портит. То ли это в самом Apache, то ли в модуле PHP - он тоже с этими функциями играется.
Проявляется в том, что некоторые запросы переходят в keepalive state (т.е. ждут продолжения запроса после окончания предыдущего на том же сокете) и остаются там навечно. Таким образом, постепенно все процессы Apache попадают в это состояние, если keealive включен, а так как выйти из него у них не получается - сервер постепенно задыхается. Причём таймаут, который у апача есть для избежания таких ситуаций, не работает. Собственно, с этого всё и началось - сервер наш начал вдруг необьяснимо дохнуть, притом что ни нагрузки процессора, ни наплыва посетителей особого не наблюдалось.
По расследованию оказалось, что функция, которая должна работать по таймауту, не вызывается. А не вызывается она потому, что есть такой флаг alarms_blocked, который блокирует обработку сигналов. Когда обработка сигналов неуместна, вызывается ap_block_alarms(), которая делает ++alarms_blocked, а когда снова можно - ap_unblock_alarms(), в которой написано вот что:
--alarms_blocked;
if (alarms_blocked == 0) {
и далее обрабатываются случаи, видимо, когда в период, что сигналы были заблокированы, был сигнал и теперь пора его отработать.
Постфактум я думаю, что уже увидя этот код, я должен был заподозрить неладное. Но с первого раза я не понял, в чём дело. Запустил отладчик и посмотрел значение alarms_blocked в зависших процессах. И оно оказалось - -1, -2 и т.п. Тут до меня дошло - а что будет, если какой-то кривой код вызовет ap_unblock_alarms(), не вызывая перед этим block()? А то и будет, что с этого момента не судьба этому процессу больше принимать сигналы по таймауту - то есть судьба, но ровно тогда, когда кто-нибудь ему это _запретит_.
Завтра буду искать, кто же это такой умный этот флаг портит. То ли это в самом Apache, то ли в модуле PHP - он тоже с этими функциями играется.
no subject
no subject
--alarms_blocked;
if (alarms_blocked < 0) {
alarms_blocked = 0;
<log a warning on incorrect signal blocking } if (alarms_blocked == 0) ..... И никакие модули более ничего не испортят... Все тот же парадигм - веди себя максимально корректно, принимай от других максимально широкии диапазон поведения (и некорректного тоже).
no subject
no subject
no subject
(0 когда должно быть 1).
Плюс неясно сколько раз этот модуль может вызвать
unlock без block
no subject
Slackers!
По-моему лучше всего именно ту функцию, которая сокращает alarms_blocked, заставить проверять, не равняется-ли эта переменная нолю перед попыткой сократить.
no subject
Re: Slackers!
Re: Slackers!
Re: Slackers!
no subject
Вот я иногда так самому себе не доверяю, что в подобных функциях ставлю проверку, которую потом можно убрать если что, потому как она в ifdef обозначена. Так называемый test-run debugging. Очень полезный подход к вопросу. Ну и в сислог сливаю, что этот код, несмотря на его неактульность, был вызван. Так иногда выявляются весьма любопытные аномалии, без риска угробить систему и образовать downtime.
А вообще мне все эти приколы напоминают старый анекдот про х.й с винтом и ж..у с закоулками...:)
no subject
no subject
no subject