Это лишь часть таблицы инструментов, которые мы рассматривали. Подробнее по ссылке.
Мы используем New Relic в каждом из наших 250 PHP-сервисов. С его помощью отслеживаем взаимосвязи между сервисами, их зависимости, смотрим нагруженные транзакции, анализируем полный трейс запроса пользователя. Наши основные функциональные требования: связи, оценка по времени отклика и параметру APDEX (собирательное значение удовлетворенности пользователя).
Отказаться от New Relic хотели давно. Главная причина — он стал дорогой. Весной добавилась вторая причина — мы из России. Запереживали, что нас могут отключить. А мы в команде инфраструктуры стараемся все сервисы держать на своей стороне.
В августе закончился договор с New Relic, так что заранее стали искать ему замену. И вот, как оно было.
С чего начали
Переезд оттягивали долго — задача большая и сложная. После 24 февраля взяли ее в план как целевую. Рассматривали все варианты: закрытые и опенсорс-аналоги New Relic.
Изначально была идея найти дешевую замену в Пакистане или Индии — странах, которые придерживались нейтралитета в отношении России. Примеры таких сервисов: Atatus и Site24x7. Мы отправили им запрос про цены и, получив ответ, ужаснулись. Оказалось в разы больше, чем нам обходился New Relic.
Процесс затягивался, потому что на письма с российской почты либо не отвечали, либо выдавали цены выше, чем на официальных сайтах. Начали активнее смотреть опенсорс-аналоги.
Главные минусы опенсорс-вариантов
Практически у всех отсутствует алертинг. Надо накручивать сверху, но с этим можно жить.
В некоторых нет APDEX-метрики. А у нас разработчики к ней привыкли.
Мы решили составить список важных нам характеристик, которые должны быть у инструмента. Я пошел в чат с разработчиками и попросил их назвать все, чем они пользуются в New Relic. Просмотрел ответы, отыскал старые аналогичные треды про возможный переезд, структурировал и выписал основные требования. Собралась первая колонка таблицы — с нужными характеристиками. Их 19.
На всякий случай дублирую ссылку на таблицу.
Также мы добавили каждому требованию приоритет:
Желательно — если не будет, то мы не расстроимся или разработаем альтернативу.
Важно, но не критично — было бы приятно, но можно жить и без.
Критично — супер важное требование.
Для наличия / отсутствия нужных характеристик у аналогов, выбрали разные цвета:
Зеленый — все в порядке.
Желтый — чего-то не хватает.
Красный или черный — у инструмента все плохо с характеристикой или мы протестировали его и он нам не подошел.
Фиолетовый — нет информации.
Если у сервиса критичный для нас параметр окрашивался в красный или черный — мы говорили ему «нет». Хотя были исключения, но об этом позже.
Я выписал все аналоги, которые нашел гуглением или которые рекомендовали. И начал сравнивать. По каждому выставлял: открытый / закрытый софт, облако / сервер, штаб-квартиру и так далее. Указывал стоимость, если цифра была в открытом доступе. Для опенсорс-решений мы старались найти примерный хост, который требуется для обеспечения минимальной жизнеспособности, и сделать десятикратный запас. Например, Apache SkyWalking стоит 200$ за стандартный хост. С запасом x10 — это 2000$.
У нас 98% бэкенда на PHP, поэтому была важна метрика поддерживаемых версии PHP. Нужно, чтобы инструмент поддерживал 7.2 — есть ряд старых проектов, хотя основная 7.4 и выше. И, конечно, важна поддержка 8.1.
Еще был важен тип агента PHP, чтобы установить новое расширение и не устраивать переделку кода 500 сервисов.
В итоге, выбрали 2 опенсорс-кандидата.
Apache SkyWalking и Zipkin
Мы остановились на них, несмотря на отсутствие алертов. У Zipkin еще и нет APDEX-метрики. Но это то, с чем решили смириться и прикрутить при необходимости.
Что дальше? Начали тестировать. Первым был Zipkin. Его название понравилось больше :)
Развернули сервер и посмотрели, как он выглядит снаружи. По сравнению с New Relic — печально, но терпимо. Для полной проверки решили собрать больше данных и подключить наши сервисы. У Zipkin есть бандлы, поддерживающие Symfony, но понадобилось расширение, которое на уровне PHP перехватывало бы запросы. И мы его нашли — Molten.
Проблема — Molten давно не обновляется и не поддерживает ни PHP 8.1, ни 7.4. Последнее обновление библиотеки — полтора года назад, комментарии на китайском. От идеи двигать Zipkin дальше мы отказались…
Попробовали SkyWalking. Он показался более готовым к продакшену.
Подняли сервер на тестинге — все более-менее. Зашли в интерфейс — понравилось и даже похож на New Relic. Стали подключаться к сервисам и нашли огромный недостаток — расширение SkyWalking, которое мы использовали, не поддерживало консольные команды! Все консьюмеры и задачи, которые у нас запущены по Cron, никак не отображались. Я не мог понять, как такое возможно. Связался с контрибьютером. Оказалось, из-за архитектуры расширения, CLI плохо контролируется и его поддержка не реализована – пруф. А это для нас критичный момент.
Снова вернулись к таблице альтернатив.
Elastic APM
Бесплатных вариантов не осталось, а из полуопенсорс только Elastic APM. Он требует лицензию. Мы рассчитывали, что она обойдется в 125$, плюс содержание своих серверов. Пообщавшись с Elastic, выяснили, что расклад следующий:
Стоимость одной ноды — 6000$ в год.
Минимальный контракт — 3 ноды.
Elastic насчитали, что нам нужно 5 нод.
Получается, Service Map стоил бы нам примерно 18-30 тысяч долларов в год. И, кажется, этот функционал лучше реализовать самим.
У Elastic APM есть PHP-расширение. Мы раскатили на тестинге и столкнулись даже с большим количеством проблем, чем в двух предыдущих вариантах:
Нет внятной документации по развертыванию в Kubernetes. Пришлось звать DevOps-команду и разбираться.
При поднятии на тестинге выяснилось, что Elastic APM заблокировал РФ. Например, чтобы внутри Kibana установить расширение для интеграции с Elastic APM, нужно подключиться к серверам Elastic Core, который блокирует любые запросы с нашей стороны.
Подумали и для интеграции подняли по инструкциям Elastic Registry, то есть свой сервер с этими же интеграциями.
Невозможно купить лицензию. Вкладка спрятана, опять же по причине блокировки РФ. Нашли внутреннюю апишку и подключили триал.
Нам снова не хватало данных. Попробовали с инфровых сервисов, у которых много связей, слать данные на тестинг. Получилось, но столкнулись с недоработками PHP-расширения.
Расширение работает стабильно, поддерживает PHP 7.2-8.1, можно нормально настроить конфигурацию и даже поставить дебаг-режим, чтобы получать сообщения об ошибках.
Но:
Внутри пришлось отключить HTTPS.
Не поддерживается Symfony HTTP-клиент из-за отсутствия поддержки curl_multi.
Не выстраивается список зависимостей для сервиса, используемые базы можно увидеть только напрямую в транзакции.
Несколько запросов к разным базам данным лепятся в одну базу. Он их не умеет различить, сматчить и построить сервисную карту.
Пришел август
Летом New Relic предупредили, что 30 августа переведут нас в режим read-only, поэтому обратного пути не было.
Мы подняли публичную продовую версию Elastic APM внутри под VPN, определились с архитектурой и вырезали лишнее, чтобы сделать ее легковесной. Стали подключать сервисы к Elastic APM, смотреть на данные и сверять с New Relic.
Единственное, что мы не нашли в Elastic APM — апишку, которая позволяет получать оттуда данные. Мы не можем по API запросить зависимые от сервисов сервисы. Поревесинженирили и нашли недокументированную API, которая дает данные для сервисной карты на фронт.
О доработках на стороне расширения
Расширение работало стабильно с PHP 8.0 / PHP 7.2, но не было поддержки RabbitMQ и Symfony Messenger. Для того, чтобы видеть данные по очередям в Elastic APM, мы создали внутренний бандл для Symfony. В нем частично перенесли функционал, который у нас уже был написан для New Relic.
Следующая проблема — в APM отсутствуют данные по запросам к сервисам кешей (Memcached, Redis). Начали смотреть, что с этим делать. Со стороны расширения это была большая доработка. Решили его не править, а позаимствовать внутри нашего бандла функционал, который использует Sentry для получения данных о запросах к кэшу.
Еще одна проблема — в Elastic APM не то чтобы отсутствует поддержка Symfony HTTP-клиента, просто он по умолчанию использует асинхронные операции, которые реализованы через curl_multi. А расширение Elastic APM не умеет обрабатывать curl multi. Даже в бэклоге нет задачи на поддержку этого.
Полезли править. Добавили curl multi, а также сохранение результатов по запросу в момент, когда получен первый статус от сервера. Это нам дает хотя бы некоторые данные о том, какой код ответа на запрос и за сколько сервер его приготовил.
Внесли доработки и поняли, что если будем делать мерж-реквест в официальный Elastic-репозиторий, то это займет много времени, а уже нужно катить. Поэтому клонировали к себе в GitLab репозиторий Elastic и закомитили правки.
Затем еще сложности. Расширение не записывало дополнительные данные по запросу в БД (название базы, адрес и порт, по которому обращение) и не поддерживало Opcache preload. Тоже доделывали.
Едем дальше.
На этом проблемы не закончились
Мы все еще используем New Relic и Elastic одновременно и они вроде не конфликтуют. Но если приложение подключается к другому Elastic по HTTP-соединению, то автоматический инструментарий New Relic и Elastic APM добавляют в header заголовок трейса, который по стандартам W3C должен быть один. А у нас получается два. И когда приходит запрос в Elasticsearch, то он выдает ошибки мультизаголовков. Выкатили для таких сервисов отдельный образ с отключенным New Relic и подготовили инструкцию по срочному переходу.
У нас постоянно сыпятся ошибки в логи контейнеров о том, что сервер не имеет HTTP-хост ключ. Это происходит из-за того, что есть хелсчеки, которые обращаются на 127.0.0.1. И у них во время запроса не определялся $_SERVER[‘HTTP_HOST’], а Elastic APM думает, что это все равно внешний запрос, пытается найти HTTP_HOST, не находит его. Из-за этого у нас общий фон логов с одной и той же ошибкой возрос по всему Skyeng. Не сильно мешает, но и не очень красиво. В итоге, повысили уровень логирования в расширении до CRITICAL, так-как помимо инфраструктуры, разработчиков это тоже сильно нервировало.
Стали проходить не все тесты. Для раннего обнаружения ошибок в образах PHP мы не отключали полностью Elastic APM не на проде. Он работает, но ничего не отправляет. Во время тестов, когда большое количество миграций и прочего, Elastic APM падает по памяти. Ограничились тем, что те, у кого происходят такие проблемы, во время тестов добавляют отдельную энвайронмент-переменную Elastic AMP disabled instrumentations. APM работает, но автоматически ничего не записывает и не тратит память.
После того, как раскатилось около 50% сервисов (примерно 100), мы стали не справляться с нагрузкой. По памяти и по CPU Elasticsearch и Kibana тянули нагрузку хорошо, а APM-серверы, которые находятся в кластере на отдельных 10 подах, начали сильно загружаться. Нам пришлось увеличить количество подов, временно убрать им ограничение на память и CPU, а также включить автоматическое масштабирование, потому что поток данных потек большой.
Потихоньку подключались следующие сервисы. Мы начали готовиться к переносу алертов из New Relic в Elastic APM… И тут не обошлось без проблем. Мы до сих пор на бесплатной лицензии, а интеграции алертов со Slack и с веб-хуками, которые используются для связи с Opsgenie — на Gold-версии.
Еще Elastic APM не умеет алертить по отдельным транзакциям — только по целому сервису. Например, есть у сервиса отдельный эндпоинт, который отвечает долго. В New Relic можно было для него настроить отдельный порог срабатывания алерта, а в Elastic APM нужно настраивать алерт по среднему уровню по больнице.
В результате, у Elastic APM либо всё время будет алертить медленный эндпоинт (порог настроен по быстрым эндпоинтам) или алертов просто не будет (порог настроен по медленному эндпоинту). У нас же принято, что все алерты настроены на определенные транзакции. Пока с помощью Grafana смогли получить данные из Elasticsearch по APM, вытащить оттуда данные по каждой из транзакций и настроить алерты. Но сложность в том, что Grafana постоянно запрашивает данные. Если сделать так для всех алертов — Elastic будет задыхаться. Решили таким способом выстраивать только критичные алерты.
Итоги
Положительные стороны Elastic APM и его расширения: | Что не очень: |
Есть расширение и оно работает! Поддерживает PHP 7.2-8.1. Есть визуализация «из коробки». Под капотом всё настроено для работы с данными APM. | Практически полное отсутствие возможности оптимизировать данные. Отправлять только транзакции с ошибками или вне среднего времени выполнения нельзя. Не поддерживается opcache.preload. Для алертов в Slack и OpsGenie или для ServiceMap требуется Platinum лицензия. В консьюмерах есть проблемы при работе расширения. Там его пришлось отключать. |
Мы перевезли 180 сервисов. Остаются задачи по оптимизации хранения и дошлифовке расширения, но основной функционал уже production-ready. Дежурные инфраструктуры используют Elastic APM для расследования инцидентов — пару раз он им в этом сильно помог.
С 1 сентября мы остались без New Relic. Хорошо, что к этому моменту была альтернатива, хоть и в состоянии MVP. Возможно, работая над разработкой собственного расширения в связке с Prometheus Grafana, вместо поиска альтернатив, мы бы закончили разработку также. Но теперь наш путь — дорабатывать имеющиеся расширение вместе с ребятам из Elastic.
Вот мы рассказываем про большое количество проблем, телодвижений и доработок — в целом стоил ли переезд того? Да, потому что профит от решения перевешивает, да и остальные аналоги хуже.
Если же вы решили писать своё расширение — PHP Internals Book в помощь.