Привет, Хабр! На связи Олег Оболенский, я руководитель направления проектирования и разработки VK Tech. В компании я отвечаю за разработку корпоративного ПО, а мои команды также оказывают комплекс профессиональных услуг по адаптации наших решений к бизнес-требованиям заказчиков. Мы реализуем облачные и гибридные проекты любой сложности и масштаба, переносим данные, поддерживаем наши сервисы, помогаем оптимизировать затраты на ИТ, управлять виртуальной инфраструктурой. Из каждого сложного внедрения мы стараемся выносить пользу, чтобы обогащать продукты новыми возможностями. Кейс, про который мы сегодня расскажем, будет на стыке работ сразу нескольких подразделений.

Около года назад к нам обратился крупный индустриальный заказчик, который уже использовал Почту VK WorkSpace. Запрос состоял в следующем: нужно было построить для заказчика ресурсно-сервисную модель. Как это должно работать, на начальном этапе не понимал никто. Что ж, тем интереснее было разобраться и построить решение.

Предыстория и постановка задачи

У заказчика была развернута масштабная почтовая инфраструктура On-premise VK WorkSpace, обслуживающая часть компании. ИТ-инфраструктура состояла из 20 серверов и 2000+ работающих docker-контейнеров. На схеме это выглядело как набор кубиков с высокой долей абстракции. Для наглядности приводим фрагмент схемы с бизнес-процессами, которые нам нужно было просчитать.

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

Кроме того, нужно было оценивать, насколько инциденты критичны: нужно ли бежать это чинить прямо сейчас, сломалось ли все или есть еще какой-то ресурс для работы, потому что компоненты системы продублированы? Например, на виртуальной машине наблюдается 100%-я занятость CPU — как это отразится на почтовой системе? Будут ли приходить письма? Будет ли доступ к календарям? А антивирус при этом будет работать? У заказчика были реализованы системы мониторинга на Zabbix, с которыми нужно было сопрячь ресурсно-сервисную модель, чтобы отвечать на все эти вопросы.  

Ключевой вопрос: какая функциональность системы будет пропадать при выходе из строя или недостатке определенных ресурсов. 

Что мы сделали, чтобы стало хорошо

В начале пути в качестве образца со словами «сделайте, пожалуйста, нечто такое же» нам передали диаграмму из пяти квадратов, которые условно изображали пул ресурсов, ВМ и сервисы. Конечно, от такой модели описания системы пришлось отказаться, потому что ничего общего с реальностью она не имела. С самого начала поняли, что построение ресурсно-сервисной модели — это тот самый случай внедрения, который может обогатить продукт, поэтому решили действовать с прицелом на последующую модификацию.

Шаг 0. Сегментация системы

Чтобы упростить себе и администраторам заказчика жизнь, мы разбили систему на более мелкие составляющие. Мы решили воспользоваться идеями, заложенными в С4-нотации, в которой предусматривается четыре уровня описания системы. 

Напомним, что на первом уровне описания в C4 система состоит из подсистем: каких-либо логически связанных блоков, которые решают определенную задачу. На втором уровне подсистемы состоят из контейнеров, под которыми понимается любая выполняемая сущность. На третьем контейнеры состоят из компонентов (пакетов и библиотек), а на четвертом компоненты состоят из кода — структур, классов, методов, функций. Например, есть подсистема авторизации и база данных, которая хранит информацию о пользователях. Кроме этого, есть сервер Keycloak и слой кэширования. Все программы работают вместе и решают одну задачу — это и есть подсистема. 

Всего у нас получилось 16 подсистем. Почему такое количество? Дело в том, что, кроме функций почтовых сообщений, есть менее гранулярные сущности. Для понимания принципа разделения приводим здесь сокращенную версию.

Подсистемы

Функции

Адресная книга

Прием и отправка сообщений

Календарь

Фронтенд приложения

Система уведомлений

Хранилище

Антиспам-фильтр

Пользовательская база

Аутентификация

Чтение событий в календаре

Синхронизация событий в календаре

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

Шаг 1. Контейнеры и поды

Нам пришлось заменить понятие C4-контейнеров на «поды». Дело в том, что в C4 нет подходящего способа описания микросервисных архитектур. Если считать pod Kubernetes подсистемой, число подсистем будет очень велико, что повышает интеллектуальную нагрузку на администратора системы, а если контейнером, то из описания контейнеров придется исключить сайдкары. 

По этой причине мы решили ввести понятие С4-pod, который располагается на уровне контейнеров (втором в С4), но при этом представляет собой несколько взаимосвязанных выполняющихся сущностей, — очень похоже на pod в Kubernetes, но на логическом уровне pod может быть шардирован и реплицирован.

Шаг 2. Распределение зон ответственности

Для простоты описания модели мы решили, что программа или жесткий диск могут находиться только в двух состояниях: «работает» и «не работает». Тут встает логичный вопрос: «А что будет, если программа по внешним признакам работает, но делает это некорректно?». Во-первых, она все еще работает — значит, все еще подчиняется нашей логике. Во-вторых, правильнее будет относить такие ситуации к проблемам тестирования, а не мониторинга.  

Мы также приняли логику, что если не работает одна из подсистем, то вся система также считается нерабочей. Разумеется, кто-то может возразить, что, если перестала работать подсистема, которая принимает почту, кажется, что все ок, ведь еще можно читать, писать, удалять или смотреть старые письма.

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

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

Чтобы не строить костыльную систему, мы выбрали легко формализуемый компромисс. 

Развивая эту идею, считаем подсистему неработоспособной, если один из ее pod’ов неработоспособен (из C4-диаграммы почты прописали вручную соответствие подсистем и подов). 

Решили, что pod неработоспособен, если неработоспособно определенное количество реплик контейнеров этого pod’а или одного из шардов этих контейнеров. Мы ввели правила для определения минимально необходимого количества реплик отдельно для stateful- и stateless-контейнеров. При этом правила для контейнеров с кворумными операциям менее строгие, чем для master-slave.  

Пример

В почте есть подсистема адресной книги, которая хранит состояние в Tarantool (на самом деле Tarantool используется в почте почти повсеместно). Если в нашей инсталляции в адресной книге будет только одна реплика контейнера Tarantool с данными адресной книги и в ней будут лежать все записи, то с падением этой реплики вся адресная книга перестает функционировать (и вся инсталляция, следовательно, тоже будет неработоспособной).

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

  • события, которые приводят к неработоспособности системы, являются critical’ами; 

  • события, которые не приводят (например, потому, что контейнер, на котором возникла ошибка, зарезервирован) — warning’ами.

Шаг 3. Признаки неработоспособности отдельного контейнера

Это самая основная проверка, поскольку из нее выводятся все остальные. Поскольку почта VK WorkSpace на 100% контейнеризирована, понятия c4-контейнеров и выполняемых контейнеров совпадают. 

Договорились считать контейнер работоспособным, если ресурсов для его работы достаточно. 

То есть контейнер функционирует: 

  • в установленных лимитах; 

  • дискового пространства достаточно и сами по себе диски исправны; 

  • сеть для взаимодействия с другими контейнерами работоспособна; 

  • статус контейнера — healthy; 

  • история перезапусков не растет, и счетчик его ошибок тоже не растет или оба растут, но не быстрее какой-то линейной функции. 

Контейнер неработоспособен, если счетчик перезапусков или ошибок растет и все подсистемы, к которым обращается контейнер, «здоровы». 

Последнее требование помогает найти первопричину аварии. Например, если принимающий mx-сервер обращается к Storage, а эта операция заканчивается ошибкой. При этом мы знаем, что подсистема стораджа сейчас неработоспособна, проверка работоспособности mx-сервера должна сообщить, что mx-сервер работоспособен и корневая причина будет локализовываться в сторадже. Возможно, что mx-сервер в этот момент будет неработоспособен сам по себе, но мы об этом не узнаем. Эту проблему решили ранжированием: проблемы более низкого уровня должны ранжироваться более высоко по сравнению с проблемами высокого уровня. Починив низкий уровень, вы, возможно, одновременно почините и более высокий. Следующий цикл опроса, в котором сторадж уже будет работоспособен, покажет неработоспособность mx-сервера. 

Проблемы низкого уровня всегда «засвечивают» проблемы более высокого уровня. 

Для реализации пришлось определить и установить лимиты контейнеров, проверить и настроить мониторинг статуса там, где он не был настроен. К счастью, счетчик ошибок был доступен «из коробки». Граф зависимостей между контейнерами мы снимаем инструментально, в том числе и для построения C4-диаграммы.

Шаг 4. Инциденты

В рамках предложенной заказчику модели алерты проранжированы в порядке критичности и уровня, сыпятся на сотрудника, который идет и смотрит, что произошло, и устраняет причину. Проблемы диагностируются довольно поверхностно и разрешаются также без глубокого погружения: «перезапусти», «почисти место», «эскалируй», — что соответствует специфике работы первых линий поддержки, а кроме того, разрешение инцидента может быть автоматизировано.

Hot take: если какая-то функциональность в сервисе есть, но она отвалилась и оказалась никому не нужна, возможно, ее не следует чинить, а нужно просто выключить. 

Шаг 5. Систематизация

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

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

К чему пришли

Заказчик получил описание настроек мониторинга зависимости контейнеров от конкретных аппаратных ресурсов. Мы обогатили набор ресурсов полученными ошибками, чтобы исследовать доступность вычислительных ресурсов: дисков, памяти и процессоров. Плюс лучше стали понимать, когда контейнеры начинают отдавать 500-е и следить за таймаутами. 

Во время сотрудничества в ИТ-инфраструктуре всегда было 20 серверов, но мы ориентировались на то, чтобы инсталляция проектировалась как масштабируемая. Чтобы, когда появлялись новые ресурсные блоки, у команды заказчика не было проблемы обновления ресурсно-сервисной модели. Для этого мы, в частности, использовали функциональность VK WorkSpace — Deployer. Это средство установки, которое может переконфигурировать инсталляцию, в том числе в случае добавления нового железа. Таким образом, процедура имплементации СРМ может быть упрощена с помощью Deployer. 

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


  1. Ranger21
    11.07.2025 13:41

    Поздравляю, вы сделали инфраструктурный мониторинг, а не мониторинг специфики приложений