Схемка примитивная до безобразия - два лоад балансера с nginx на борту и keepalived для переключения в случае падений.
Все радовало глаз, кроме load average. Запросов примерно 10k rps overall. И я все время грешил на lua, который использовался в nginx для выбора нужного апстрима. Выглядит это примерно так:
access_by_lua '
-- Try POST first
ngx.req.read_body();
local args, err = ngx.req.get_post_args();
if next(args) == nil
then
-- Since post is empty, use GET
args, err = ngx.req.get_uri_args();
end
local uri = ngx.var.uri;
local matched = string.find(uri, "needed-method");
local some_arg = args["some_arg"];
if (matched ~= nil and (nil == some_arg or "" == some_arg or string.find(some_arg, "^arg-value$")))
then
ngx.exec("@proxy");
end
';
Ну а ниже уже определяем location @proxy и направляем запрос куда надо. К слову, очень удобный способ при миграции. К примеру, переписываете вы api с python на golang. Используя lua и подход указанный выше вы очень легко сможете проксировать часть запросов (функционал которых уже реализован) на golang. Причем принимать решение о проксировании вы сможете на основне внутренних данных запроса. Тогда переезжать можно будет постепенно, а не разом все переносить.
Возвращаемся к load average. Гитхаб оказался завален жалобами на nginx lua high cpu usage и во всех тредах советовали немного отпрофилировать nginx. Чем я собственно и занялся. Скачал, собрал, запустил - https://github.com/openresty/openresty-systemtap-toolkit#sample-bt. Получил карту вызовов системных функций и что увидел? Правильно! lua оказалась не при делах. Корень зла крылся в ssl 🙂 Кто-бы мог подумать.
Ну и разрешилось все достаточно легко - добавил ssl_session_cache и нагрузка резко пошла вниз. На скриншоте два идентичных load balancer'а. Справа - после добавления ssl-related настроек, слева - первоначальный вариант.
Ну и конечно вывод - гипотезы надо проверять.
Ах да, чуть не забыл полезную ссылочку на утилитку для генерации ssl конфига: https://mozilla.github.io/server-side-tls/ssl-config-generator/