Общие стратегии противодействия давлению на услуги в условиях постоянной высокой нагрузки
Мне интересно, каковы общие стратегии противодавления, которые люди используют для своих веб-сервисов?
Представьте, что ваш сервис работает под большой нагрузкой, и в какой-то момент нагрузка достигает 120% вашей емкости. Как вы справляетесь с этим?
Самая разумная стратегия, о которой я могу подумать, - это отказаться от соединений. Поэтому, если один хост достигает своей пиковой мощности (например, все рабочие Apache заняты), я начинаю отклонять TCP-соединение, пока один из рабочих не освободится. Таким образом, все принятые соединения обрабатываются немедленно, без очереди (поэтому задержка минимальна), а избыточные 20% отклоняются, что позволяет балансировщику нагрузки переотправить их на другой хост или выполнить любую другую стратегию сброса нагрузки (например, перенаправление на статический / кешированный контент).
Я думаю, что этот отказоустойчивый подход намного превосходит любой вид очередей. Небольшие очереди хороши для поглощения коротких очередей в трафике, но с чрезмерной очередью ваша система может резко потерпеть неудачу при большой нагрузке. Например, при обработке очереди FIFO без какого-либо AQM он может войти в состояние, когда все обработанные запросы уже истекли по тайм-ауту на стороне клиента, поэтому система не продвигается вперед.
Я был удивлен, что эту стратегию не так легко реализовать, как кажется. Мой подход состоял в том, чтобы установить небольшое невыполненное прослушивание на веб-сервере, ожидая отклонения всех соединений, которые не подходят. Но из-за изменений в ядре Linux 2.2 эта стратегия разваливается (см. http://veithen.github.io/2014/01/01/how-tcp-backlog-works-in-linux.html).
Более новое ядро Linux принимает соединения для вас безоговорочно. Ответ SYN-ACK отправляется клиенту без учета размера прослушивания. Включение опции tcp_abort_on_overflow также не сильно помогает. Эта опция заставляет ядро отправлять RST, когда соединение не помещается в очередь приема, но в этот момент клиент уже считает соединение УСТАНОВЛЕННЫМ и, возможно, начало посылать данные.
Это особенно проблематично с HAProxy. Если соединение было успешно установлено, оно не будет пересылать запрос на другой сервер, так как этот запрос мог иметь некоторые побочные эффекты на сервере.
Итак, я думаю, мои вопросы:
- я странный за попытку реализовать что-то подобное?
- Есть ли другие стратегии для борьбы с устойчивой высокой нагрузкой, которые вы можете порекомендовать?
- tcp_abort_on_overflow ядра Linux не работает и должен был применяться вместо этого к полуоткрытой очереди?
Заранее спасибо!
1 ответ
Чтобы ответить на ваш первый вопрос: да. Ну, в любом случае, по моему личному мнению, не принимайте это на свой счет. Дело в том, что вы пытаетесь установить ограничения для своего стека TCP, в то время как перед вами стоит балансировщик нагрузки со множеством счетчиков и опций. Если вы ограничиваете себя в стеке TCP, вы сталкиваетесь с большим количеством проблем при достижении этих ограничений. Я бы проверил и сохранил ограничения в самом loadbalancer. Настройте счетчики сеансов или создайте сценарий работоспособности, который будет проверять работоспособность сервера. Достигнув пределов, вы можете либо отклонить новые входящие запросы, либо перенаправить их на другой сервер, когда вы установите бэкэнд как полный. Вы ограничены пределами вашего Apache, а не вашей ОС или haproxy, поэтому старайтесь держаться подальше от системных ограничений, контролируя нагрузку на ваш Apache до того, как он достигнет его.
Я думаю, это уже ответило на ваш второй вопрос.
Третий ответ на вопрос более сложный, и я не думаю, что вы захотите углубиться в это. Достижение состояния переполнения TCP, на мой взгляд, уже слишком далеко в настройке сервера для поддержания высокой нагрузки и трафика.
Это мои два цента, надеюсь, это поможет.