Распределенные системы. Паттерны проектирования - [18]

Шрифт
Интервал

Существует  множество  стандартизированных  интерфейсов  мониторинга —  syslog , мониторинг событий Windows (ETW),  JMX  для  Java-приложений  и  многие  другие  протоколы  и  ин-терфейсы.  Однако  все  они  различаются  как  протоколами,  так  и способами коммуникации (push или pull). К сожалению, приложения, входящие в вашу распределенную  систему,  могут  включать  в  себя  как  части  из  самописного  кода,  так  и  готовые  open-source-компоненты.  В  результате  вы  сталкиваетесь  с  широким  разнообразием  интерфейсов  мониторинга, которые необходимо интегрировать в одну по-нятную систему.

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

Глава 4. Адаптеры 67

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

В качестве примера рассмотрим мониторинг состояния контей-неров с помощью Prometheus ( https://prometheus.io/ ). Prometheus —  это агрегатор данных мониторинга, который собирает показатели  организует  в  упорядоченную  по  времени  базу  данных.  Кроме  базы данных, Prometheus предоставляет средства визуализации  и язык запросов для анализа собранных показателей. Чтобы обе-

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

Однако многие приложения, такие как хранилище «ключ — зна-чение»  Redis,  предоставляют  показатели  в  формате,  не  совме-стимом  с  Prometheus.  Следовательно,  паттерн  Adapter  весьма  полезен для адаптирования существующих сервисов вроде Redis  к интерфейсу сбора показателей Prometheus. 68 Часть I. Одноузловые паттерны проектирования

Рассмотрим  спецификацию  простой  группы  контейнеров  для  сервиса Redis:

apiVersion: v1

kind: Pod

metadata:

name: adapter-example

namespace: default

spec:

containers:

- image: redis

name: redis

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

apiVersion: v1

kind: Pod

metadata:

name: adapter-example

namespace: default

spec:

containers:

- image: redis

name: redis

# Предоставляем адаптер, реализующий интерфейс Prometheus - image: oliver006/redis_exporter

name: adapter

Этот пример иллюстрирует не только ценность паттерна Adapter  в плане обеспечения унифицированного интерфейса, но и полез-ность контейнерных паттернов в целом как средства обеспечения  модульности  и  повторного  использования  контейнеров.  При-мер  демонстрирует,  как  совместить  существующий  контейнер  с  Redis  и  адаптер  в  формат  Prometheus.  Совокупным  эффектом  Глава 4. Адаптеры 69

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

Как  и  в  случае  с  мониторингом,  системы  очень  неоднородно  журналируют  данные.  Системы  могут  разделять  журналы  на  различные  уровни,  например  debug,  info,  warning  и  error,  каж-дый  из  которых  записывается  в  отдельный  файл.  Некоторые  просто выводят информацию в потоки  stdout  или  stderr . Это  особенно критично в случае контейнеризованных приложений,  когда обычно ожидается, что контейнеры выводят информацию  в  поток  stdout ,  так  как  именно  его  содержимое  доступно  при  выполнении команд  docker  logs  или  kubectl  logs . Усложняет ситуацию и то, что журналируемая информация в об-щем случае имеет структурированные элементы, например дату  и время записи, но эти сведения сильно различаются для разных  реализаций библиотек журналирования (например, для встроен-ного в Java средства журналирования и пакета  glog  в Go). Записывая и читая журналы своей распределенной системы, вы,  конечно же, не особо заботитесь о различиях между форматами.  Вы  хотите  убедиться,  что,  несмотря  на  различную  структуру  данных, каждая запись имеет соответствующую метку времени. К счастью, как и в случае мониторинга, паттерн Adapter помогает  предоставить  модульную,  повторно  используемую  архитекту-ру  для  ведения  журналов.  Контейнер  приложения  может  вести  журнал  в  файле,  а  контейнер-адаптер будет  перенаправлять  его  содержимое  в  поток  stdout .  Разные  контейнеры  приложения