Это короткая история наивного любителя популярных технологий.

Ранее я уже писал почему на моем текущем проекте мы решили использовать — Apache Kafka, если вкратце, то цель — унификация используемых технологий в компании.

Сфера деятельности компании это ставки на спорт, зона ответственности моей команды состоит в том, чтобы принять и оцифровать происходящее на игровом поле, будь то реальное поле з зеленой травкой или серый бетон виртуального CS:GO.

Очень важно чтобы данные инцидент произошедший в игре был передан дальше по системе и коэффициенты были пересчитаны быстрее чем потенциальный Беттер поставит очередную ставку на основании новых вводных. Например, забитый гол в лиге чемпионов на 90+ минуте основного времени.

Итак, вернемся к нашим баранам.

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

Там где можно сэкономить — экономят.

Наша компания не исключение. Для обеспечения организационной части бизнеса — СРМ и интерфейсов первичного ввода данных(интерфейс судьи/статиста) мы используем PHP, для того чтобы производить сложные вычисления, используются иные технологии.

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

Что для “русского” - хорошо, для “немца” — смерть.

Адаптировав эту поговорку под ИТ можно сказать иначе:

Что для компилируемых ЯП — хорошо, для скриптовых — смерть.

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

Но, есть маленький нюанс.

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

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

В моем случае процесс установления соединения занимал 100–300мс.

Сразу же отмечу что система работала с дефолтными настройками и никакой тюнинг не производился, за неимением специалистов с глубокой экспертизой по настройке работы Apache Kafka.

Проблема: Сам по себе тайминг в 300мс для нас не являлся критическим, нас устраивает время ответа до 1 сек. Поскольку весь остальной код отрабатывает за ~100мс, то мы отлично вкладывались в установленные нормы SLA.

Несмотря на то, что сам код приложения и Apache Kafka(AWS MSK) находились в одной Availabilty Zone, а поначалу и вовсе на соседних EC-2(Kafka была в Docker’е), это никак не избавило нас от сетевых сбоев и задержек/проблем присутствующих в инфраструктуре AWS.

Мы постоянно наблюдали, несколько раз в сутки, скачки во времени установления соединения до 1500мс, что являлось для нас критическим таймингом. Мы могли бы конечно решить этот вопрос, например, с помощью — родного для PHP брокера сообщений RabbitMQ, но это же "костыльный костыль" и еще как минимум одна/две точки отказа, вторая это демон(или тулза) который бы перекладывал сообщения из одной системы очередей в другую.

Поскольку мы не хотели идти на столь отчаянный шаг, мы решили посмотреть в другую сторону. Этой стороной оказалось использование http proxy. После некоторых исследований и экспериментов мы остановились на open sourse решении от компании confluent — Kafka Rest Proxy.

Данный инструмент написан на Java. Весь секрет в том что прокси подсоединяется к кластеру Kafka, держит с ним соединение и принимает http запросы — быстро производит запись и отдает ответ содержащий метаинформацию о результате вставки, например - offset записанного сообщения.


В итоге мы получили стабильную скорость записи ~10мс, без неожиданных скачков. Естественно скорость будет зависеть от массы факторов, как например: размер сообщения, количество брокеров в вашем кластере или сотен других доступных к настройке параметров Kafka.

Вывод: шалость удалась, но пришлось использовать магию из запретной секции :)

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


  1. xeeaax
    31.08.2022 00:07
    +2

    Разумно. Если критично время, то вредно под запрос устанавливать соединение.
    (у нас один разработчик смог даже на REST Proxy каждый раз устанавливать соединение)

    Кстати, а почему Kafka, если важно время? Она вроде сильно хуже RabbitMQ по таймингам?


    1. VladVerpeta Автор
      31.08.2022 09:25

      Иные команды в компании имеют потребность использовать Kafka и для того чтобы не раздувать зоопарк технологий - решили остановится на этой технологии.

      Писал об этом в другой своей статье, линк на неё в самом начале)


  1. vgoodvin
    31.08.2022 10:03
    +1

    А что делает RabbitMQ для PHP родным? Для него кстати тоже есть такой прокси cloudamqp/amqproxy.


    1. VladVerpeta Автор
      31.08.2022 11:02
      +1

      php - умеет держать persistent connection по amqp протоколу, а с Kafka - такого пока не придумали.

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

      RabbitMQ использует протокол amqp - который также является достаточно затратным для установки соединения, но на моей практике - проблем это не вызывало.

      С RabbitMQ начинаются проблемы, когда начинается работа с 10+к сообщений в секунду или же когда хочется большие сообщения пересылать(500kb+).


  1. Djeux
    31.08.2022 11:01

    Если память не изменяет, Slack использует Go для подобного решения. Go держит соединение с кафкой и принимает http запросы от PHP

    https://slack.engineering/scaling-slacks-job-queue/


    1. VladVerpeta Автор
      31.08.2022 11:34

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


      1. Djeux
        31.08.2022 12:03

        Можно еще librdkafka с https://github.com/arnaud-lb/php-rdkafka глянуть. Решает проблему поднятия соединения.


        1. VladVerpeta Автор
          31.08.2022 12:13

          Мы её и используем)

          Она отлично работает, мы ее используем в консюмерах, там где соединение устанавливается 1н раз и держится постоянно, но в режиме request/response эта либа не дает возможности держать постоянное соединение(