Как Мы Строим Систему Обработки Сообщений

Наша команда занимается разработкой серверной системы обработки сообщений с мобильных устройств.

Устройства собирают информацию о работе сложного оборудования и отправляют сообщения в процессинговый центр.

В этой статье я хочу поделиться подходами к построению таких систем.

Идеи достаточно общие, их можно применить к любой системе со следующей архитектурой:

Как мы строим систему обработки сообщений

По каналам связи устройства отправляют сообщения на наш шлюз — точку входа приложения.

Задача приложения — выяснить, что именно пришло, выполнить необходимые действия и сохранить информацию в базе данных для дальнейшего анализа.

Будем рассматривать базу как конечную точку обработки.

Звучит просто, но по мере роста количества и разнообразия сообщений появляется несколько нюансов, которые я хочу обсудить.

Немного об уровне нагрузки.

Наша система обрабатывает сообщения от десятков тысяч устройств, при этом в среднем мы получаем от нескольких сотен до тысячи сообщений в секунду.

Если ваши цифры отличаются на пару порядков в ту или иную сторону, возможно, набор ваших проблем и подходы к их решению будут другими.

Помимо реального количества сообщений в секунду, существует проблема их неравномерного поступления.

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

Для решения этой проблемы система организована как набор очередей и их обработчиков.

Принимающий шлюз не выполняет никакой реальной работы — он просто получает сообщение от клиента и помещает его в очередь.

Это очень дешевая операция, поэтому шлюз способен принимать огромное количество сообщений в секунду.

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

Обработка является асинхронной, и нагрузка постоянно ограничивается.

Возможно, в пик время пребывания сообщений в очереди немного увеличится, вот и все.

Зачастую обработка сообщения нетривиальна и состоит из нескольких действий.

Следующий логичный шаг — разбить работу на несколько этапов: несколько очередей и обработчиков.

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

Как мы строим систему обработки сообщений

Первая очередь содержит сообщения по мере их поступления с устройства.

Обработчик декодирует их и помещает во вторую очередь.

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

Это основная ситуация, о чем еще нужно подумать?



Выбор ценностей



1. Легко создавать, изменять и поддерживать.

Асинхронная распределенная обработка сообщений усложняет программный продукт. Мы постоянно работаем над снижением этой цены.

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

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

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

Мы стараемся постоянно проводить рефакторинг, если чувствуем, что код можно сделать немного лучше и проще.

Все источники просматриваются, а наиболее важные части обычно разрабатываются парами.



2. Отказоустойчивость
Имеет смысл сразу определить требования к способности системы продолжать функционировать в случае отказов оборудования и подсистем.

Они будут разными для всех.

Возможно, кто-то готов просто выкинуть все сообщения за те 5 минут, что перезагружается один из серверов.

В нашей системе мы не хотим терять сообщения.

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

Зависимые сообщения должны оставаться в очереди и будут обработаны, как только проблема будет решена.

Допустим, ваш код на одном сервере синхронно вызывает веб-службу на другом сервере.

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

При асинхронной обработке сообщение будет ждать, пока второй сервер снова подключится к сети.



3. Производительность
Количество сообщений, обработанных в единицу времени, задержка, нагрузка на сервер — все это важные параметры производительности системы.

Именно поэтому мы закладываем в проект гибкую архитектуру.

Однако не стоит с самого начала зацикливаться на оптимизации.

Как правило, подавляющее большинство проблем с производительностью вызвано относительно небольшими фрагментами кода.

К сожалению, мало кто способен заранее предсказать, где именно будут эти проблемы.

Здесь люди пишут целые книги по преждевременной оптимизации .

Убедитесь, что ваша архитектура позволяет быстро настроить систему и забыть об оптимизации перед первыми нагрузочными тестами.

При этом нагрузочные тесты следует начинать заранее и затем сделать частью стандартной процедуры тестирования.

И только когда тесты покажут конкретную проблему, приступайте к оптимизации.



Настройка мозга



1. Работа с очередями и асинхронными обработчиками
Я уже писал об этом выше.

Наши основные инструменты — очереди и их обработчики.

В дополнение к классическому стилю организации кода «получил запрос, назвал удаленный код, дождался ответа, вернул ответ наверх», мы получаем «получил сообщение из очереди, обработал его, отправил сообщение другому».

подход «очередь».

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



2. Разбейте обработку на несколько этапов
Если обработка сообщений достаточно сложна и может быть разбита на несколько этапов, предусмотрите несколько очередей и обработчиков.

Имейте в виду, что чрезмерная фрагментация может затруднить понимание системы.

Здесь должен быть баланс.

Довольно часто встречается раздел, естественный и понятный разработчикам.

Если нет, попробуйте подумать о точках отказа.

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



3. Не смешивайте декодирование и обработку
Обычно сообщение приходит в формате какого-либо протокола взаимодействия устройств в сети: бинарный, xml, json и т.д. Раскодируйте и преобразуйте их в свой внутренний формат как можно раньше.

Это решит как минимум две проблемы.

Во-первых, протоколов может быть несколько; После декодирования можно унифицировать формат дальнейших сообщений.

Во-вторых, упрощается ведение журнала и отладка.



4. Упростите перенастройку очередей
Структурируйте свой код обработки так, чтобы вы могли легко изменить конфигурацию очереди.

Разделение обработчика на две части не должно приводить к тонненому рефакторингу.

Не позволяйте вашему коду слишком сильно зависеть от конкретной реализации очереди; завтра ты, возможно, захочешь это изменить.



5. Обработка сообщений в группах
Часто имеет смысл получать сообщения из очереди не по одному, а сразу группами.

Сервисы, которые вы используете, могут принимать огромные объемы данных для пакетной обработки, и в этом случае один большой вызов обычно будет намного эффективнее, чем сотня маленьких.

Вставка сотен записей в базу данных за раз будет быстрее, чем сто удаленных вызовов.



Создание инструментов



1. Внедрить тотальный надзор
Инвестируйте в мониторинг с самого начала.

Вы должны легко и наглядно увидеть график пропускной способности, среднего времени обработки, текущего размера очереди, времени с момента последнего сообщения с разбивкой по очереди.



Как мы строим систему обработки сообщений

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

Правильно настроенные графики и уведомления очень полезны для отладки и предварительного нагрузочного тестирования.



2. Тестируйте все
Системы обработки сообщений являются идеальным полигоном для автоматизированного тестирования.

Протокол ввода определен и ограничен, взаимодействия с живыми людьми нет. Покройте свой код модульными тестами.

Обеспечить возможность замены боевых очередей на тестовые очереди в локальной памяти и делать быстрые тесты взаимодействия обработчиков.

Наконец, проведите полноценные интеграционные тесты, которые можно будет запустить в бета- (промежуточной) среде (а еще лучше — в рабочей среде).



3. Создайте сборник ошибочных сообщений.

Чаще всего вы не хотите, чтобы ошибка при обработке одного сообщения остановила всю очередь.

Не менее важно умение диагностировать ошибку.

Поместите такие сообщения в специальное хранилище и сосредоточьте все свое внимание на этом хранилище.

Обеспечьте возможность легко переместить сообщение обратно в очередь обработки после устранения причины ошибки.

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

Мы держим их в отстойнике и периодически проверяем, не пришло ли время.



4. Автоматизируйте развертывание
Установка и обновление системы должны происходить в один или несколько кликов.

Стремитесь к частым обновлениям продукта, в идеале — к автоматическому развертыванию после каждой фиксации в основной ветке.

Сценарий установки поможет разработчикам поддерживать свою личную среду и среду тестирования в актуальном состоянии.



Вместо заключения

Хорошая, понятная архитектура — это также способ упростить общение между разработчиками, их общее видение и набор концепций.

В этом смысле нам очень помогло сформулировать системную метафору в виде картинки, с которой мы можем начать многие дискуссии в проекте.

Наша метафора похожа на эту картинку из Статьи дяди Боба Чистая архитектура :

Как мы строим систему обработки сообщений

На нашей диаграмме мы выявляем сущности системы и их зависимости, что помогает в обсуждении приблизиться к правильному проектированию, найти ошибки или спланировать рефакторинг.

Теги: #очередь сообщений #асинхронность #масштабируемость #дизайн #личный опыт #отказоустойчивость #разработка веб-сайтов #Анализ и проектирование систем #проектирование и рефакторинг

Вместе с данным постом часто просматривают:

Автор Статьи


Зарегистрирован: 2019-12-10 15:07:06
Баллов опыта: 0
Всего постов на сайте: 0
Всего комментарий на сайте: 0
Dima Manisha

Dima Manisha

Эксперт Wmlog. Профессиональный веб-мастер, SEO-специалист, дизайнер, маркетолог и интернет-предприниматель.