Highload Junior. 1. HighLoad++ для начинающих
Tags: highload, article, highloadjunior
Published: 2023-11-14 17:55:39

## Проблематика

Высокая нагрузка - это нагрузка, с которой по какой-то причине не справляется железо (не хватает CPU или памяти). 

На данный момент с развитием железа проблемы его нехватки отпали, если приложение тормозит, то в 99% случаев это косяк в архитектуре.


Расммотрим рядовую операцию на бэкенде 

1. Прием данных по сети
2. Парсинг полученных данных
3. Взаимодействие с БД
4. Формирование ответа
5. Отправка ответа клиенту


Самый простой способ реализовать эту операцию - использовать один поток на один запрос. Но тогда быстро упремся в кол-во обрабатываемых запросов в секунду. 
Далее можно увеличить кол-во используемых котоков или процессов, распределить нагрузку между несколькими серверами. 
Однако все это не даст значительного прироста в RPS - он останется в пределах нескольких сотен.

При этом если проанализировать, сколько времени выполняется каждый из пунктов в операции на бэкенде, то увидим, что:

- Прием данных по сети - 15к в сек

- Парсинг полученных данных - 15к в сек

- Взаимодействие с БД - 60к в сек

- Формирование ответа - 100к в сек

- Отправка ответа клиенту - 15к в сек

Если этого все сложить по формуле

1/sum(1/freq(i))

то получим 6к запросов в секунду, а не условно 500.

В таких случаях нужно заняться профайлингом. Тогда увидим, что код выполняется процессором от силы 10% всего времени, а остальное времени идет ожидание от БД и сети.


## Событийно-ориентированная архитектура

Решить предыдущую проблему поможет изменение парадигмы программирования.

Событийно-ориентированная архитектура подразумевает, что выполнение программы определяется событиями, на которые осуществилась "подписка". То есть мы говорим, что когда поступит событие успешного сохранения в БД, сделай то-то. 
Это то-то определяем в колбеке, который передаем отдельным аргументом. Из-за этого придется менять основную часть кодовой базы, которая крутится вокруг взаимодействия по сети.


Также приходится решать проблемы, связанные со сменой парадигмы.

- сохранение контекста между колбеками

- обработка исключений


Чтобы было нагляднее, традиционную парадигму с потоками можно сравнить с обувным магазином, где покупатель часто находится в ожидании, когда ему принесут обувь.
А событийно-ориентированную парадигму - с продуктовым магазином, где продавец всегда при деле находится и обслуживает очередь.


## Green Threads

Если брать обычные потоки, то их переключением занимается планировщик в составе операционной системы.
Однако можно написать собственный планировщик, который бы управлял зелеными потоками (эмуляция многопоточной среды - подпрограмма), переключаясь между ними в момент ожидания операций ввода/вывода в одном.
Соответственно, если операция сугубо процессорная, то профита не будет.

Тогда если соединить вместе друг с другом свой планировщик и машину событий, то получим таком порядок выполнения операции:


1. Регистрация событий в машине состояний
2. Передача управления планировщику
3. При наступлении события планировщик будит зеленый поток
4. Программа работает с данными от события, которое наступило в пред. пункте

Т.е. зеленый поток усыпляется до тех пор, пока не наступает событие.

Такой подход подразумевает использования библиотеки для использования зеленых потоков и написания кода-оберток над БД и сетевых вызовов.