да много что делают, но не думаю, что кому-то это о чём-либо скажет, т.к. вызывается еще и куча внутренних функций, а приводить весь код и проводить нормальное сравнение я не собираюсь, я лишь только хочу разжечь срач.
почему у dkstra это получается, а у меня нет? =(
function CallPrepare(user, callerid, destination, from_originate_context)
local query, result, direction, call, route, manager_info, manager_call, real_balance, traffic_info
local max_duration = 0
-- callerid info
callerid = ResolveCallerid(callerid)
-- resolve
direction = ResolveDirectionByNumber(destination)
-- checkflood
if not CheckFlood(user, callerid, destination) then return "Declined 403" end
-- info for destination
call = GetInfoByDirection(user, direction)
-- is direction routed?
if not direction then return "Declined 380" end
if not call.direction then return "Declined 380" end
-- route info
route = GetRouteInfo(call.route)
-- manager info
manager_info = GetUserData(user.manager, 'username')
-- reseller recursive processing
local manager_max_duration = 99999
local try = 0
while manager_info.accesslevel < 25 or not manager_info do
-- max tries
if try > 10 then request.die("Error|Death coil was triggered") end
-- account status
real_balance = manager_info.actual_balance
if manager_info.is_unlimited then real_balance = 99999.99 end
if manager_info.active < 0 then return "Declined 403" end
-- find out maximum possible call duration from minimal balance of user/manager
if call.cost ~= 0 then max_duration = math.floor(real_balance/cost)*60 end -- +minutes_remaining*60
if max_duration < manager_max_duration then manager_max_duration = max_duration end
if (manager_info.sip_max_call_len < manager_max_duration) and (manager_info.sip_max_call_len > 0) then manager_max_duration = manager_info.sip_max_call_len end
-- try to find proper route
if (not route or call.route == 0) then
manager_call = GetInfoByDirection(manager_info, direction)
if manager_call.route ~= 0 then
route = GetRouteInfo(manager_call.route)
end
end
-- recursion++
manager_info = GetUserData(manager_info.manager, 'username')
try = try+1
end
-- get real user balance
real_balance = user.actual_balance
if user.is_unlimited then real_balance = 99999.99 end
-- max call duration
if call.cost ~= 0 then max_duration = math.floor(real_balance/call.cost)*60 end -- +minutes*60
if manager_max_duration < max_duration then max_duration = manager_max_duration end
if (manager_max_duration < max_duration) and user.sip_max_call_len > 0 then max_duration = user.sip_max_call_len end
-- error parsing
if direction == -1 then return "Declined 480" end -- wtf with number
if call.prefix == "Error" or route == 0 or prefix == 'NULL' then return "Declined 380" end -- direction disabled
if cost == -1 then return "Declined 380" end -- direction disabled
-- ban user by IP
if user.active < -4 then return "Declined 666" end
-- is user banned?
if user.active < 0 then
UpdateUserData(user, "active", user.active - 1, true)
return "Declined 403"
end
-- out of money
if max_duration <= 0 then
LogEntry(user.sip_extension, destination, callerid, call.direction, '0:00', 'default', '0INSUFFICIENT', 0)
return "Declined 401"
end
-- cli
if not helper.is_int(callerid) and not from_originate_context then return "Declined 470" end
-- our reslt
return "Allowed "..max_duration.." "..callerid.." "..translit.ru2lat(call.direction:gsub(' ', '')).." "..route.prefix.." "..route.route
end
а нет, и правда количество запросов в базу совпадает с кол-вом worker'ов. это как-то пофиксить можно или нет? (хоть и запросов в саму БД в приложении не так уж и много, но всё же)
Сделай sleep 30. Сделай 10 клиентов, как описано выше. Потом через 5 секунд создай ещё 10 клиентов и т.д. С какого момента при 3 процессах nginx все упадёт, накроется тазом?
Я не спец. по хайлоад. Мой бест практис: pre-fork + max workers. Типа как сделано в php-fpm. Альтернатива: использовать все средства (мониторинг, профилирование в рилтайм, бить по рукам разрабов если такое допустили), чтобы не было никаких долгих запросов.
sleep 30 - оно упадет по таймауту (в настройках nginx 10 секунд макс. таймаут апстрима) оно не падает, но время ответа в 2-3 раза увеличивается для следущей «пачки» клиентов. это как-то пофиксить можно, или это фича?
ну про максимизацию воркеров это само собой. а долгих в БД запросов нет, да и >32 одновременных запроса это как-то фантастично:) //php-fpm & mysql & nginx в подобной ситуации ведут себя похоже, но имхо всё упирается в mysql - в top'е 99% загрузка всех ядер mysqld и 1gb ram usage
правда, тут уже не «бенчмарк» с sleep'ом был, а реальная ситуация - сервер апстрим провайдера повис и через час решил «оповестить» нас отчётами о доставке ~500 смс одновременно
Неважно что в топе. Oracle DB умеет http запросы в процедурах: клиент > БД > http-request to remote host. Никаких ресурсов жрать, естественно, не будет. Зато удаленный хост может тупить и отдать страницу через 30 секунд. Зачем так делать другой вопрос. Просто пример о топе.
Все «форки» Oracle DB имеют такой же изъян, что я описал. В том числе и mysql/maria. Современная БД должна уметь работать по session id + request id в рамках одного соединения. Проще говоря уметь работать с очередью запросов, а не с экземпляром соединения.
Не знаю, может кто запилил под RabbitMQ (или аналог) сторадж в SQL. Ничто не мешает сейчас сделать такое. Раньше, в 70х, авторы БД считали, что вот БД, вот человек-пользователь, вот клиент (тупо клон telnet). Из всего, что я видел: хаки клиентских драйверов mysql/pg. Но это не то: надо менять саму БД и прикручивать менеджер очереди.
Это не то. Я такой «пул» могу на коленках написать и что? Тут кроме очереди в БД должен быть кэш, который бы смотрел: так, таблица не изменилась, предыдущий результат отдали 0.0001с назад, берем и отдаем значение из кэша, а не делаем еще раз селект + лок на таблицу. Ну и все в таком духе.
Нет, я не говорю, что это плохое приложение. Оно плохое by design, т.к. не исправляет дизайн (архитектуру) БД. Может через 10 лет кто-то решиться это сделать.
Для процедур тоже из кэша? Я не вникал внутрь pg, так что может чего-то не знаю. Суть в том, что pgpool это клиент для pg-server. Т.е. лишний элемент (уменьшает надежность, вносит свои баги и т.д.).
Ну и попроще пример: в очереди 100 одинаковых задач одна за другой идут последовательно, что сделает твой pgpool? Он сумеет понять, что все они одинаковые? Т.е. после получения ответа из БД он сразу вышлет 99 одинаковых ответов? Или всех прогонит через БД? А он так и сделает, т.к. pgpool архитектурно не встроен в БД, он не знает, что кроме него к БД подключен пользователь Петя, который на 55 задаче делает INSERT в эту же таблицу.
Что должно быть в идеале: БД видит это делает один прогон по таблице и моментально отдает ответ на остальные 99 задач. Если в середину попадет INSERT, допустим 42 по счету, то 1 запрос - читает из БД, далее до 41 идет чтение из кэша, потом INSERT, потом снова чтение, и далее из кэша до 100 задачи.
Разница в логике здесь не в том, что кэш/не кэш, а точно знать, когда и какой запрос выполняется, независимо от того сколько пользователей/сессий открыто и запускают запросы. Все, решает сама БД, когда оптимизировать, а когда нет. Из того что я помню, любой SELECT вешает на таблицу READONLY-блок, т.е., клиент даже на этапе формирования ответа при подании в ту же секунду INSERT вернет старое значение! А БД можно изменить так, что если ответ не сформирован и имеем INSERT, то сначала сделаем INSERT, а затем вернем конечный результат.
Постгрес в любом случае кэширует запрошенные данные. Но соль pgpool не только в очереди запросов, но и в том, что он реюзает тоже самое соединение по многу раз - это дает возможность постгресу кэшировать не только данные но и query plan, в том числе и для процедур (http://www.postgresql.org/docs/current/static/plpgsql-implementation.html#PLP...).
То, что он еще не является частью постгреса - это конечно жаль.
Нет. Мы писали блочную кешилку в redis. Вариант с nginx+lua быстрее php и выдерживает раз в 20 больше одновременных запросов.
(на самом деле больше. с пхп мы уперлись в пхп, с луа мы уперлись в редис (он однопоточный), пришлось несколько инстансев с кластеризацией-на-коленке делать и все равно мы упираемся в редис с ~25-30K rps)
Есть и минусы. Стабильность lua+nginx пока ниже и отлаживать сложнее. Зачастую при ошибках в коде оно попросту роняет воркер с сегфолтом (тому что там везде jit и ffi).
«средненький», я бы сказал. умеет в - управление пользователями, лицевыми счетами (на несколько пользователей может быть один лицевой), инвойсы, финансы, отчёты, логи, смски, двухсторонний обмен информацией с SIP-сервером (астериск) через SIPMESSAGES, маршрутизация, прямые номера, тарифные планы, и офк квотирование вызовов и тарификация real-time. билайн - направление вызова.