Опыт Построения Инфраструктуры На Микросервисной Архитектуре



Опыт построения инфраструктуры на микросервисной архитектуре

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

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

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

Но прежде чем вы решите пойти на такой шаг, вам необходимо ответить на 3 главных вопроса:

  • Как разбить монолит на микросервисы и каких критериев следует придерживаться.

  • Как будут взаимодействовать микросервисы?
  • Как контролировать?
Кратким ответам на эти вопросы и будет посвящена данная статья.



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

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

Мы банк, поэтому вся система крутится вокруг операций с финансами и разных вспомогательных вещей.

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

Таким образом, мы разработали следующие правила:

  • Следуйте букве S SOLID применительно к микросервисам.

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

  • Для работы микросервису необходима информация из собственной базы данных или из запроса.

  • Постарайтесь обеспечить чистоту (в смысле функциональных языков) микросервисов.

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



Как будут взаимодействовать микросервисы?

Вариантов много, но в конечном итоге все их можно абстрагировать до простого «обмена сообщениями микросервисов», но если реализовать синхронный протокол (например, RPC поверх REST), то большая часть недостатков монолита останется, но преимущества микросервисов почти не проявятся.

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

Выбирая между RabbitMQ и Kafka, мы выбрали последнее и вот почему:

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

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

  • Понятный и простой способ масштабирования сервиса: добавьте разделы в тему, запустите больше подписчиков — все остальное сделает Kafka.
Дополнительно хотелось бы обратить внимание на очень качественное и подробное сравнение .

Очереди Kafka + асинхронность позволяют нам:

  • Кратковременно отключите любой микросервис для обновлений без заметных последствий для других.

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

    Например, недавно произошел сбой микросервиса фискализации.

    Устранили за 2 часа, он забрал необработанные купюры у Кафки и все обработал.

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

  • Запускайте тестовые версии сервисов на текущих производственных данных и сравнивайте результаты их обработки с производственной версией сервиса.

В качестве системы сериализации данных мы выбрали AVRO; почему описано в отдельная статья .

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

Хотя AVRO поддерживает Разрешение схемы Мы этим не пользуемся и решаем чисто административно:

  • Данные в топиках записываются и читаются только через AVRO, название топика соответствует названию схемы (и Confluent другой подход — они записывают AVRO ID схемы из реестра в старшие байты сообщения, поэтому в одной теме могут быть сообщения разных типов
  • Если вам нужно дополнить или изменить данные, то в Kafka создается новая диаграмма с новой темой, после чего на новую тему переходят все производители, а за ними и подписчики.

Сами схемы AVRO мы храним в подмодулях git и подключаем их ко всем проектам Kafka. Централизованный реестр схем решили пока не внедрять.

P.S.: Коллеги.

сделал вариант с открытым исходным кодом, но только с JSON-схемой вместо AVRO .



Некоторые тонкости



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

Это особенность модели взаимодействия «публикация-подписка» — подписавшись на тему, подписчик получит их все.

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

Если это станет проблемой, то можно будет сделать отдельный сервисный маршрутизатор, который будет распределять сообщения по нескольким разным темам, реализовав тем самым часть функционала RabbitMQ, отсутствующего в Kafka. Сейчас у нас есть один подписчик Python в одном потоке, обрабатывающий примерно 7-5 тысяч сообщений в секунду, но если запустить его через PyPy, то скорость возрастает до 11-15 тысяч/сек.



Ограничение времени жизни указателя в теме

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

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



Срок для подтверждения прочтения

Если читатель Kafka не подтверждает чтение в течение 30 секунд (настраиваемый параметр), то брокер считает, что что-то пошло не так и при попытке подтверждения чтения возникает ошибка.

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



График подключения труден для понимания

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

Чтобы как-то сделать его (граф связей) читабельным, мы договорились о следующих обозначениях: микросервисы — овалы, топики Kafka — прямоугольники.

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

Но, увы, лучше не становится.

Так что этот вопрос пока открыт.

Опыт построения инфраструктуры на микросервисной архитектуре



Как контролировать?

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

Нет логов - нет работы.

Затем они начали использовать Прометей и кафка-экспортер немного доработал свою приборную панель: https://github.com/kkirsanov/articles/blob/master/2019-habr-kafka/dashboard.json В результате получаем следующие картинки:

Опыт построения инфраструктуры на микросервисной архитектуре

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

Дополнительно в InfluxDB копируются все сообщения из ключевых (платежные операции, уведомления от партнёров и т.д.) тем, заносимые в ту же графану.

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

Итак, ответы на вопросы типа «каково среднее время задержки ответа от сервиса» или «Сильно ли поток транзакций сегодня отличается от вчерашнего для этого магазина» всегда под рукой.

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

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

Получается аналог zipkin/opentracing для MQ, позволяющий легко восстановить его путь на графе после получения сообщения.

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

Вспомните пример с небольшим сервисом, доля платежей которого составляет всего 0,0001%.

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

Теги: #python #DevOps #Микросервисы #Системный анализ и проектирование #kafka

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

Автор Статьи


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

Dima Manisha

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