Распределенные системы. Паттерны проектирования - [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 . Разные контейнеры приложения