В современном мире скорость отклика приложений является критическим фактором их успешной работы. Особенно это касается глобально распределённых систем, где миллисекунды могут значительно влиять на пользовательский опыт и бизнес-результаты. Компания Koyeb, специализирующаяся на серверлес-платформе для деплоя высоконагруженных приложений по всему миру, столкнулась с резким увеличением времени до получения HTTP 200 ответа после успешного развертывания — эта задержка поднималась с привычных 30 секунд до нескольких минут. Рассмотрим, как решалась эта комплексная проблема, которая привела к глубокому анализу компонентов Envoy и Consul в инфраструктуре. Koyeb предлагает пользователям удобную платформу для глобального запуска контейнеров и кода с автоматическим управлением инфраструктурой.
В основе их технолог stack лежит связка Envoy, как глобального и региональных балансировщиков нагрузки, и Consul — для сервис-дискавери и метаданных приложений. Появление заметных лагов заставило команду разработчиков тщательно проанализировать цепочку взаимодействий — от выхода кода на глобальные балансировщики трафика до получения актуальных данных о зарегистрированных сервисах. Начальная подозрение пало на Envoy — прокси и балансировщик, который управляет маршрутизацией трафика на основе подробных конфигураций. В Koyeb архитектура предусматривает два уровня балансировки: глобальные балансировщики, которые направляют запросы в ближайший регион, и региональные HTTP балансировщики, которые более точно направляют трафик к конкретным инстансам. Для обновления конфигураций у них существует внутренний сервис knetwork, занимающийся генерацией и доставкой настроек Envoy по всему миру.
Аномалии в производительности knetwork и удлинённые времена генерации конфигураций уже являлись тревожным сигналом. Однако полный размах проблемы раскрывался при глубоком анализе работы региональных балансировщиков и их взаимодействия с Consul. В каждом регионе Consul осуществляет регистрацию всех приложений и поддерживает актуальную информацию для сервисов. knetwork регулярно обращается к Consul для получения списка сервисов и соответствующих метаданных. Неожиданно команда обнаружила, что значительная часть задержек и возросшей нагрузки приходится на вызовы к эндпоинту Catalog.
ListServices(), являющемуся критически важным для получения информации о доступных сервисах. Профилирование Consul с помощью pprof предоставило подтверждение: CPU-потребление кластером возрастало именно из-за этой функции, которая вызывалась значительно чаще, чем ожидали инженеры. Данные логов Consul и включённый режим TRACE выявили, что количество запросов Catalog.ListServices() было аномально большим. Это заставило искать источник подобных вызовов в архитектуре.
Расследование привело к выявлению связи с использованием внутреннего кеширования в запросах к Consul через параметр UseCache. Специфически изменённый код в CoreDNS плагине для DNS-разрешений внутри сервис-меша стал запрашивать данные с включённым кешем в Consul. На первый взгляд, локальный кеш должен был облегчить нагрузку на Consul-серверы — однако поведение оказалось противоположным. Особенность реализации кеша в Consul заключается в механизме background refresh caching. После первого запроса данные кэшируются у локального агента Consul.
При этом агент поддерживает процесс фонового обновления кеша путём длительных блокирующих запросов к серверам Consul для отслеживания изменений в данных. Если значение в кеше устарело, происходит повторный запрос. Однако, с учётом высокой динамики списка приложений и разнообразия фильтров, которые формируют различные кеш-ключи, Consul агенты запускали множество параллельных бекграунд-рутин, каждая из которых регулярно обновляла кеши и тем самым неоднократно вызывала вызывающий высокую нагрузку Catalog.ListServices() на серверах. В итоге, включение кеша в запросах, служившее для повышения надёжности при возможных сбоях Consul, приводило к эффекту лавины запросов и росту CPU потребления, задержке в синхронизации конфигураций Envoy и, как следствие, к увеличению времени «готовности» приложений.
Чтобы завершить расследование, команда Koyeb решила отказаться от встроенного кеширования Consul, внедрив собственный минималистичный кеш на уровне сервиса, который хранил недавние результаты вызова Catalog.ListServices() и предоставлял отказоустойчивость, необходимую для корректной работы в случае недоступности Consul. Это позволило уменьшить нагрузку на Consul и возвратить показатели латентности к привычным значениям. Из рассмотренного кейса можно вывести несколько важных уроков для разработчиков и команд инженеров, работающих с глобально распределёнными системами. Кеширование — эффективный инструмент оптимизации, но его внутренние механизмы необходимо тщательно изучать прежде, чем внедрять в продакшен.
Скрытые фоновые процессы могут приводить к неожиданной нагрузке и нарушать стабильность. Активное использование инструментов профилирования, таких как pprof, и включение расширенного логирования помогают быстрее локализовать источник проблем. В целом, опыт Koyeb иллюстрирует, что даже популярные и отлаженные компоненты, как Consul и Envoy, требуют подробного понимания своих внутренностей и адаптации под специфику нагрузки и архитектуру конкретного проекта. Внимательное изучение исходного кода и документированных особенностей позволило не только решить проблему, но и получить ценный опыт для предотвращения подобных ситуаций в будущем. Проблемы с задержками и производительностью неизбежны в масштабируемых системах, особенно при экспансии по глобальному масштабу.
Важно иметь постоянный мониторинг, чётко организованный процесс расследования инцидентов и гибкие методы адаптации конфигураций и компонентов. Только тогда можно обеспечить надёжную эксплуатацию и удовлетворённость пользователей. Опыт Koyeb с Envoy и Consul демонстрирует необходимость комплексного подхода к решению проблем производительности и важность понимания не только бизнес-логики, но и внутренней архитектуры используемых технологий. В условиях стремительного развития распределённых вычислений этот подход становится залогом успеха в создании эффективных и устойчивых в работе приложений.