Планирование нагрузки на сервер
Решил немного рассказать про планирование нагрузки на сервер,хотя тут будет информация в основном заимствованная с одного из ресурсов(с blogerator.ru)
В общем ситуация такова, что нагрузочное тестирование показало, что сервер может обработать
10 запросов в секунду. Значит ли это, что на практике сервер выдержит
такую нагрузку в Интернете?
Вообще говоря ответ скорее будет - нет.
Сейчас разберемся почему.
Имеется простая задача.
Дан сервер,
синхронно обрабатывающий запросы из Интернет
в одном потоке. Т.е. в каждый момент времени сервер может либо
обрабатывать один запрос, либо ожидать новые запросы. Запросы становятся
в очередь ожидания, если в данный момент сервер занят обработкой
другого запроса. Время обработки одного запроса равно 100 мс.
И мы подобрались к основному вопросу: каково будет среднее
время ожидания запроса в очереди при средней нагрузке на сервер
в 10 запросов в секунду? Правильный ответ — время ожидания будет
стремиться к бесконечности.
Как же так? В каком то месте произошло что то внезапное? Дело в том, что средняя и равномерная нагрузка — это «две
большие разницы». Средняя нагрузка на сервер может быть представлена
в виде
процесса Пуассона. Это означает, что в начале первой секунды может сразу прийти 100 запросов, а за последующие 9 секунд — ни одного.
В итоге выходит 10 запросов в секунду за интервал в 10 секунд со средним временем ожидания
sum(1..99)/100 * 100 мс = 4.95
секунды.
Рассмотрим другие варианты. Очевидно, что при средней нагрузке,
превышающей 10 запросов в секунду, сервер не сможет обрабатывать лишние
запросы, что приведет к бесконечному увеличению очереди ожидания
запросов.
А что будет, если нагрузка будет ниже максимально допустимой?
Например, каково будет среднее время ожидания при 95% нагрузке, т.е. для
нашего случая 9.5 запросов в секунду?Если вы думаете,что сейчас самое время расслабиться и пойти погонять чаю, рассчитывая на 0мс,то чай откладывается.
Спешу вас снова огорчить — среднее время ожидания в этом случае будет равно
950 мс
, т.е. в 9.5 раз больше времени, необходимого на обработку самого
запроса! Идем дальше. Давайте попробуем предположить время ожидания
при 90% нагрузке. Нет, вовсе не 900 мс, а 450 мс. ВНЕЗАПНО!
А при какой нагрузке среднее время ожидания будет равно времени,
необходимому для обработки запроса? Иными словами, при какой средней
нагрузке среднее время ответа от сервера будет равно
200 мс
(
100 мс
ожидание +
100 мс
обработка)? Правильный ответ — 66.666...%! Даже при одном запросе
в секунду среднее время ожидания будет равно не нулю, а где-то 5.56 мс.
Не очень похоже на адекватные результаты.
Числа получены экспериментальным путем(я верю автору который его проводил,но если нет,то это лучшее розового мира с пони в котором вы находились до этого), после чего была выведена формула.
Вот очень простая функция, написанная на
python, которая была использована для моделирования нагрузки на сервер и вычисления среднего времени ожидания.
def NormalizedAvgWaitTime(load_factor, requests_count):
"""
Calculates normalized average wait time for the given
load factor.
Models requests to a synchronous single-threaded server
using Poisson process and calculates an average wait time
per request for the given load factor.
Args:
load_factor: a floating point value in the range [0..1).
The value 0 means the server isn't loaded with requests
at all, the value 1 means the average qps load on the
server is equivalent to its' maximum capacity.
requests_count: an integer representing the number of
requests to model. Higher values mean higher precision
for the returned result.
Returns:
a floating point number representing normalized average
wait time per request for the given load factor. The
value 0 means requests are processed immediately, while
any number W means requests stay in the queue for an
average W*T seconds, where T is a time required for
processing a single request on the idle server.
"""
if not load_factor:
return 0
points = sorted(random.random() for i in range(requests_count))
request_time = load_factor / requests_count
total_wait_time = 0
x = points[0]
for i in range(1, requests_count):
y = points[i]
wait_time = request_time - y + x
if wait_time > 0:
total_wait_time += wait_time
y += wait_time
x = y
return total_wait_time / load_factor
После того, как были получены экспериментальные данные, осталось подогнать под них формулу.
При
load_factor = 1
наша функция стремится к бесконечности. Значит, у нас должна быть
дробь, в знаменателе которой присутствует множитель, стремящийся к нулю
при
load_factor = 1
. На эту роль хорошо подходит
(1 — load_factor)
. Идем дальше. При
load_factor = 0
наша функция равна нулю. Значит, в числителе дроби должен быть множитель, равный нулю при
load_factor = 0
. Очевидно, что это и есть
load_factor.
Дальше — при
load_factor = 0.5
наша функция должна равняться тоже 0.5 . Значит,
C*0.5/(1-0.5) = 0.5
.
Откуда
C = 0.5
. В итоге формула принимает вид:
NormalizedAvgWaitTime(load_factor) = 0.5*load_factor / (1-load_factor)
Как правильно планировать нагрузку на сервер?
И вот мы подходим к главному вопросу,то что было сказано выше,должно было натолкнуть на мысль,что результаты наших нагрузочных тестов не совсем объективны.Проблема в том, что поток
тестовых запросов не является Пуассоновским процессом, с которым суждено
встретиться серверу в production. Если вы сейчас обеспокоились заказчиками или своими проектами,то это всего лишь опасения,хрен с ними,дальше все будет намного лучше.Достаточно
найти максимальную нагрузку, выдерживаемую системой по схеме, описанной
выше.
После этого по формуле вычисляете допустимую нагрузку в production
для заданного среднего времени ожидания запроса. Например, для
максимальной нагрузки в
1000 qps
и среднего времени ожидания запроса, равного 100% времени обработки запроса:
1 = 0.5*load_factor/(1-load_factor) => load_factor = 1/1.5 = 2/3.
Тогда допустимая нагрузка равна:
1000*2/3 = 666.666... qps
.
Выводы
Всегда следите за нагрузкой на системы, обрабатывающие запросы, которые распределены во времени по
процессу Пуассона.
К таким системам относятся все системы с потенциально большим
количеством пользователей. Например, все сервера подключенные
к Интернет.
Не допускайте, чтобы средняя
нагрузка повышалась более чем на 75% от максимально допустимой, т.к.
это ведет к молниеносному увеличению среднего времени ожидания входящих
запросов,криков со стороны руководства и заказчиков,месяца без премий,отсутствию серфинга в Калифорнии.