При реализации микросервисов организациям приходится перестраивать архитектуру традиционных монолитных приложений. Это помогает повысить гибкость и масштабируемость сервисов и быстрее выводить на рынок новые возможности.
Каждый микросервис выполняет конкретную функцию. При этом микросервис может извлекать и обрабатывать данные сразу из нескольких разнородных источников. Среди этих источников — хранилища данных, унаследованные системы и другие совместно используемые сервисы, развёрнутые локально в дата-центрах или в облаке. Подобные сценарии добавляют свою задержку к времени отклика микросервиса, поскольку для работы внутренних систем требуется сразу несколько вызовов в режиме реального времени. Задержка часто колеблется в диапазоне от нескольких миллисекунд до нескольких секунд в зависимости от объёма данных, пропускной способности сети и логики обработки данных. В некоторых сценариях целесообразно размещать кеш близко к уровню микросервисов. Это позволяет повысить производительность: обращаться к серверной части в режиме реального времени становится не нужно или требуется намного реже.
Кеш снижает задержку и ускоряет взаимодействие между сервисами в микросервисных архитектурах. Кеш — это уровень хранения данных с высокой скоростью доступа, на котором находится подмножество всех ваших данных. Из кеша они будут доставлены быстрее, чем при обращении к основному хранилищу данных.
При работе с клиентами мы встречали сценарии, в которых кеширование данных позволило снизить задержку на уровне микросервисов. Кеширование может быть реализовано несколькими способами. Мы рассмотрим два таких сценария. В обоих случаях слой микросервисов создаётся с использованием бессерверных вычислений на платформе AWS. При этом требуются данные из нескольких источников, развёрнутых локально в облаке или на клиентском оборудовании. Вычислительный уровень построен с использованием функций AWS Lambda. Хотя сами Lambda-функции живут недолго, кешированные данные могут использоваться последующими экземплярами того же микросервиса без обращения к бэкенду.
Сценарий 1: кеш по требованию, чтобы сократить объём вызовов в реальном времени
Шаблон Cache-Aside применяется для ленивой загрузки часто используемых данных. Это означает, что объект кешируется, только когда потребитель его запрашивает, а соответствующий микросервис решает, стоит ли сохранять объект.
Такой способ полезен, когда уровень микросервисов выполняет несколько вызовов для извлечения и обработки данных в режиме реального времени. Объём этих вызовов можно существенно сократить, если кешировать на короткое время часто используемые данные.
Давайте обсудим сценарий из жизни. На рис. 1 показан клиентский портал, который выдаёт список автокредитов, их статус и чистую непогашенную сумму кредита для клиента:
Микросервис Billing получает запрос. Затем он пытается извлечь необходимые объекты (например, список автокредитов, их статус, чистый непогашенный остаток по кредиту) из кеша, используя ключ object_key. Если информация есть в кеше, отправителю запроса посылается ответ с использованием кешированных данных.
Если запрошенные объекты недоступны в кеше («непопадание» в кеш), микросервис Billing выполнит несколько вызовов локальных сервисов, приложений и источников данных и извлечёт нужные данные. Результат будет скомпонован и отправлен обратно пользователю. Этот результат тоже ненадолго останется в кеше.
Если клиент выполнит платёж с помощью микросервиса Payment, то хранимую в кеше величину баланса нужно будет инвалидировать или удалить. Микросервис Payment обработает платёж и вызовет асинхронное событие (payment_processed). При этом сформируются ключи объектов для последующих процессов, которые удалят неактуальные объекты из кеша.
События (events) хранятся в хранилище событий (event store).
Микросервис CacheManager получит событие (payment_processed) и отправит в кеш запрос на удаление данных по соответствующему ключу object_key. При необходимости CacheManager также может обновить кешированные данные: вызвать ресурс сервиса Billing или подгрузить данные непосредственно из системы-источника в зависимости от логики обращения к данным.
На рис. 2 показаны сервисы AWS для сценария 1. Уровень микросервисов (Billing, Payments и Profile) создаётся с помощью функции AWS Lambda. Шлюз Amazon API Gateway представляет Lambda-функции в виде API-операций и позволяет внутренним или внешним потребителям обращаться к ним.
Все три микросервиса подключены к кешу данных и могут сохранять в него и извлекать оттуда объекты. Кеш организован в оперативной памяти с помощью технологии Amazon ElastiCache. Объекты данных хранятся в кеше недолго. Каждому объекту присваивается соответствующее значение времени жизни (TTL). Когда оно истекает, объект удаляют. Пользовательские события (например, payment_processed) публикуются в Amazon EventBridge, а затем обрабатываются.
Сценарий 2: упреждающее кеширование больших объёмов данных
В крупных проектах модернизации и миграции не все источники данных развёртываются на сравнительно небольшое время. Некоторые унаследованные системы, например работающие на мейнфреймах, требуют более длительного периода вывода из эксплуатации. Многие устаревшие бэкенд-системы обрабатывают данные с помощью периодических пакетных заданий. В таких сценариях фронтендные приложения могут использовать кешированные данные от нескольких минут до нескольких часов, в зависимости от характера данных и способа их использования. При этом серверные системы не справляются с большим объёмом вызовов на уровне интерфейсного приложения.
В таких сценариях необходимые данные/объекты можно идентифицировать заранее и загрузить непосредственно в кеш (рис. 3):
Автоматизированный процесс загружает данные/объекты в кеш во время начальной загрузки. Изменения на уровне источников данных (в БД на мейнфрейме или другой системе хранения данных) фиксируются и применяются на уровне кеша с помощью автоматизированного конвейера CDC (Change Data Capture).
В отличие от первого сценария, микросервисы не выполняют вызовы в реальном времени для подгрузки данных в кеш, а используют те данные, которые уже были для них закешированы.
Тем не менее на уровне микросервисов могут сформироваться события, если данные в кеше устарели или определённые объекты были изменены другим сервисом (например, сервисом Payment при совершении платежа).
События хранятся в менеджере событий Event Manager. При получении события CacheManager инициирует бэкенд-процесс для обновления устаревших данных по требованию.
Все изменения данных поступают непосредственно в систему записи.
Как показано на рис. 4, объекты данных хранятся в базе данных Amazon DynamoDB, которая обеспечивает низкую задержку при доступе к данным в любых масштабах. Извлекает данные акселератор DynamoDB Accelerator (DAX) — полностью управляемый, высокодоступный кеш, который работает в оперативной памяти. Он десятикратно повышает скорость извлечения данных — даже при миллионах запросов в секунду.
Данные в DynamoDB могут быть загружены различными способами в зависимости от варианта использования клиента и технологического ландшафта. API Gateway, Lambda и EventBridge предоставляют те же функции, что и в первом сценарии.
Сценарий 2 также полезен, когда фронтенд-приложения должны кешировать данные на длительное время, например в корзине покупок.
Чтобы уменьшить задержку и повысить производительность на уровне вычислений AWS Lambda, кроме кеширования, можно воспользоваться другими способами:
Рекомендации по использованию функций AWS Lambda показывают, как повторно использовать среду выполнения для повышения производительности Lambda-функций.
В статье Знакомство с расширениями AWS Lambda показано, как реализовать конфигурацию и кеш данных с помощью расширений AWS Lambda Extensions.
Выводы
Архитектура микросервисов позволяет построить несколько уровней кеширования в зависимости от сценария. В этой статье мы обсудили, каким образом кеширование данных на вычислительном уровне способно уменьшить задержку при получении данных из разных источников. В сценарии 1 количество обращений к серверной системе в режиме реального времени сокращается благодаря тому, что наиболее часто используемые данные сохраняются в кеше. Сценарий 2 поможет хранить большие объёмы данных в кеше продолжительное время, когда вызовы внутренней системы в реальном времени невозможны.
Если вам интересна экосистема Serverless-сервисов и все, что с этим связано, заходите в сообщество в Telegram, где можно обсудить serverless в целом.
tzlom
Не понятно зачем нужен CacheManager, Payment по сути все равно о кеше в курсе т.к. генерит список id на удаление, что мешает ему посылать их сразу в систему кеширования?
ggo
ничего не мешает. можно и напрямую слать из payment.
но можно и абстрагировать. payment шлет изменения и дальше его ничего не волнует (fire-and-forget). а отдельный ответственный кладет изменения в кеш.
tzlom
В смысле кладет? Он же только чистит, и это тоже может быть запрос без ожидания ответа.