Проблематика
Высокая нагрузка - это нагрузка, с которой по какой-то причине не справляется железо (не хватает CPU или памяти).
На данный момент с развитием железа проблемы его нехватки отпали, если приложение тормозит, то в 99% случаев это косяк в архитектуре.
Расммотрим рядовую операцию на бэкенде
- Прием данных по сети
- Парсинг полученных данных
- Взаимодействие с БД
- Формирование ответа
- Отправка ответа клиенту
Самый простой способ реализовать эту операцию - использовать один поток на один запрос. Но тогда быстро упремся в кол-во обрабатываемых запросов в секунду.
Далее можно увеличить кол-во используемых котоков или процессов, распределить нагрузку между несколькими серверами.
Однако все это не даст значительного прироста в RPS - он останется в пределах нескольких сотен.
При этом если проанализировать, сколько времени выполняется каждый из пунктов в операции на бэкенде, то увидим, что:
Прием данных по сети - 15к в сек
Парсинг полученных данных - 15к в сек
Взаимодействие с БД - 60к в сек
Формирование ответа - 100к в сек
Отправка ответа клиенту - 15к в сек
Если этого все сложить по формуле
1/sum(1/freq(i))
то получим 6к запросов в секунду, а не условно 500.
В таких случаях нужно заняться профайлингом. Тогда увидим, что код выполняется процессором от силы 10% всего времени, а остальное времени идет ожидание от БД и сети.
Событийно-ориентированная архитектура
Решить предыдущую проблему поможет изменение парадигмы программирования.
Событийно-ориентированная архитектура подразумевает, что выполнение программы определяется событиями, на которые осуществилась "подписка". То есть мы говорим, что когда поступит событие успешного сохранения в БД, сделай то-то.
Это то-то определяем в колбеке, который передаем отдельным аргументом. Из-за этого придется менять основную часть кодовой базы, которая крутится вокруг взаимодействия по сети.
Также приходится решать проблемы, связанные со сменой парадигмы.
сохранение контекста между колбеками
обработка исключений
Чтобы было нагляднее, традиционную парадигму с потоками можно сравнить с обувным магазином, где покупатель часто находится в ожидании, когда ему принесут обувь.
А событийно-ориентированную парадигму - с продуктовым магазином, где продавец всегда при деле находится и обслуживает очередь.
Green Threads
Если брать обычные потоки, то их переключением занимается планировщик в составе операционной системы.
Однако можно написать собственный планировщик, который бы управлял зелеными потоками (эмуляция многопоточной среды - подпрограмма), переключаясь между ними в момент ожидания операций ввода/вывода в одном.
Соответственно, если операция сугубо процессорная, то профита не будет.
Тогда если соединить вместе друг с другом свой планировщик и машину событий, то получим таком порядок выполнения операции:
- Регистрация событий в машине состояний
- Передача управления планировщику
- При наступлении события планировщик будит зеленый поток
- Программа работает с данными от события, которое наступило в пред. пункте
Т.е. зеленый поток усыпляется до тех пор, пока не наступает событие.
Такой подход подразумевает использования библиотеки для использования зеленых потоков и написания кода-оберток над БД и сетевых вызовов.
Top comments (0)