«Профит велик. Мы получили множество свобод, которыми не обладали раньше», — Владимир Плизга о микросервисах

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


Сегодня мы поговорим о внедрении микросервисной архитектуры в Центре Финансовых Технологий (ЦФТ) — группе компаний, работающих в области информационных технологий для финансового сектора с 1991 года. То есть это организация, где качество продукта чрезвычайно важно, от него зависят реальные деньги.


В свою очередь, Владимир Плизга последние 6 лет погружен в разработку бэкенда интернет-банков и сопутствующих сервисов в ЦФТ, где активно топит за микросервисы и прочие модные штуки. Чтобы пообщаться с ним, я приехал прямо в офис ЦФТ, сделал сэлфи и обязательную фотку красного слона :-)


Обсуждаемые темы:


  • Зачем нужны микросервисы;
  • Как с ними жить (судьба REST и SOAP, statefull vs. stateless, переход от монолита к микросервисам, совместимость с legacy и многое другое);
  • Микросервисные технологии (Spring Cloud Netflix, Zuul, …), какие с ними проблемы, что нужно допиливать;
  • Документация: на русском или английском? Написание и генерация документации (Swagger, SpringMVC, SpringFox). Архитектурные диаграммы — нужны ли, в чем рисовать, как хранить;
  • Мониторинг, восстановление от сбоев;
  • Ну и самое главное: стоит ли игра свеч?


-sl3d4bb4psfnjwcgqqcsebaah8.png


nzqguy-ia0-5s_aullz5kjfzliw.png


(слева — Владимир, справа — olegchir)


— Зовут меня Владимир Плизга, работаю в компании ЦФТ уже несколько лет. В основном занимаюсь бэкенд-разработкой на Java. До этого совсем немного работал в других областях, но это можно отнести к студенческому и пост-студенческому периоду. Если быть более точным, то сейчас занимаюсь разработкой финансовых сервисов — и не какими-то там брокерами и котировками, как часто думают, слыша слово «финансы», а интернет-банками и сопутствующими сервисами. Например, такие инструменты, как сайты отслеживания подарочных карт — когда людям вместо наличных денег дарят универсальную брендированную карточку, которой можно рассчитываться везде, где принимают эти карты. К ней прилагается приложение, с помощью которого можно контролировать расходы по этой карточке, смотреть историю, активировать, прочие профиты получать.


— Эта карточка-сертификат — она пополняемая?


— Зависит от того, какая модификация продукта. Большинство из них не пополняются. Сам ее приобретатель, тот, кто будет ее дарить, один раз пополняет карту на какую-то сумму, которая ему комфортна, обычно от 300 рублей до 15 тысяч рублей, дарит её, и всё. Есть отдельные модификации, где можно в том числе пополнять. Но это не сертификат, а именно платёжная карта, с чипом внутри, это полноценный такой финансовый продукт. Но он скорей побочный, а основное для нас — это именно предоплаченные карты, то есть те карты, которые для людей являются своего рода дополнением к кошельку, либо к электронному, либо к настоящему. Туда можно любым удобным способом запуливать деньги, а потом — рассчитываться ими хоть в интернете, хоть в магазинах, хоть через сам платежный кабинет (он у нас называется чаще всего не «интернет-банк», а именно «платёжный кабинет»), на всякие нужды, начиная от базовых платежных сервисов типа «оплатить садик», «оплатить ЖКХ» и прочее — в общей сложности более 5 тысяч услуг поддерживается — и заканчивая всякими платежами с AliExpress и прочими. В принципе, любыми электронными.


Моя роль во всём этом заключается в том, что на текущий момент через меня проходят именно архитектурные решения о бэкенде. Это всё, что касается микросервисов. Сейчас мы на пути ухода от монолита к микросервисам, мы постепенно отпиливаем кусочки и новый функционал уже не добавляем в монолит, чтобы следовать правилу (кому-то уже надоевшему): чтобы вылезти из ямы, надо сначала перестать себе её копать. Занимаюсь также другими вещами, например, код-ревью, через меня проходит много бизнес-задач, в том числе по принципиально новому функционалу. Ну и сопутствующие дела по производительности, по архитектурным улучшениям… В каком-то смысле типичная работа бэкенд-разработчика.


— А ты прям архитектор-архитектор, рисуешь кубики в редакторе?


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


— А всё-таки, UML-диаграммки рисуете?


— Да, рисуем, но не вдаемся в крайности поддержки их синтаксиса, правильности и так далее.


— То есть они не являются источником генерации кода.


— Нет, не являются.


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


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


— Она генерится динамически из исходников?


— Нет, мы поддерживаем её в Confluence. Там есть плагин Gliffy, который позволяет на уровне абстрактных фигур достаточно легко поддерживать картинку. Перетаскивание одного блока не заставляет вручную перерисовывать всякие связи. Буквально вот такие базовые вещи пока нас удовлетворяют. За счёт того, что мы разделяем участки на отдельные диаграммы, нам нет необходимости поддерживать всю картину целиком, поскольку она и для восприятия в этом виде непригодна. Есть блоки, в которые можно провалиться и увидеть другой, обособленный участок, который тоже пригоден для непосредственного восприятия.


— У вас система разработана так красиво, грамотно и аккуратно, что вот эти блоки дают вменяемую структуру?


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


— Сейчас сколько есть микросервисов?


— Единицы десятков.


— Уже неплохо. У многих и такого нет :-)


— Но мы всё еще в начале пути.


— Какие у вас в этом начале пути стоят задачи?


— Задачи с точки зрения технического развития, архитектурного?


— Задачи с точки зрения чего угодно. Ты же здесь архитектор!


— Я хоть и архитектор, но в первую очередь я отталкиваюсь от потребностей бизнеса, коль скоро они для нас первоопределяющие. Бизнес хочет получить ценность, прямо сейчас. Поскольку мы пытаемся быть agile, мы допускаем, что какие-то вещи могут даже не пригодиться. Если мы во что-то вкладываемся, мы заведомо понимаем, что мы экспериментируем, проверяем, прощупываем почву. Исходя из этого, нам нужно построить свою разработку и свое приложение так, чтобы любая доработка была максимально дешевой — настолько дешевой, чтобы её было даже не жалко выкинуть. Разумеется, в абсолюте этого быть не может, но тем не менее, благодаря текущему направлению мы можем позволить себе в том или ином виде запилить какой-то кусочек инкрементально, не вкрапив его в монолит, куда он врастет корнями и поменяет всё вокруг себя, а сделать такую нашлёпочку рядом. Поиграться, посмотреть, как оно себя будет вести, что оно из себя будет представлять с точки зрения ценности конечному пользователю, и потом, при необходимости — выкинуть. Исходя из этих трех приоритетов: скорость, дешевизна и независимость от других компонентов — мы и пытаемся разрабатывать компоненты дальше.


В чём это проявляется чисто технически, если переходить от громких слов к делу. Нужно стараться не наращивать монолит. Он у нас и так достаточно большой, мы его так и называем — «ядро», всё, что его касается — «ядерное», «ядрёное», как-то ещё… В общем, туда по возможности больше не лезть. Естественно, строить коммуникации с внешними клиентами для нас (это и веб, и различные платформы mobile) нужно без участия этого ядра и сопутствующих ему сателлитов. То есть заводить все соединения напрямую через точку входа, чтобы там на уровне маршрутов, на уровне балансировщика нагрузки, можно было в любой момент отключать, переключать этот трафик и как-то контролировать его более гибко, чем когда он в едином потоке заливается в ядро.


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


— Этот шаблон на чём основан? На чем-то общеупотребительном, типа Spring Cloud, или что-то свое?


— По готовым Cloud-решениям… Возможно, мы даже не пойдем по этому пути, а будем использовать отдельные библиотеки. Это, в первую очередь, Eureka, Zuul — стандартные решения для реестра сервисов, точки входа.


— Вы это уже используете, или это направление развития?


— Уже используем. Точка входа и реестр сервисов уже сейчас в эксплуатации. Чтобы обкатать это решение, мы зарулили на него не боевой трафик от конечных пользователей, а вспомогательный с колл-центров, тот, который не такой активный и нагруженный. А что касается базы самого микросервиса, то это Spring Boot, как, в принципе, и у всех остальных. Не знаю, можно ли его считать «голым». Разумеется, с какими-то дополнительными фреймворками, чаще всего — фреймворками того же Spring. Мы больше всего упираем на спринговые решения.


— А вот вы прикручивали это самостоятельно или взяли, что есть? Например, Spring Cloud Netflix. То есть аннотации, RestTemplate и т.п.


— Да. Сейчас опыт наших микросервисов в том, что точка входа, что реестр сервиса — с точки зрения прикладного кода — они очень маленькие. Почти всё сводится к тому, что мы добавили аннотацию, а вся остальная прелесть лежит за пределами Java-кода: это скрипты сборки, скрипты старта, и всё, что касается его окружения и адаптации к нашим реалиям, CI/CD и дальше по девопсу. Правда, в точке входа мы ещё своих фильтров понапилили для дополнительного контроля доступа, вопросов безопасности, обеспечения обратной совместимости API — в общем, есть у нас свои допилки. Но опять же, даже само понятие фильтра — это абстракция, взятая из самой библиотеки Zuul, которая втянута в Spring Cloud.


— Понял. А всякие такие штуки, circuit breaker, собираетесь использовать?


— Да, собираемся. Но тут такая ситуация, что собираться-то собираемся, а сами уже используем. Просто Zuul, в поставке Spring Cloud, уже включает в себя Hystrix, и он уже работает, и мы уже вынуждены с его настройками разбираться, учитывать, что у него таймауты настраиваются, мягко говоря, нетривиальными способами, кое-какие приседания приходится делать. Мы его используем, но не могу сказать, что мы это делаем максимально сознательно и всё контролируем.


— Не было ли желания что-нибудь допилить? В Эврике, например. Или в Зууле.


— Zuul, к счастью, оказался достаточно гибок, чтобы такого желания не возникло. А, нет, вру. Есть у меня пул-реквестик на GitHub. Хотя нет, извиняюсь, сейчас это просто issue, а пул-реквест в разработке. В общем, оказалось, что Zuul из коробки не поддерживает кастомные HTTP-статусы. Под «кастомными» я подразумеваю те, которые не стандартизированы самим RFC на HTTP-протокол. 431 — незачем, никак не задан, нигде не светится. Оказалось, что в Зууле они внутри в кишках заложились на то, что приходящий код, который проксируется через точку входа наружу, обязательно будет соответствовать одному из элементов перечисления, зашитого в этот же самый исходный код самого Зуула. И когда туда приходит HTTP-статус, для которого нет мапинга, он падает. Причём падает очень плохо, обходного решения нет. Я им написал, они ответили — ну да, наверное, так, попробуй пофикси. Просто я еще обнаружил с удивлением для себя, что вот это место, где происходит основная поломка, оно несет в себе чисто отладочную роль. Оно призвано выкусить кусочек запроса, чтобы его правильно залогировать, и вот это «правильно» подразумевает, что будет логироваться не голый HTTP-статус, а элемент вот этого самого перечисления.


— Нужно развернуть обертку.


— И получается, что из-за отладки, которая может быть и отключена, но на таком уровне всё равно работает, падает всё приложение. На самом деле, острота этой проблемы упала. Мы передумали связываться с кастомными HTTP-статусами.


— Зачем они вам вообще были нужны?


— Была одна задумка, если интересно — в двух словах расскажу. Мы хотели с их помощью передавать оттенки происходящих ошибок или вообще ответов от конечных микросервисов. У нас каждый бизнес-сценарий подразумевает массу всяких всевозможных отклонений от результата. И для клиента зачастую важно знать, чем закончился бизнес-сценарий и каждый его шаг. Это может быть как необходимость повтора попытки, позже или прямо сейчас, причем повтора как сознательного пользователем, так и автоматического — клиентом. Это может свидетельствовать о необходимости показа диалогового окна с предложением что-нибудь там поменять. Если превратить конкретный пример, то пополнение с удалённой банковской карты, с которой мы перечисляем деньги на свои предоплаченные карты, может осуществляться как с комиссией, так и без. И разумеется, мы по умолчанию всегда пытаемся сделать это без комиссии. А если не получается, то мы обязаны явно уведомить пользователя, что что-то пошло не так, давай попробуем с комиссией. И вот такие штуки мы как раз хотели обруливать кастомными HTTP-статусами. Своими, прямо договариваться с собой на уровне API (весь API у нас документирован в Swagger) и там как раз и прописывать в формате: статус + что нужно сделать клиенту. Тема не зашла по нескольким причинам. Минорных причин было множество, но одна из главных: на тот момент у существующего монолита было сложившееся API, было принято передавать оттенки ошибок не в виде HTTP-статуса, а в виде полей, в самом теле ответа.


— А может, лучше поставить HTTP-заголовки?


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


— Ты сказал про Swagger. Какая у вас практика его использования? Насколько это хорошо? Есть ли там приятные или неприятные моменты?


— Хватает и тех, и других. Осмелюсь сказать, что приятных чуть больше, коль скоро уж мы на нём. Во-первых, самое главное, что мы заполучили (хотя здесь заслуга Swagger не такая уж большая) — это простота описания. Так уж получилось, что монолит у нас построен на Play Framework. В Play хоть и есть плагины для генерации swagger-документации, но, как это всегда бывает, по историческим причинам их писали разные люди в разное время, и эти плагины непригодны ни для чего, они у нас не работают. Поэтому документацию приходилось писать вручную. Прямо спецификацию, прямо сидеть и писать руками.


— Как большая часть мира сейчас и делает.


— Но, вот как ни крути, согласись, что ты то же самое пишешь кодом, зачем ещё сидеть и руками повторять?


— И еще раз в джавадоке. И четвёртый раз в тестах.


— Да! Зачем? Очень хотелось на этом сэкономить, поэтому, когда мы уже пошли по микросервисному пути, мы не стали изобретать никаких велосипедов, проанализировали несколько решений. На текущий момент самым мэйнстримовым, самым развитым решением показался SpringFox. Знаешь что-нибудь про него?


— Нет, ничего. Теперь вот название знаю.


— Этот генератор Swagger-документации на основе описаний контроллеров в самом Spring. В частности, в Spring Boot. Но на самом деле, под Boot он не сильно заточен, а ориентирован на SpringMVC, откуда все аннотации берутся. Но со Spring Boot дружит. Идея в том, что структура API, набор методов, их параметры — уже описаны в контроллере, в виде его методов и аннотаций, и их можно извлечь. Это уже львиная доля работы, скелет документации. Всё, чего тут не хватает — словесного описания. Но очевидно, что его достаточно легко добавить аннотациями в самом коде. Ровно по этому пути и идет SpringFox — берет аннотации Swagger (точнее, из подпроекта swagger-annotation, это часть генератора), применяет эти аннотации к контроллерам на Spring (SpringMVC, или SpringBoot в данном случае). Потом интерпретирует на лету, генерит Swagger-спецификацию. И в чём еще одна прелесть — прямо в составе микросервиса, выставляет еще один эндпоинт (не на отдельном порту, а на отдельном контексте), на котором открывается Swagger UI (эти красивые зеленые HTML-формы), где представлена вся документация, готовая не только для чтения, но и чтобы можно было поиграться с ней — сразу из коробки работают кнопки «try it out», чтобы отправить запрос в микросервис. На первый взгляд выглядит действительно как магия: не нужно вручную писать спецификацию, и в то же время она доступна. Есть отдельный URL, по которому ее можно запросить и потом скормить какому-нибудь SOAP UI или Postman. Всё это уже есть. Плюс к этому, на порту каждого микросервиса развернута документация (не нужно где-то искать, вспоминать), пригодная для чтения. Ещё один плюс — любое изменение в коде повлечет за собой изменение документации. Это надо еще постараться что-то такое написать и не заметить, что в этом же месте ты пишешь о том же самом в виде текста. В этом, конечно, существенный плюс такого решения.


Но, признаюсь честно, оно неидеально. Не все гладко. Сам SpringFox хотя и хорошо ориентируется в аннотациях и в структурах запросов Спринга, но не идеально. В частности, есть проблемы с коллекциями. Когда из методов возвращаются коллекционные типы, то он кривовато это представляет в UI. К тому же он позволяет тюнить не все те параметры, которые предоставляет голый Swagger — есть хотелки, которые следовало бы учесть. Есть ещё ряд шероховатостей. Но в целом, вполне рабочий подход. Но правда, и нам для этого пришлось перегруппироваться. Если раньше мы не стесняясь добавляли в сами контроллеры какую-то дополнительную бизнес-логику (валидацию, например — если она не сделана на уровне аннотаций), то теперь пришлось на уровне команды передоговориться. Сказать, что контроллеры для нас являются входной точкой и источником документации. Никакой бизнес-логики прикладной валидации, например, быть не должно там. Иначе они становятся нечитабельными, на каждом методе куча аннотаций. Вместо того, чтобы быть одному методу @RequestMapping, внезапно появляются @ApiOperation, @ApiResponse и так далее — куча всяких разных аннотаций.


— Половина листа кода аннотациями заполнена?


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


— Эту документацию всегда пишут программисты, или у вас есть документаторы?


— Нет, мы пишем сами, только разработчики.


— И это нормально всегда происходит, без шероховатостей?


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


— У вас продукты на какую страну ориентированы?


— На Россию.


— А на каком языке пишется документация?


— На русском. У нас своя команда, нет иностранцев, в том числе в удаленных офисах, поэтому мы всё ведем на русском.


— Эта документация, получается, генерится для работы внутри компании? Или вы внешним подрядчикам тоже это отдаете?


— У нас был такой опыт, но не сейчас, и подрядчики у нас русскоговорящие.


— Круто, очень везёт.


— Я знаю!


— Вы смотрели код этого SpringFox? Если очень захочется, его можно вообще пропатчить, или там адовая жесть?


— Да, можно. Там есть, конечно, нетривиальные места. Но в целом он написан нормально. Не скажу, что отлично, но неплохо. Пара раз уже поднималась рука поправить всякие скользкие места, да времени пока не нашлось. А во-вторых, за ним стоят довольно активные ребята и сами его довольно неплохо пилят. Не так активно, как хотелось бы, но регулярно выкатывают какие-то обновления. Правда, пока что ещё ни одной нашей хотелки не покрыли.


— Насчёт HTTP: вы стараетесь наложить ваши запросы на какой-нибудь определённую методологию, например, на REST?


— Да, стараемся. Одно время, на самом старте движения к микросервисам мы очень сильно на это упирали. Обсуждали, проговаривали, были жаркие споры.


— Но обычно это очень сложно, натянуть сову на глобус. Как у вас с этим?


— У нас с этим как обычно бывает, исторически сложилось. Если ты помнишь, я уже упоминал про вынужденную поддержку обратной совместимости с прежним API, на котором у нас огромный парк клиентов. У сотен тысяч людей на телефонах установлен. И все наши потуги быть restful во всех отношениях сползли с глобуса за счёт того, что мы были вынуждены поддерживать обратную совместимость с тем API. А то API, мягко говоря, не совсем restful. Там используется только POST и GET, вне зависимости, удаляешь ты или редактируешь сущность. Такого понятия как «сущность», вокруг которого строится весь REST — тоже его не особо придерживались. Там такой подход больше, как в самой Java — есть какой-то метод, давай запихнем его имя в сам адрес. Вот оно присутствует в самом этом адресе, getBySomething. Этот подход не ужасный, он рабочий, нормальный. С REST получается, конечно, лаконичней, няшней, но какой-то прикладной огромной ценности я не почувствовал, при том что API достаточно большой, взрослый. Как мне казалось, он рисковал стать болтливым за счёт того, что нет никакой единой парадигмы, но в принципе получилось неужасно. И сейчас, несмотря на то, что мы держим в голове какие-то RESTовые фишки и стараемся их использовать, ту же ориентацию на сущности, пытаемся так проектировать адреса методов, чтобы во главе угла стояла сущность и потом уже она потом подразделялась на какие-то тонкости, следующие по слэшу вглубь запроса, всё равно приходится ограничивать себя этими аспектами обратной совместимости. То есть у нас такой полу-REST.


— Stateless или stateful?


— Микросервисы сейчас все stateless. С одной штукой разве что есть вопросы, потому что следующим этапом в ближайшее время станет развертывание в системе оркестрации. Планируем в Docker-контейнерах всё это выкатывать на Kubernetes. Там одно из главных требований, которое мы согласовали с нашей эксплуатацией, которое, в принципе, весьма естественное — stateless microservices. Причины понятные: чтобы можно было любой из них уронить в любое время и тут же поднять рядом другой, чтобы он мог подхватить запросы. Чтобы они были максимально легкими на подъем и на урон.


— А если всё-таки будут сервисы, которые тяжелые, что с ними делать? Если k8s уронит сервис на 400 гигов в хипе…


— Что делать с этими данными?


— Что делать с данными, как правильно проектировать сервисы, чтобы они переживали такие миграции?


— Подходов есть несколько. Один из тех, который практикуется у нас (хотя не могу сказать, что он хорош в этом кейсе) — использовать распределенные хранилища. Чтобы то место, которое ты назвал хипом, стало не просто хипом, а ещё и где-то между микросервисами хранилось. Классическое решение (не знаю, насколько классическое для всех, но для нас оно таковым стало) — это Hazelcast. Распределенное хранилище на основе Hazelcast. Сейчас так работает монолит. Он кластеризован, у него есть общее распределенное хранилище. Любой кусочек данных хранится на всех нодах. Если одна нода упадет, никто не потеряет эти данные (разумеется, если они успели реплицироваться).


— Какая степень репликации?


— Сейчас я тебе точно не скажу.


— Скажем так, это фуллсинк или как пониже?


— Зависит от данных. В каком-то случае мы используем фулл, а для менее критичных данных, которые легко повторить, там 2/3. То есть данные хранятся на двух из трёх нод (если в кластере три ноды). Но тут я могу в чем-то наврать. Это один вариант.


Второй вариант — если у микросервиса раздулся хип до 400Гб, и всё это ценные данные— всё ли в порядке с микросервисом? Действительно ли он должен себя так вести?


— Он уже не «микро», это «жирносервис».


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


— Что будет, если в середине цепочки микросервисов упадёт полностью или частично что-то, что активно используется соседями? Там будет какой-нибудь graceful degradation или что-то такое?


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


— Просто я беседовал с разными людьми, и две основные стратегии для людей, у которых нет честного GD/DR: если у нас приходит миллиард китайцев и падает кусок графа микросервисов — либо просто лежим и даже не пробуем отработать миллиард китайцев, либо «всё пропало», начинаем в ужасе бегать кругами, кричать и пинать админов. Как у вас с этим? Что это будет у вас?


— Думаю, это будет ближе к первому :-)


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


— Ну, звучит-то да, хорошо. Но по факту, насколько это реализуемо?


— Можно так сделать? Вы так делаете?


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


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


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


— Каким образом эксплуатация поймёт, что у нас что-то плохо? Я намекаю на мониторинг.


— Мониторинги наставлены на самых разных уровнях. Начиная от времени выполнения определенных критичных SQL-запросов и заканчивая активностью воркеров на Apache вовне. На все эти мониторинги выставлены определенные алерты, которые срабатывают по уровням (зеленый, желтый, оранжевый, красный и т.п.) — в зависимости от этого поднимается степень тревоги. Есть какие-то пороговые значения. Имею в виду, пороговые с точки зрения времени срабатывания алерта — в каком сколько мы бываем. И на всё это завязаны отдельные службы эксплуатации и сопровождения, которые не смотрят на них, а имеют каналы, по которым система сама их уведомит в случае проблем. В любой момент они на связи и могут быть привлечены к разбору ситуации.


— Эти мониторинги вы написали сами или используете какие-нибудь Спланки или ещё что-то стандартное?


— Смотря о какой части системы говорить. То, что касается бизнес-логики — это в первую очередь то, что на Java — там мы используем готовые решения. Для монолита используется JAMon, для SpringBoot микросервисов нам пока достаточно Actuator (то, что с самим Бутом поставляется). А всё, что касается инфраструктурной области — это уже мониторинг самих времён выполнения в БД, или дальше, ближе к клиенту — то у сопровождения и эксплуатации свои инструменты используются. Я сейчас затрудняюсь назвать, что они используют — всякие безумные штуковины, в которые я даже и не вникаю, потому что они нас, как разработчиков, и не касаются. Здесь процесс построен таким образом, что эта область целиком и полностью под ними. Только когда идёт что-то не так или требуется консультация, мы вместе разбираемся. Но в целом, нет необходимости нам над этим работать с этими инструментами.


— Если у нас идут какие-то ошибки в бизнес-логике, к чему мы имеем отношение: как выставить уровень угрозы, начиная с которого нужно сигнализировать с желтым и выше приоритетом?


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

© Habrahabr.ru