пятница, 23 ноября 2012 г.

Планирование нагрузки на сервер

Планирование нагрузки на сервер

Решил немного рассказать про планирование нагрузки на сервер,хотя тут будет информация в основном заимствованная с одного из ресурсов(с 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% от максимально допустимой, т.к. это ведет к молниеносному увеличению среднего времени ожидания входящих запросов,криков со стороны руководства и заказчиков,месяца без премий,отсутствию серфинга в Калифорнии.

Комментариев нет:

Отправить комментарий