Друзья, привет! Если у вас так же много разработчиков как у нас, то и им, возможно,  стало тесно стоять в очереди на deploy в монолите. А значит, вы можете решить перейти на микросервисную архитектуру и дать каждому игроку свой мяч каждой команде свой микросервис. 

В микросервисной архитектуре вы столкнётесь с новыми проблемами, которые не встретишь в монолите. Много сервисов означает много узлов отказа, а значит теперь вам придется следить за их стабильностью как за единым целым. Ещё много одинаковой логики по подключению к хранилищам и отправке метрик. И это только начало списка. Решить часть этих проблем вам поможет IT-платформа PaaS — техническое решение и команда, которая его развивает и поддерживает.

Платформа:

  • помогает пользователям не отвлекаться от бизнес задач: не делать свои версии адаптеров к хранилищам и отправку метрик;

  • стандартизировать технологии и решения в компании и тем самым экономить усилия на поддержку инфраструктуры;

  • автоматически предупреждать проблемы стабильности;

  • следить за всеми микросервисами как за единой системой.

Это вторая статья из цикла, посвященного PaaS. В первой статье мой коллега, Александр Ермолаев, рассказал, с каких инструментов и принципов мы начинали делать платформу в далеком 2020-м.

Меня зовут Дмитрий Лукиянчук, и я руковожу отделом в IT-платформе СберМаркета. В этой статье я сделаю обзор инструментов, которые есть у нас сейчас, спустя 2,5 года, и какие задачи эти инструменты решают. Вы узнаете, что вам нужно будет сделать, если вы сами решите взяться за построение платформы. А если у вас уже есть своя платформа, то вам будет интересно найти 10 отличий в своей и нашей реализации.

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

  1. Технологический стек

  2. Шаблон и библиотека микросервиса

  3. sbm-cli: Управление сервисом из консоли

  4. CI/CD pipeline

  5. Deploy

  6. Внутренний портал разработчика

  7. Grafana service dashboard и алерты

  8. Поиск по всем сервисам и сбор статистики

  9. Чат поддержки

  10. Документация

  11. Заключение

Технологический стек

Сейчас наша платформа поддерживает работу с четырьмя языками:

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

  • Ruby — наш монолит был написан на Ruby и у нас большая команда разработчиков на этом языке. Благодаря платформе они могут быстро создавать новые микросервисы.

  • Python — основной язык наших специалистов по машинному обучению.
    Для python, кроме шаблона «микросервиса-сервера», планируем сделать ещё и «шаблон-airflow» для описания pipeline для ML.

  • JavaScript — язык для frontend-сервисов.

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

  • Postgres, если нужна реляционная база данных.

  • Redis для кэша, синхронизации задач между экземплярами сервиса и иногда как key-value хранилище.

  • Clickhouse, если нужна колоночная база данных.

  • Flipt для feature flag.

В качестве транспорта используем три технологии:

  • Protobuf over Kafka. Для асинхронного взаимодействия между сервисами используем Kafka, сообщения кодируем в формате protobuf.

Для работы c Protobuf over Kafka в командной строке выпустили в open source утилиту protokaf.

  • gRPC — для синхронного взаимодействия между сервисами.

Для моков gRPC-запросов мы выпустили в open source gRPC Wiremock. О нем Никита Смирнов из моей команды рассказывает в статье Как мы сделали grpc-wiremock: сервис, создающий мок-сервер для ваших контрактов в одну команду.

  • HTTP — для выставления API наружу -для web, mobile клиентов и внешних партнерских сервисов.

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

Немного о нашей инфраструктуре:

  • Kubernetes — здесь живут наши сервисы.

  • Istio — используем для контроля сетевого взаимодействия: rate limiter, circuit breaker, маршрутизация запросов по заголовкам и прочее.

  • Victoria metrics и Grafana — для сбора, хранения и отображения метрик.

  • Kibana — для поиска по логам.

  • Jaeger — для анализа трасс сквозных запросов.

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

Шаблон и библиотека микросервиса

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

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

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

  2. Стандартизировать технологии и решения в компании и тем самым экономить усилия на поддержку инфраструктуры.

  3. Автоматически предупреждать проблемы стабильности.

В самом простом виде шаблон — это git clone репозитория-скелетона с последующей заменой названия и путей на название и пути сервиса. Но представьте: пользователи создали несколько сервисов из вашего шаблона, прошла неделя, и в ядре шаблона вы обнаружили баг, теперь вам нужно сделать merge request в каждый сервис! 

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

Ещё вы захотите отделить файлы ядра, оставшиеся в сервисе, от пользовательских. Например, пользовательские gitlab-файлы. Это позволит вам в будущем обновлять файлы ядра простой заменой.

Наш шаблон микросервиса состоит из четырех частей:

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

  • Конфиги с описанием используемых хранилищ, переменных и сведений о сервисе.

  • Импорта нашей библиотеки — она содержит объект приложения, пакеты транспорта и хранилищ, функции-помощники. Каждый пакет библиотеки отправляет метрики, пишет логи, задает настройки по умолчанию, улучшающие стабильность сервиса.

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

Инициализация приложения на основе платформенной библиотеки go-libs
Инициализация приложения на основе платформенной библиотеки go-libs

sbm-cli: Управление сервисом из консоли

Довольно быстро вы решите, что пользователям неудобно пользоваться длинной инструкцией и захотите дать им возможность создавать сервис одной командой. Поэтому в СберМаркете мы сделали sbm-cli — консольный клиент для создания сервиса и других сценариев работы с ним.

Основные команды консольной утилиты sbm-cli
Основные команды консольной утилиты sbm-cli

sbm-cli позволяет создать сервис и обновлять его:

  • $ sbm-cli service create https://path/to/gitlab/repo — чтобы создать сервис;

  • $ sbm-cli service upgrade — чтобы обновить платформенную библиотеку и ядро шаблона в сервисе.

sbm-cli дает возможность запустить сервис локально в playground, нашем решении на основе docker compose:

  • $ sbm-cli service up — запуск сервиса в docker compose;

  • $ sbm-cli service status — получение статуса playground и подсказок для обращения к сервису и хранилищам;

  • $ sbm-cli service down — остановка.

Подробно про playground смотрите в моем докладе на PaaS Meetup.

sbm-cli предоставляет инструменты для ежедневной разработки:

  • создание и применение миграций;

  • генерация серверного кода;

  • добавление и генерация клиентов для общения с другими сервисами.

Кстати, возможность генерировать серверный код и клиенты мы получили как раз благодаря применению API first подхода. О нем я писал в разделе «Технологический стек».

Пример запуска Playground
Пример запуска Playground

CI/CD pipeline

После того как сервис создан, начинается ежедневная работа с ним. В сервисе есть файл .gitlab-ci.yml. Он импортирует в себя задачи для исполнения в базовом gitlab pipeline. Также, он импортирует файл .gitlab-ci-usr.yml, лежащий рядом. В этот файл пользователь может добавлять свои задачи.

Базовый gitlab pipeline реализует flow работы с git для совместной разработки сервиса и контроля качества. Flow работы с git у нас состоит из трех итераций:

  • Pipeline ветки: путь от написания кода локально до деплоя на фича стейдж и мержа в мастер ветку.

  • Pipeline мастера: путь от мержа в мастер ветки до деплоя на стейдж и создания релиза.

  • Pipeline релиза: путь от создания релиза до деплоя в прод.

Pipeline каждой итерации включает в себя:

  • прогон автотестов и линтеров:

    • юнит тесты, тесты с playground, контрактные тесты;

    • линтеры на код;

    • валидация конфигов;

    • проверка свежести версий библиотек и docker-образов;

    • проверка кода скриптами безопасности;

  • сборка кода — собранный образ используется во время deploy;

  • deploy — для каждой итерации deploy происходит в свою среду.

Pipeline релиза
Pipeline релиза

Deploy

В prod и stage, наши сервисы живут в отдельных кластерах kubernetes. Прямое сетевое взаимодействие между кластерами запрещено. Это помогает избежать путанницы, повышает безопасность и стабильность.

В prod можно деплоить только из pipeline релиза. Deploy на прод всегда несет риск — новый релиз может содержать ошибку. Чтобы уменьшить его, мы реализовали канареечный деплой на базе Argo rollouts: Pod’ы сервиса новой версии поднимаются и убираются по одному, а трафик запросов переводится на новые pod’ы попроцентно. Если это приводит к росту ошибок и нежелательному изменению метрик, то деплой останавливается и сервис возвращается на предыдущую версию.

Подробнее о том, как устроен канареечный деплой, рассказывал Антон малафеев на PaaS Meetup.

У нас есть только одно окружение, повторяющее prod полностью — stable stage. В нем представлены все сервисы и там они взаимодействуют друг с другом. В это окружение можно деплоить только из pipeline мастера. Мы держим только одно такое полное окружение по двум причинам:

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

  • Также, кратно возрастают затраты на инфраструктуру.

Pipeline ветки позволяет задеплоить код для тестирования на feature stage — его pod’ы разворачиваются в том же кластере, что и stable stage, но трафик со stable stage на них не идет. Сам же сервис из feature stage по умолчанию обращается к сервисам-зависимостям, развернутым в stable stage. Это позволяет тестировать сервис в одиночку.

Но иногда бывает нужно собрать контур из нескольких сервисов на разработческих ветках так, чтобы эти сервисы взаимодействовали друг с другом. Это можно сделать на внутреннем портале разработчика. О нем я чуть подробнее расскажу в разделе «Внутренний портал разработчика». В этом случае для каждого сервиса создается свой feature stage и все сервисы обращаются по сети друг к другу. Для взаимодействия через Kafka система создает временные топики, чтобы избежать гонки чтения между feature и stable stage.

О контуре из нескольких сервисов мой коллега Рома Шпак рассказывал на PaaaS Meetup.

Внутренний портал разработчика

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

  • посмотреть карту взаимосвязей микросервисов — можно выбрать интересующий вас транспорт (см. раздел «Технологический стек») и сравнить реальный трафик между сервисами с объявленным в конфиге;

  • посмотреть единый журнал событий, происходящих по всей системе — деплои сервисов, алерты и другие;

  • развернуть контур связанных сервисов на feature stage (см. раздел «Deploy»);

  • изучить индивидуальную карточку сервиса с информацией о нем;

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

  • запустить нагрузочное тестирование на сервис — для нагрузочных тестов используем k6.

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

Grafana service dashboard и алерты

Важный инструмент для обеспечения стабильности — dashboard сервиса в Grafana. Это «зрение» владельца сервиса для понимания, как сервис чувствует себя в prod окружении.

Как вы помните, сервисы созданы из одного шаблона и используют одни и те же платформенные библиотеки а, значит, отправляют одинаковый набор метрик в Victoria metrics. Одинаковость этого набора позволила сделать единый дашборд, на котором можно выбрать имя сервиса и увидеть что с ним происходит: трафик запросов, нагрузка на CPU, состояние хранилищ, отдельных библиотек, runtime языка и другое. К этому dashboard’у привязаны также ссылки на более подробные дашборды по каждому компоненту.

Grafana service dashboard
Grafana service dashboard

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

Поиск по всем сервисам и сбор статистики

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

  • быстро находить сервис с нужными параметрами для тестирования фич;

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

  • собирать отчет со статистикой использования функционала;

  • отправлять merge request на обновление PaaS библиотек во всех сервисах.

Чат поддержки

Техническую поддержку пользователей мы ведем в выделенном чате в Mattermost (аналоге Slack). Там мы помогаем пользователям решить возникшие сложности, собираем проблемы для решения и идеи для реализации, узнаем, что нужно добавить в документацию.

Документация

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

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

Заключение

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

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

Tech-команда СберМаркета ведет соцсети с новостями и анонсами. Если хочешь узнать, что под капотом высоконагруженного e-commerce, следи за нами в Telegram и на  YouTube. А также слушай подкаст «Для tech и этих» от наших it-менеджеров.

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


  1. diamFC
    30.09.2023 06:32

    Здравствуйте. Спасибо за статью.

    Расскажите про инструмент отображения зависимостей между сервисами. На картинке у вас Huginn


    1. wtertius Автор
      30.09.2023 06:32

      Приветствую!

      Huginn - это название нашего внутреннего портала разработчика.

      Зависимости мы отображаем в нем в разных представлениях:
      1) Карта сервисов. Можно приблизить и посмотреть названия, можно в строке поиска найти свой сервис. Фактические связи - строятся на основании статистики реального взаимодействия, собранной с istio. Задекларированные связи - берутся из конфигов сервисов.

      Карта сервисов
      Карта сервисов

      2) На карточке сервиса указаны его зависимости - другие сервисы и базы данных.

      Зависимости в карточке сервиса
      Зависимости в карточке сервиса

      3) Карта связей топиков и сервисов

      Карта связей топиков и сервисов
      Карта связей топиков и сервисов


      В рамках этого цикла статей планируем выпустить отдельную про Huginn.


  1. Arcanebinder
    30.09.2023 06:32

    помогает пользователям не отвлекаться от бизнес задач:

    Если у пользователя есть биззадача - он от неё не отвлечется. (Не плодить сущности)

    стандартизировать технологии и решения в компании и тем самым экономить усилия на поддержку инфраструктуры;

    Всё уже стандартизировано до вас. (IEEE)

    автоматически предупреждать проблемы стабильности;

    Если есть проблема стабильности - выяснить корень и исключить его.

    следить за всеми микросервисами как за единой системой.

    Микросервисы должны умереть. (Не плодить сущности(см.п1)


    1. wtertius Автор
      30.09.2023 06:32

      Здравствуйте!

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

      С другой стороны, если у вас больше 50ти команд, которые разрабатывают монолит, то как бы вы организовали совместную работу с кодовой базой?


  1. artschedrov
    30.09.2023 06:32
    -1

    NodeJS — язык для frontend-сервисов.

    Я конечно извиняюсь, но когда это NodeJS стал языком?


    1. wtertius Автор
      30.09.2023 06:32

      Спасибо, уточнил формулировку - JavaScript