Ваша микросервисная архитектура больше похожа на пинбол или на фастфуд?
Микросервисы - это здорово. Они позволили нам разбить устаревшие монолитные промышленные приложения и заменить их набором быстрых сервисов. Мне не нужно объяснять вам, почему это хорошо для современной организации - существует множество материалов, которые расскажут вам о преимуществах микросервисов и, что не менее важно, о недостатках. Я предполагаю, что вы сделали «домашнюю работу» и с радостью переходите на микросервисы (или планируете это сделать) или сделали это и живете с этим результатом. Мой опыт работы с микросервисами основан на работе с веб-приложениями. Я видел два разных шаблона, когда компании переносят веб-/онлайн-приложения на микросервисы - один я называю архитектурой пинбола, а другой - архитектурой фаст-фуда.
Архитектура пинбола? Будучи ребенком в70-х и 80-х годах 20 века, я с любовью вспоминаю автоматы для игры в пинбол. Вы вложили деньги в слот, и он открыл металлический шарик в желобе, который вы запустили в игровой стол с помощью поршня. Вы набирали очки, выполняя задания и наборы или просто повторяя схемы. Наклон стола и различные кикеры сговорились отправить ваш мяч в желоб в нижней части стола, и вашей единственной защитой было ударить по мячу плавниками, управляемыми кнопками сбоку стола.
Это хорошее путешествие по памяти, но какое отношение это имеет к микросервисам? Представьте, что запущенный шар - это HTTP-запрос в систему. Он приходит сверху, где попадает в функцию (услугу), а затем отскакивает в другом направлении, чтобы попасть в другую функцию (услугу) и так далее. Это не редкая архитектура микросервисов. Это то, что вы часто видите в результате разбиения существующих монолитов на микросервисы, часто в сочетании с миграцией в облако. Нет ничего противоестественного в том, чтобы поддерживать такой образ мышления, ориентированный на обслуживание запросов, при разработке и создании вашего решения. Но в итоге вы получаете сервис/обработчик, который выполняет всю работу по беготне по сбору всех данных, необходимых для выполнения требуемого действия и возврата требуемого ответа.
Проблема становится более острой, если вы выбрали "без серверную» или событийно-ориентированную архитектуру с большим количеством меньших, «хорошо выполняющих одну задачу» сервисов, которые вносят свой вклад в более крупную систему. Увеличение количества сообщений / запросов / событий, пересылаемых между различными компонентами системы, может привести к проблемам с эксплуатацией, требуя серьезной детективной работы для выявления основной причины, когда что-то пойдет не так. Компания ThoughtWorks назвала это вспышкой на своем технологическом радаре в ноябре 2019 года («лямбда-пинбол»), хотя с тех пор она исчезла. Такая архитектура вполне разумна, но дополнительные функции могут непропорционально увеличить сложность системы. Со временем, при постоянном развитии системы, такой подход может стать обузой. Возможные подводные камни:
Непреднамеренные побочные эффекты. Если сервис был создан с расчетом на использование определенными клиентами (не редкость для монолитной миграции), но теперь получает вызовы от нового клиента, может выполняться нежелательная логика, что приводит, например, к созданию неточных данных.
Условия гонки. Если служба A вызывает службу B, затем служба C, а затем и B, и C обращаются к службе D, что, если у службы B плохой день и вызов службы C получен первым? Проблемы с производительностью. С увеличением внутренней нагрузки из-за запросов, пингующих систему, вы довольно быстро обнаружите узкие места.
Неоптимальные затраты. Вы можете решить некоторые проблемы с производительностью в облаке, потратив средства (например, увеличив число операций ввода-вывода в секунду при чтении в DynamoDB).
Так что рано или поздно вы почувствуете некоторую боль и решите снизить внутреннюю нагрузку на систему. Какая же альтернатива? - Архитектура фаст-фуда.
Что-то общее в ресторанах быстрого питания заключается в том, что для достижения быстрого времени подачи заказа (запрос / ответ) они используют ряд процессов для подготовки и подачи частей еды заранее, готовых к выдаче.
Рестораны быстрого питания не ждут вашего заказа, чтобы начать готовить еду. То, что можно сделать заранее, обычно делается заранее. Доступны комплектующие, готовые к сборке по вашему заказу.
Примеры:
Закусочная будет готовить гамбургеры в расчете на то, что кто-то скоро их закажет. Они собирают бургер с салатом и булочкой, упаковывают его и опускают по желобу, чтобы сделать его доступным для персонала, принимающего заказы.
Фургон для уличной еды с картофелем фри приготовит картофель на 2/3, и для окончательной обжарки потребуется всего несколько минут, чтобы доставить вкусный, горячий картофель фри. Горячие начинки будут изготавливаться партиями и храниться в горячем состоянии для сборки. Охлаждённые / холодные начинки будут приготовлены и находиться в пределах легкой досягаемости.
На прилавке, где подают паэлью, стоят две сковороды: одна приготовлена и готова к подаче, а другая готова для приготовления следующей партии, когда первая сковорода частично продана.
То, что достигается процессами «подготовить и представить», - это старт для выполнения вашего заказа. Вам не нужно ждать 20 минут, пока кто-нибудь почистит картошку, нарежет её и приготовит - это уже было сделано до того, как вы решили, что пора съесть картошку фри!
Но какое это имеет отношение к архитектуре микросервисов? Хорошая новость заключается в том, что вы можете использовать аналогичные принципы для достижения аналогичных результатов.
Микросервисы как приготовление пищи
Взаимодействие клиентов с вашими системами можно условно разделить на два типа:
Запросы данных — например, продукты по категориям, подробная информация о продукте, история моих заказов.
Запросы на действие — например, обновить мой профиль, добавить товар в корзину, оформить заказ.
Запросы на действие имеют два профиля производительности. Клиент либо ждет подтверждения запрошенного действия (синхронный), либо не ждет (асинхронный). Последний очень быстрый; первый ограничен системными компонентами, ответственными за действие, так что вы не так уж много можете сделать для повышения производительности.
Запросы данных также имеют аналогичные профили производительности. Клиент должен дождаться получения и возврата запрошенных данных. Производительность этого действия будет ниже, если системе необходимо получить данные из системы записи, или быстрее, если в системе уже есть доступные данные.
Подготовить и представить (системная версия)
Как и в случае с фаст-фудом, системы могут подготавливать и представлять данные. В данном случае речь идет о получении данных из бэкэнд-систем (возможно, нескольких бэкэндов) и приближении их к сервису, обрабатывающему запрос клиента. Это вовсе не новая идея. Исторически сложилось так, что многие серверные части не подходят для обработки объемов запросов веб-масштаба, поэтому уровень кэширования помещается перед серверной частью. Это немного приближает данные к клиенту, но чтобы действительно воспользоваться преимуществами архитектуры быстрого питания, вам необходимо преобразовать их в формат, близкий к потребностям клиента, и сделать их локально доступными для службы, обрабатывающей запрос клиента.
Золотые правила архитектуры быстрого питания
Минимизируйте выборку данных, пока клиент ожидает. Очевидно, что мы стремимся свести к минимуму время отклика, поэтому ключевой целью должно стать устранение операций ввода-вывода. Мышление по умолчанию должно заключаться в том, чтобы иметь готовые данные, если нет веской причины не делать этого.
Вот несколько вопросов, которые следует задать себе:
Мог ли я получить эти данные раньше?
Вам действительно нужно ждать, чтобы добраться до серверной части в тот момент, когда клиент что-то запросил?
Насколько изменчивы данные?
Часто ли данные меняются, и важно ли, чтобы данные были точными?
Имейте в виду, что данные, которые видит клиент, всегда будут на X миллисекунд устаревшими к тому времени, когда он их увидит, поэтому вопрос на самом деле заключается в том, «насколько устаревшие данные могут считаться достаточно точными».
Для таких вещей, как квоты на передачу данных мобильного (сотового) телефона или цены на криптовалюту, ранняя предварительная выборка явно не подходит, и данные должны извлекаться по запросу (возможно, с коротким временем жизни кеша, чтобы снизить нагрузку на серверную часть).
Есть ли способ, которым я могу быть уведомлен, что данные изменились?
Для данных, которые изменяются, мне нужно ждать следующего ежедневного потока или я могу получить событие, которое говорит мне, что я должен обновить свое представление?
Минимизируйте преобразование данных для ответа на запрос.
Опять же, мы стремимся свести к минимуму время отклика, поэтому устранение повторяющихся преобразований - еще одна ключевая цель. Мы стремимся максимизировать работу, не проделанную для обслуживания запроса клиента.
Дополнительные вопросы, которые следует задать себе:
Повторяю ли я преобразование для последовательных запросов? Если да, то это хороший признак того, что вам следует сохранять данные после преобразования, чтобы избежать ненужной работы.
Можно ли разбить запрошенные данные? Возможно, преобразование необходимо, потому что вы смешиваете два или более источников данных вместе для создания составного представления. Если это так, рассмотрите изменчивость составных частей данных. Старайтесь предварительно преобразовывать данные с низким уровнем изменений вместе и смешивать данные с более высокой волатильностью по запросу, тем самым сводя к минимуму преобразование по запросу.
Максимизируйте невыполненную работу - это все очень просто в теории, но есть и другие практические аспекты, о которых следует помнить.
Другие вещи, которые следует учитывать:
Экономически эффективно ли подготовить все данные? Если вы используете свои системы локально, вам нужно будет выделить целую нагрузку на хранилище. В облаке это менее проблематично, но все равно дорого обходится как с точки зрения хранения, так и операций ввода-вывода. Посчитайте: любую систему можно сделать быстрее, но это не всегда рентабельно.
Возможным компромиссом здесь является ограничение объема подготовленных данных с помощью подхода «точно в срок». Это хорошо работает, когда у вас есть предсказуемый шаблон спроса, например, использование событий входа клиента для запуска предварительной выборки данных для наиболее вероятного следующего действия клиента.
Каковы требования безопасности к данным? Если вы переносите все эти бизнес-данные из серверной части и храните их рядом с клиентом, вы берете на себя ответственность за безопасность этих данных.
Существуют ли какие-либо требования к суверенитету данных, например, должно ли это оставаться в центре обработки данных Российской Федерации?
Нужно ли мне предоставлять контрольный журнал о том, кто получает доступ к этим данным?
Каковы мои обязательства по хранению данных и праву на забвение?
Как я контролирую доступ к этим данным?
Раньше серверная часть могла выполнять проверку авторизации, но если теперь она добровольно передает данные в вашу систему, вы несете ответственность за повторение проверки авторизации. Так что продолжайте, относитесь к своим бизнес-данным как к ингредиентам.
Пинбол или фаст-фуд? Так какой же лучший вариант?
Архитектуру пинбола проще понять, создать и использовать, но сложнее и дороже масштабировать.
Архитектура быстрого питания масштабируется и работает лучше, но требует более продвинутого уровня инженерной зрелости.