О асинхронных процессах
Привет!
Недавно мы в kruguss столкнулись с проблемой, наш сервис сбора информации о пользователях (браузер, ip адрес и так далее) стал медленно отвечать, ранее значение response time было 30 - 40мс, деградировало оно до 200мс, причина была нам понятна, мы обращались к внешним api сервисам в том же потоке что и исполнялся внутренний код (хождение в базу и так далее). Решение долго себя ждать не заставило, мы решили сделать асинхронную обработку запроса, потому что результат тут же нам был не нужен, по-этому мы смогли применить эту парадигму.
Немного о сервисе, сервис собирает информацию о пользователе из разных источников, начиная от браузера клиента и операционной системы, заканчивая его страницами в соц.сетях. Соответственно мы делаем много запросов к внешним сервисам, которые могут где-то медленно работать, где-то вообще быть в down time'е.
Для своего асинхронного решения мы решили использовать rabbitmq (это брокер сообщений позволяющий обрабатывать десятки тысяч сообщений в секунду). Немного архитектуры
Мы здесь видим бекенд который принимает запросы и в ответ сразу возвращает http статус 202 (принято) и отправляет сообщение в rabbitmq, у rabbitmq есть консюмер который слушает сообщения из очереди и обрабатывает уже их, отправляет все нужные запросы на отдельные сервера которые обеспечивают нас дополнительной информацией и пишет результаты в денормализованном виде в postgresql.
Вы наверное уже подумали, а что будет если упадет rabbitmq?
- А если упадет rabbitmq, то ничего страшного, все сообщения он сохраняет на диске (durable сообщения) и когда rabbitmq восстановится и снова будет в строю, то он дошлет нашему consumer'у остальные сообщения (наш consumer так же переподключится автоматически)
Наверное у Вас появился еще один вопрос, а что будет если упадет приложение?
- А ничего, rabbit будет накапливать сообщения пока не поднимется приложение, когда оно поднимется, мы обработаем накопившиеся сообщения.
А теперь выводы:
- Мы отказались от синхронной обработки запроса на бекенде в пользу асинхронной и увеличили пропускную способность http endpoint'а вместе с response time
- Мы получили систему которая может проще масштабироваться
- Мы уменьшили response time c 200мс до 10мс без кешей! Профит? Мы думаем, что да.