Мониторинг Подключения В Сервисной Сети



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

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

Естественно, существует задача мониторинга коммуникаций между серверами и сервисами.

О виде этой задачи, о том, какие решения подходят, а какие нет, мы поговорим далее.



Структура сети: интерфейсы, серверы, сервисы.

Как и многие другие веб-приложения, наше состоит из внешнего интерфейса (FE), внутреннего интерфейса (BE) и сервисов.

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

В нашем случае FE почти всегда nginx, BE — tomcat. Эта архитектура вполне стандартна; нестандартности начинаются тогда, когда нужно принять решение о том, как маршрутизировать запросы между фронтендами, бэкендами и сервисами.

В нашем случае маршрутизация контролируется базой данных конфигурации CMDB. Эта база данных отражает как физическую структуру сети (центры обработки данных, физические серверы,.

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

Первый условно «оффлайн», и заключается в том, что раз в несколько минут скрипт выбирает необходимую информацию из CMDB и строит текущие конфиги, например, для nginx, включая необходимые апстримы.

Как работает второй метод доступа к CMDB, описано в следующем разделе.



CMDB, короткие имена, поиск сервисов по названию

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

Этот метод используется в основном бэкэндами для обнаружения необходимых им сервисов, для связи сервисов между собой и основан на использовании DNS. Понять, как это делается, проще всего по картинке с пояснениями:

Мониторинг подключения в сервисной сети

  1. Серверная часть be5, расположенная на хосте host58, должна подключиться к базе данных, имя службы базы данных db1 (короткое DNS-имя).

  2. Из имени db1, из данных в resolv.conf, строится имя db1.be5.host58.example.com. Резолвер отправляет запрос в PowerDNS.
  3. Плагин pDNS от имени db1.be5.host58 делает вывод, что контейнер be5, расположенный на хосте хост58, ищет сервис db1
  4. Данные CMDB используются для предоставления списка запущенных IP-контейнеров, предоставляющих службу db1, которые находятся ближе всего к хосту58.
  5. Сервис на be5 выбирает произвольный адрес из полученного списка и обращается к сервису db1
Подведем итог: фронтенды, бэкенды, сервисы находят друг друга, используя единый источник информации CMDB. Есть два метода получения адресов: через построение конфигов и через DNS-запросы.



Физическая структура сети, проблемы связи



Мониторинг подключения в сервисной сети

Мы арендуем сервера у хостинг-провайдеров.

Структура в разных дата-центрах одинаковая — набор физических хостов, на которых работают контейнеры с фронтендами, бэкендами или сервисами.

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

Всего мы находимся в шести дата-центрах, в каждом дата-центре около ста-двух серверов, а на каждом сервере — до четырех-пяти контейнеров.

Итого получаем около тысячи хостов и около пяти тысяч контейнеров.

Поскольку вся структура сети не в наших руках, мы не можем следить за ссылками, коммутаторами, загрузкой каналов и т. д. По этой же причине (сеть не в наших руках) мы используем ipsec для связи между серверами.

Ipsec иногда преподносит сюрпризы в виде потери связи между двумя хостами (или просто между контейнерами).

Инфраструктура провайдера преподносит аналогичные сюрпризы.

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

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

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

Когда количество хостов приближается к тысяче, этот простой метод перестает работать:

  1. время пинга становится слишком длинным, или:
  2. потребление сети для мониторинга становится заметным (стандартный пинг, отправленный с одного сервера на тысячу серверов в течение секунды, будет занимать около мегабита полосы пропускания, если так делают все тысячи серверов, то это уже слишком много)
  3. Загрузка ЦП на хосте для обработки и анализа «кто кого видит или не видит» становится большой
  4. соединение между контейнерами не отслеживается - мы не видим проблем с ipsec или корневой конфигурацией, приводящих к проблемам на уровне контейнера
Чтобы решить все эти проблемы одним махом, нам необходимо отслеживать не «все», а только связь между компонентами, которые обращаются друг к другу.

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

А для сервисов, которые используют CMDB через разрешение, мы разберем логи PowerDNS и выясним, что PowerDNS ответил на запрос.

Таким образом мы можем собрать полный список того, какие IP-адреса могут быть доступны каким компонентам.



Мониторинг, тесты

Собираем полный список текущих связей между контейнерами в одном месте; для задачи мониторинга соединений это одно место играет роль «сервера».

Вся информация представлена на сервере в виде словаря:

контейнер список соединений
be5.host58 192.168.5.1 192.168.5.2 10.1.2.3 10.2.3.4
be8.host1000 10.0.0.1 10.0.100.5
Сервер делает эту информацию доступной через интерфейс REST. Вторая половина мониторинга находится в каждом контейнере — назовем эту часть «агентом».

Агент ничего не знает о контейнере, в котором он находится, ничего, кроме его имени, и не сохраняет никакого текущего состояния.

Раз в две минуты агент обращается к серверу за списком своих подключений, и сервер отвечает строкой из таблицы выше.

Обычно длина списка IP-адресов не превышает десяти.

Агент отправляет пинги на эти адреса.

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

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

Мы много чего мониторим через munin, но munin дает достаточно большую задержку в представлении данных, а здесь мы можем получить что-то напрямую в режиме «реального времени».

Поэтому агент также собирает такие показатели, как LA в компоненте, скорость запросов к nginx, если они есть, и количество ошибок nginx с разбивкой по коду.



Мониторинг подключения в сервисной сети



Мониторинг, представление и анализ результатов

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

Примерно такая информация у нас есть:

имя отключает ОКРУГ КОЛУМБИЯ роль нагрузка nginxErrRate возможность подключения nginxAccessRate
be1.host123 0 Техас быть 0.21 15.55 31.38
be1.host122 0 Техас быть 0.11| 18.28 34.61
fo1.host161 2 В.

А.

фо 0.02 0.11 10.1.1.4,10.1.2.4 14.1
fo1.host160 0 В.

А.

фо 0.0 0.00 0.0
fo1.host162 2 В.

А.

фо 0.01 0.18 10.2.1.4,10.2.4.3 17.56
Часть информации в этой таблице отправляется агентами (disconnects, load, nginx.), часть (DC, роль) заполняется из CMDB. Поскольку данные в этой таблице очень недолговечны, а количество строк в ней порядка тысячи, имеет смысл спроектировать ее как часть sqlite-базы данных типа «:memory:».

Основной причиной всего этого сада были проблемы с мониторингом связи.

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

«SELECT name FROM data ORDER by Disconnects DESC» — дает нам список серверов с проблемами связи, которые нам следует решить в первую очередь.

Результаты этого запроса, если они не пустые, отправляются в Nagios в виде оповещения с прикрепленным списком проблемных серверов.

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

Это может произойти по разным причинам, связанным как с нашими эксплуатационными проблемами, так и с внешними для нас причинами.

Абстрактный пример — изменилась маршрутизация между дата-центрами, в результате кросс-дат-центры запросы больше не укладываются во временные рамки, что приводит к увеличению ошибок 504 в nginx. Запрос «SELECT SUM(nginxAccessRate),SUM(nginxErrorRate),dataCenter FROM data GROUP by dataCenter ORDER BY SUM(nginxAccessRate)» дает нам общую картину ошибок с разбивкой по дата-центрам.

Эту общую картину потом можно детализировать с помощью запросов, которые работают только с ошибками 504 и т. д. Другой пример — допустим, мы хотим выяснить, есть ли корреляция между нагрузкой сервера и количеством возникающих на нем ошибок.

Запрос «SELECT load,nginxErrorRate FROM data WHERE role="be1» ORDER by nginxErrorRate DESC» дает нам возможность построить график или аналитически обнаружить такую зависимость.

Список таких примеров можно продолжать.

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

Это не решение, которое заменяет комбинации типа statsd+graphite хотя бы потому, что нет ведения истории; возможность быстро получать разные снимки поведения системы — это просто бонус к анализу связности между сервисами.



Заключение

Описанная система в настоящее время контролирует связь около тысячи контейнеров.

Никаких проблем с производительностью пока не обнаружено.

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

Мы боремся с этим, регулируя чувствительность оповещений Nagios. Теги: #мониторинг #Высокая производительность

Вместе с данным постом часто просматривают: