SUPER_OLEG_DEV Telegram 225
Привет!

Достаточно давно делился статьей где описывал различные механизмы и подходы которые мы применяем для SSR приложений на Tramvai (сейчас доступна на хабре).

Один из механизмов - Request Limiter, модуль который ограничивает количество параллельно обрабатываемых запросов при перегруженном Event Loop приложения, для возможности стабильно отдавать 2xx ответы и рендерить странички даже под большими нагрузками.

Работает по похожим принципам с https://github.com/fastify/under-pressure, только не отбрасывает все запросы при нагрузке, а держит еще LIFO очередь что бы обеспечить большее количество успешных ответов без сильной деградации времени ответа.

Когда переводили наши интеграционные тесты на 20 версию Node.js, начали падать нагрузочные тесты Request Limiter. Основная проблема - перестали быстро отвечать health-чеки приложения (а отзывчивые health-чеки и метрики очень важны и что бы в реальном времени понимать что происходить и для graceful рестартов и так далее)

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

Завел issue, получил много интересного и ценного фидбека от Matteo Collina - https://github.com/nodejs/node/issues/57364

Оказалось, что изменения в libuv убрали запуск таймеров в начале цикла на старте event loop, теперь они запускаются только в конце - то есть после poll (входящие запросы и прочее) и check (setImmediate).

В веб-сервере под капотом Tramvai мы испольуем setImmediate для того что бы иметь возможность "разорвать" event loop между тяжелыми задачами по SSR и ответить на легкие запросы /metrics, /health и так далее.

У libuv есть логика по ограничению одновременно обрабатываемых immediate коллбэков - https://github.com/libuv/libuv/blob/49b6e4db0cfc2bdb4c4151030618981c2fc0795b/src/unix/core.c#L462-L465

http модуль внутри использует различные таймеры/интервалы, до обновления ноды все это вместе с request limiter работало так скажем в гармонии, логика по обработке запроса (в том числе таймеры) выполнялась на одной фазе event loop до immediate коллбэков.

После обновления libuv в Node.js, если я все правильно понял, логика обработки запроса теперь раскидана до и после check фазы с immediate коллбэками, и происходит что-то вроде взаимной блокировки - мы не можем полноценно обрабатывать новые запросы (в том числе быстро ответить 429 кодом) пока в очереди есть много immediate коллбэков.

Также Маттео накинул несколько кейсов почему в целом опасно использовать setImmediate для дробления обработки запросов и что это просаживает перф - https://github.com/fastify/fastify/pull/545

Проблем тут вижу несколько:
- в нашем кейсе, SSR это не тысячи а десятки RPS как в бенчмарках fastify/h3, и такие проблемы нам не важны
- но при этом у нас была реальная и очень полезная возможность оставаться отзывчивыми, и держать под нагрузкой адекватные 2xx RPS
- также я не вижу интеграционных тестов в репозитории under-pressure и сомневаюсь до конца что инструмент работает ожидаемо

Пару дней назад Маттео написал даже в блок Platformatic (это их коммерческий продукт для Node.js стека) про кейс, итого получился подробный обзор проблемы (правда черезчур нейросетевой):
- https://x.com/matteocollina/status/1951322487595090177?s=19
- https://blog.platformatic.dev/the-dangers-of-setimmediate

Основной поинт Маттео который я полностью поддерживаю - надо использовать worker_threads, и само приложение поднимать в воркере, таким образом изолировать его event loop (тут он рекламирует их сервер Watt который так делает из коробки)

Для Tramvai тут проблема что это сильно не вписывается в текущую архитектуру.

Придется делать еще один заход и смотреть как мы можем избавиться от setImmediate, и что в итоге выжать из Request Limiter под нагрузками на свежих версиях Node.js
👍14🔥123



tgoop.com/super_oleg_dev/225
Create:
Last Update:

Привет!

Достаточно давно делился статьей где описывал различные механизмы и подходы которые мы применяем для SSR приложений на Tramvai (сейчас доступна на хабре).

Один из механизмов - Request Limiter, модуль который ограничивает количество параллельно обрабатываемых запросов при перегруженном Event Loop приложения, для возможности стабильно отдавать 2xx ответы и рендерить странички даже под большими нагрузками.

Работает по похожим принципам с https://github.com/fastify/under-pressure, только не отбрасывает все запросы при нагрузке, а держит еще LIFO очередь что бы обеспечить большее количество успешных ответов без сильной деградации времени ответа.

Когда переводили наши интеграционные тесты на 20 версию Node.js, начали падать нагрузочные тесты Request Limiter. Основная проблема - перестали быстро отвечать health-чеки приложения (а отзывчивые health-чеки и метрики очень важны и что бы в реальном времени понимать что происходить и для graceful рестартов и так далее)

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

Завел issue, получил много интересного и ценного фидбека от Matteo Collina - https://github.com/nodejs/node/issues/57364

Оказалось, что изменения в libuv убрали запуск таймеров в начале цикла на старте event loop, теперь они запускаются только в конце - то есть после poll (входящие запросы и прочее) и check (setImmediate).

В веб-сервере под капотом Tramvai мы испольуем setImmediate для того что бы иметь возможность "разорвать" event loop между тяжелыми задачами по SSR и ответить на легкие запросы /metrics, /health и так далее.

У libuv есть логика по ограничению одновременно обрабатываемых immediate коллбэков - https://github.com/libuv/libuv/blob/49b6e4db0cfc2bdb4c4151030618981c2fc0795b/src/unix/core.c#L462-L465

http модуль внутри использует различные таймеры/интервалы, до обновления ноды все это вместе с request limiter работало так скажем в гармонии, логика по обработке запроса (в том числе таймеры) выполнялась на одной фазе event loop до immediate коллбэков.

После обновления libuv в Node.js, если я все правильно понял, логика обработки запроса теперь раскидана до и после check фазы с immediate коллбэками, и происходит что-то вроде взаимной блокировки - мы не можем полноценно обрабатывать новые запросы (в том числе быстро ответить 429 кодом) пока в очереди есть много immediate коллбэков.

Также Маттео накинул несколько кейсов почему в целом опасно использовать setImmediate для дробления обработки запросов и что это просаживает перф - https://github.com/fastify/fastify/pull/545

Проблем тут вижу несколько:
- в нашем кейсе, SSR это не тысячи а десятки RPS как в бенчмарках fastify/h3, и такие проблемы нам не важны
- но при этом у нас была реальная и очень полезная возможность оставаться отзывчивыми, и держать под нагрузкой адекватные 2xx RPS
- также я не вижу интеграционных тестов в репозитории under-pressure и сомневаюсь до конца что инструмент работает ожидаемо

Пару дней назад Маттео написал даже в блок Platformatic (это их коммерческий продукт для Node.js стека) про кейс, итого получился подробный обзор проблемы (правда черезчур нейросетевой):
- https://x.com/matteocollina/status/1951322487595090177?s=19
- https://blog.platformatic.dev/the-dangers-of-setimmediate

Основной поинт Маттео который я полностью поддерживаю - надо использовать worker_threads, и само приложение поднимать в воркере, таким образом изолировать его event loop (тут он рекламирует их сервер Watt который так делает из коробки)

Для Tramvai тут проблема что это сильно не вписывается в текущую архитектуру.

Придется делать еще один заход и смотреть как мы можем избавиться от setImmediate, и что в итоге выжать из Request Limiter под нагрузками на свежих версиях Node.js

BY SuperOleg dev notes




Share with your friend now:
tgoop.com/super_oleg_dev/225

View MORE
Open in Telegram


Telegram News

Date: |

The channel also called on people to turn out for illegal assemblies and listed the things that participants should bring along with them, showing prior planning was in the works for riots. The messages also incited people to hurl toxic gas bombs at police and MTR stations, he added. Telegram message that reads: "Bear Market Screaming Therapy Group. You are only allowed to send screaming voice notes. Everything else = BAN. Text pics, videos, stickers, gif = BAN. Anything other than screaming = BAN. You think you are smart = BAN. ‘Ban’ on Telegram It’s easy to create a Telegram channel via desktop app or mobile app (for Android and iOS): Telegram is a leading cloud-based instant messages platform. It became popular in recent years for its privacy, speed, voice and video quality, and other unmatched features over its main competitor Whatsapp.
from us


Telegram SuperOleg dev notes
FROM American