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

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

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

При работе с клиентами мы встречали сценарии, в которых кеширование данных позволило снизить задержку на уровне микросервисов. Кеширование может быть реализовано несколькими способами. Мы рассмотрим два таких сценария. В обоих случаях слой микросервисов создаётся с использованием бессерверных вычислений на платформе 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 или подгрузить данные непосредственно из системы-источника в зависимости от логики обращения к данным.

Рис. 1. Кеширование часто используемых данных сокращает задержку
Рис. 1. Кеширование часто используемых данных сокращает задержку

На рис. 2 показаны сервисы AWS для сценария 1. Уровень микросервисов (Billing, Payments и Profile) создаётся с помощью функции AWS Lambda. Шлюз Amazon API Gateway представляет Lambda-функции в виде API-операций и позволяет внутренним или внешним потребителям обращаться к ним.

Рис. 2. Сервисы AWS для реализации сценария 1
Рис. 2. Сервисы AWS для реализации сценария 1

Все три микросервиса подключены к кешу данных и могут сохранять в него и извлекать оттуда объекты. Кеш организован в оперативной памяти с помощью технологии Amazon ElastiCache. Объекты данных хранятся в кеше недолго. Каждому объекту присваивается соответствующее значение времени жизни (TTL). Когда оно истекает, объект удаляют. Пользовательские события (например, payment_processed) публикуются в Amazon EventBridge, а затем обрабатываются.

Сценарий 2: упреждающее кеширование больших объёмов данных

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

В таких сценариях необходимые данные/объекты можно идентифицировать заранее и загрузить непосредственно в кеш (рис. 3):

  • Автоматизированный процесс загружает данные/объекты в кеш во время начальной загрузки. Изменения на уровне источников данных (в БД на мейнфрейме или другой системе хранения данных) фиксируются и применяются на уровне кеша с помощью автоматизированного конвейера CDC (Change Data Capture).

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

  • Тем не менее на уровне микросервисов могут сформироваться события, если данные в кеше устарели или определённые объекты были изменены другим сервисом (например, сервисом Payment при совершении платежа).

  • События хранятся в менеджере событий Event Manager. При получении события CacheManager инициирует бэкенд-процесс для обновления устаревших данных по требованию.

  • Все изменения данных поступают непосредственно в систему записи.

Рис. 3. Упреждающее кеширование массивных объёмов данных избавляет от необходимости совершать вызовы в реальном времени.
Рис. 3. Упреждающее кеширование массивных объёмов данных избавляет от необходимости совершать вызовы в реальном времени.

Как показано на рис. 4, объекты данных хранятся в базе данных Amazon DynamoDB, которая обеспечивает низкую задержку при доступе к данным в любых масштабах. Извлекает данные акселератор DynamoDB Accelerator (DAX) — полностью управляемый, высокодоступный кеш, который работает в оперативной памяти. Он десятикратно повышает скорость извлечения данных — даже при миллионах запросов в секунду.

Рис. 4. Сервисы AWS для реализации сценария 2
Рис. 4. Сервисы AWS для реализации сценария 2

Данные в DynamoDB могут быть загружены различными способами в зависимости от варианта использования клиента и технологического ландшафта. API Gateway, Lambda и EventBridge предоставляют те же функции, что и в первом сценарии.

Сценарий 2 также полезен, когда фронтенд-приложения должны кешировать данные на длительное время, например в корзине покупок.

Чтобы уменьшить задержку и повысить производительность на уровне вычислений AWS Lambda, кроме кеширования, можно воспользоваться другими способами:

Выводы

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

Если вам интересна экосистема Serverless-сервисов и все, что с этим связано, заходите в сообщество в Telegram, где можно обсудить serverless в целом. 

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


  1. tzlom
    16.02.2022 10:31

    Не понятно зачем нужен CacheManager, Payment по сути все равно о кеше в курсе т.к. генерит список id на удаление, что мешает ему посылать их сразу в систему кеширования?


    1. ggo
      16.02.2022 10:56
      +1

      ничего не мешает. можно и напрямую слать из payment.

      но можно и абстрагировать. payment шлет изменения и дальше его ничего не волнует (fire-and-forget). а отдельный ответственный кладет изменения в кеш.


      1. tzlom
        16.02.2022 13:29

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


  1. darkbenladan
    16.02.2022 12:54
    -1

    Коротко и ясно, спасибо автору.