Введение

Привет, я Михаил Ковалев, Python-разработчик в Точке.

Именно в Точке я впервые столкнулся с микросервисами и конкурентной средой. В предыдущих компаниях мне не приходилось с ними работать. Не то чтобы я жил в уверенности, что Монолит исполнит все мои желания, просто таковы были особенности проектов.

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

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

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

Все примеры будут на Python. Однако это будет полезно всем, кто имеет небольшой опыт разработки для конкурентной среды. А вставки кода на Python можете рассматривать как обычный псевдокод ????

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

Цех разработки Точки

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

Кроме сервисов на Python, у нас есть сервисы на PHP, Java, GO и т.д. Даже внутри Python-комьюнити нет единого стандарта: кто-то пишет на Django, кто-то предпочитает Flask или FastAPI, а кто-то комбинирует различные инструменты.

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

Однако, все эти сервисы не существуют каждый в своём изолированном пространстве: им надо как-то общаться между собой. Давайте посмотрим, как это происходит.

Для взаимодействия сервисов существует два основных способа:

  • Взаимодействие через HTTP.

  • Сервисная шина предприятия (Enterprise Service Bus или просто ESB).

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

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

Например, сервис, управляющий платежами, не хранит информацию о том, какие сервисы надо уведомить об изменении статуса платежа. Он просто забрасывает сообщение в шину. Если кто-то из адресатов в данный момент недоступен, сервис-отправитель не заботится о том, чтобы послать уведомление повторно: за него это сделает ESB. А ещё шина следит за маршрутами сообщений, чтобы сервис, отвечающий за рассылку email-ов пользователям, не мог отправлять запросы на создание платежей.

Мы ещё вернёмся к ESB в следующих статьях, когда будем рассматривать особенности отправки и обработки сообщений.

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

  • каждый экземпляр в любой момент может начать обрабатывать данные, которые уже обрабатывает другой экземпляр;

  • одновременно пришли два запроса с противоположными требованиями: например, на создание платежа и блокировку счета;

  • запрос дошел до адресата, а ответ отправителю уже нет — например, из-за проблем с сетью;

  • или ответ может быть и дошел, а отправителя уже нет, потому что к нему пришёл OOM Killer.

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

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

Поэтому нам крайне важна консистентность данных во всех наших сервисах, ведь при её нарушении мы рискуем как минимум нарваться на немаленькие такие штрафы при очередной сдаче отчётности, а как максимум – потерять лояльность наших клиентов. ????

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

А пока напишите в комментариях, живёте ли вы в монолите или в микросервисах? Есть ли у вас проблемы, связанные с конкурентностью? Как вы справляетесь с ними?

Комментарии (2)


  1. murkin-kot
    21.12.2022 13:05

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


    1. mixon271 Автор
      21.12.2022 23:17

      Разумеется, это затевалось не ради неожиданных проблем :slightly_smiling_face:

      Цель всего цикла статей -- рассказать о наших подходах к решению определённого круга проблем. И в самом начале я решил очертить круг проблем и почему они вообще возникают

      Цель данной статьи не в том, чтобы показать преимущества или недостатки микросервисов. Её цель -- описать реальность, в которой работают наши разработчики