Гибриды побеждают или холивары дорого

    Мотивом для написания данной статьи послужил тот факт, что на habr.com участилось появление материалов маркетингового характера про Apache Kafka. А также тот факт, что из статей складывается впечатление что пишут их немного далекие от реального использования люди — это конечно же только впечатление, но почему-то в большинстве своем статьи обязательно содержат сравнение Apache Kafka с RabbitMQ, причем не в пользу последнего. Что самое интересное — читая подобные статьи управленцы без технического бэкграунда начинают тратить деньги на внутренние исследования, чтобы ведущие разработчики и технические директора выбрали одно из решений. Так как я очень жадный/домовитый, а также так как я сторонник тезиса "В споре НЕ рождается истина" предлагаю вам ознакомится с другим подходом — почти без сравнения разных брокеров.


    Без сравнения никуда


    Вообще, по правильному, я должен был сделать статью в формате Kafka+RabbitMQ+Nats+ActiveMQ+Mosquito+etc, но мне кажется, что для Вас дорогие читатели это будет перебор, хотя обычно в моих архитектурных решениях присутствуют все вышеуказанные сервисы (и не только). И это я еще не рассказываю про AzureServiceBus/AmazonServiceBus — которые также участвуют в "гибридах" при крупных программах проектов. Поэтому пока остановимся на связке Kafka+RabbitMQ и далее вы поймете почему: по аналогии можно подключить любой сервис с его протоколом. Потому что:


    сравнивая Apache Kafka и RabbitMQ вы сравниваете 2 (два) бренда, а точнее 2 коммерческие компании — Confluent и vmWare, и немножко Apache Software Foundation (но это не компания)

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


    • RabbitMQ — мультипротокольный и расширяемый брокер сообщений
    • Apache Kafka — платформа для распределенной потоковой передачи событий
    • Confluent Platform — платформа потоковой передачи событий с возможностью создания высокопроизводительных конвейеров обработки данных для целей аналитики и интеграции в бизнес-сценариях

    Я не зря третьим пунктом выделяю наработки компании Confluent — те кто собирается использовать Apache Kafka в продуктиве должны хотя бы видеть какую функциональность дополнительно добавляет Confluent к Apache Kafka. А это SchemeRegistry, RestProxy, kSQL и еще несколько интересных штук, о одной из которых мы поговорим ниже, она называется Kafka-Connect.


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


    Итак — чтобы было совсем понятно, куда я веду.


    • ключевая особенность RabbitMQ — мультипротокольность и расширяемость. (основной язык якобы Erlang)
    • ключевая особенность экосистемы Kafka — потоковая передача с обработкой (основной язык якобы Scala/Java)

    Отсюда и возникают минусы каждого из решений


    • для RabbitMQ мы не сможем построить нормального решения для потоковой обработки. Точнее сможем, но НЕ штатно.
    • а для Kafka мы не сможем сделать мультипротокольность, точнее сможем но НЕ штатно.

    Сократ не говорил, что в споре рождается истина


    Еще одна новость: действительно, если почитать источник, то Сократ вообще-то в итоге пришел к тому, что нужно обеспечить диалог, а если по научному — то истина рождается в научном споре, который формально представляет собой процесс публикация со ссылкой на источники -> а затем научная критика оппонентов -> истина


    А значит перейдем к ссылкам — для начала их будет три. Когда 14 лет назад я совместно с коллегами начинал использовать брокеры сообщений в качестве основы для построения своих интеграционных решений, мы сразу обратили внимание, что фактически с точки зрения "клиента" (конечного приложения), под разные задачи подходят разные протоколы интеграции.


    • ODBC
    • AMQP
    • MSMQ
    • XMPP
    • IP over Avian Carriers

    так как тогда наша задача была интегрировать всякое (python, C#, java) и 1С — был придуман проект One-S-Connectors (ссылка). Сейчас он имеет сугубо академический интерес (так как в 1С мире моя персона достаточно известна и на Хабре много 1С специалистов из сообщества "воинствующих 1С-ников" — эта ссылка специально для них).


    Однако уже тогда (в 2006 году) стало понятно, что по большому счету конечному разработчику придется менять/выбирать протокол под бизнес-задачу. А инфраструктурщикам придется обеспечить максимально широкий спектр интеграционных протоколов. От ODBC до Kafka/NATs/ModBus.


    Но вернемся к дню сегодняшнему — когда я начал использовать в проектах уровня ГИС (государственные информационные системы) различные транспорта данных внезапно выяснилось, что универсальные адаптеры — это не только концепт воинствующих 1С-ников, но и соседей. Поэтому многие идеи при внедрении черпались из еще двух интересных проектов



    маленькое примечание для менеджеров про Kombu — как то так получилось, что имплементация протокола Apache Kafka до сих пор открыта и почему-то перешла в разряд "Дайте денег", поэтому для Python проектов приходится использовать дополнительно https://github.com/confluentinc/confluent-kafka-python

    Когда вы дочитаете до этого момента — предполагаю, что вы зададите вопрос про остальные языки: Java, GoLang, RUST, etc. Но во первых я не зря выше указал что по серьезному в наш обсуждаемый сегодня гибрид нужно добавить историю про NATs и ActiveMQ и внезапно JMS — поэтому просьба дочитать до конца: Java будет, а во вторых мы переходим к еще трем полезным ссылкам



    Прокомментируем их? Дело в том, что как бы вы не хотели, а для полноценного использования "в длинную" — вам придется подписаться на историю релизов как сервера RabbitMQ и самое главное на те самые расширения (лежат в каталоге /deps) которые постоянно добавляются в ядро RabbitMQ, так и на портал компании Confluent где она публикует приложения полезные для конечного бизнеса использующего Apache Kafka в продуктиве.


    подход к расширяемости за счет активируемых расширений также используется в экосистеме PostgreSQL — тот который CREATE EXTENSION hypopg, так что подход реализованный компанией Pivotal/vmWare далеко не новый в нашем чудесном мире архитектуры программного обеспечения

    Дополнительно — на чудесном рынке облачных услуг в формате "Серьезная штука как сервис" есть еще один игрок — это компания 84Codes. Когда в рамках проектов внедрения нет нормальных инженеров по инфраструктуре — именно 84Codes спасает пилотные проекты, потому как у них можно легко арендовать бесплатные/сильнодешевые контура CloudAMQP и CloudKarafka.


    Я как бы обещал, что не буду ничего говорить про деньги, однако придется отразить 2 ключевых момента:


    • компания vmWare зарабатывает известно на чем, поэтому RabbitMQ ей развивается как часть своей платформы — то есть они инвестируют в открытый проект не особо занимаясь его монетизацией. Возврат их инвестиций происходит в других местах, ну и также за счет контрибьюторов на GitHub.
    • а вот компания Confuent собирается монетизировать свою платформу через Enterprise лицензию в которую включает те самые коннекторы Enterprise-Kafka-Connect, а также GUI для управления платформой.

    Когда-то давно существовал https://github.com/jcustenborder/kafka-connect-rabbitmq, примечателен тот факт, что товарищ Джереми его скрыл, оставив только свои наработки для Java разработчиков в виде Maven Archetype — еще раз обращаю Ваше внимание, что компания Confluent будет и дальше пытаться монетизировать свою деятельность, так что переводить всю интеграцию только на Kafka я бы на вашем месте поостерегся.

    Поэтому когда вам топят за Kafka учитывайте, что вы либо изучаете Java, либо платите за Enterprise лицензию. А когда вам топят за RabbitMQ учитывайте, что либо вы изучаете системное администрирование (Erlang накладывает особенности системного администрирования), либо покупаете сервис у провайдеров типа 84Codes. Кодить на Erlang никогда не придется — там это не нужно, если только вы не контрибьюторы OpenStack.


    Поставил и забыл — уже не работает


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


    • использование только одного протокола интеграции приводит к появлению ProtocolLock и как следствие к VendorLock — я же не зря выше написал, что за каждым открытым продуктом, стоит какой-то ключевой комплект вендоров — как они себя поведут: мы не знаем.
    • в мире ИТ больше нет серьезных продуктов, которые бы представляли собой монолитную службу — все приложения давно стали композитными.
    • все нормальные вендоры сокращают свои релизные циклы по ключевым продуктам — нормальной практикой стало выпускать редакции раз в 3 месяцаTDD, BDD, CICD, ScallableAgile и DevOps (DocOps, DevSecOps) — эти инженерные практики и методики управления не просто так развиваются. Всем очень хочется сокращать себестоимость и TimeToMarket.

    Абзац выше важен, как финальный аккорд, прежде чем мы перейдем к Docker-Compose. А именно к нему я вел — чтобы и разработчики и инфраструктурщики понимали что такое гибридная инфраструктура в режиме мультипротокольности (с) — нужно сделать так, чтобы каждый мог поэкспериментировать с предлагаемым контуром. Как я уже указал выше — первично подобное применительно к Kafka+RabbitMQ было подсмотрено именно у коллег из 84Codes (хорошие ребята — всем советую).


    Чтобы вы смогли поэкспериментировать сами


    Итак подходим к примерам, так как обоснования и вводных уже хватит. Предположим вы уже поняли, что вам также нужна мультипротокольность, однако мы же помним, что все рекламные материалы про Apache Kafka нам рассказывают что это единственное решение с реализацией exactly-ones доставки сообщений от отправителя получателю. Собственно на самом деле — нам и нужен гибрид, чтобы сделать из связки ТочкаОбмена->Очередь журнал Kafka (это тот который Topic) — чтобы возникла сущность под называнием Offsets у нашей очереди событий.


    exactly-ones

    проверка на внимательность читающего exactly-ones — это шутка в формате "Хотя бы один раз из 1С", а имеется в виду концепт Exactly once — строго однократная доставка сообщений получателю, без необходимости повторной отправки от отправителя.


    Предлагаю попробовать. Концепт для проверки Вашими руками будет состоять из:


    • Zookeper
    • KafkaBroker
    • RabbitMQ
    • KafkaConnect

    и трех приложений приложений


    • отправитель на Python по протоколу AMQP 0.9
    • получатель на С# по протоколу AMQP 1.0
    • получатель на C# по протоколу Kafka

    Еще интересное замечание: когда вы смотрите на всякие обучающие видео по Apache Kafka — авторы часто (но не всегда) старательно пишут примеры на Java, это они делают скорее всего для того, чтобы скрыть от вас особенности использования librdkafka — C++ библиотеки на основе которой сделаны многие не-джава адаптеры,. Я же наоборот предлагаю вам начинать исследование интеграции с Kafka именно с неё, чтобы четко оценивать риски "куда вы ввязываетесь": очень примечательно что там работает фактически один разработчик, формально в одиночку https://github.com/edenhill/librdkafka/pulse/monthly, а допустим wmWare старается поддерживать свою линейку клиентов под своим брендом.

    Ну и самое главное и тяжелое:


    контур содержит открытый форк старого RabbitMQ-Kafka-Sinc-Connector — того самого который товарищи из Confluent в своё время скрыли с Github.


    Докер контура для экспериментов


    Для показательного эксперимента мы сделаем 2 композитных приложения — инфраструктурное-трансформационное и непосредственно бизнес-приложения.


    Развертываем RabbitMQ и Kafka


    контур инфраструктуры который нам понадобится — запускается достаточно просто


    docker-compose -f dockers/infra.yml up -d

    Если вам интересно что же там внутри, нашего композитного приложения, то в конце статьи дается ссылка на полный комплект исходников, наиболее интересен в нем Kafka-UI и непосредственно RabbitMQ-Sinc, все остальное обычно и штатно для всех известных примеров по Kafka или RabbitMQ


        image: provectuslabs/kafka-ui:latest
        ports:
          - 8080:8080
        depends_on:
          - kafka-broker
          - zookeeper
        environment:
          KAFKA_CLUSTERS_0_NAME: local
          KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS: broker:29092
          KAFKA_CLUSTERS_0_ZOOKEEPER: zookeeper:2181
          KAFKA_CLUSTERS_0_JMXPORT: 9101
    

    Но самое главное кроется в репозитории Java


        <parent>
            <groupId>com.github.jcustenborder.kafka.connect</groupId>
            <artifactId>kafka-connect-parent</artifactId>
            <version>1.0.0</version>
        </parent>

    Если подробно изучить pom.xml — то выяснится, что существует заглавный проект для всех коннекторов к Кафка, в котором используется Java-Kafka-Adapter


    И непосредственно синхронизацией c RMQ занимается штатный Java клиент:


                <groupId>com.rabbitmq</groupId>
                <artifactId>amqp-client</artifactId>
                <version>${rabbitmq.version}</version>

    Таким образом — по правильному, чтобы получились повторить тот же эксперимент что и у меня, необходимо выполнить:


    • собрать из исходников java синхронизатор — -1-build-connect-jar.bat
    • собрать контейнер с синхрозатором — 00-build-connect-image.sh

    и уже потом запустить полный инфраструктурный контур


    • стартуем полный инфраструктурный контур — 01-start-infra.sh

    обратите внимание — так как Docker использует разное поведение при работе с PWD для Windows и Linux — приходится делать дубликаты скриптов. В остальных случаях — под обоими операционными системами используется интерпретатор sh

    В итоге вы получите следующий комплект сервисов



    На картинке можно увидеть как подключаются конфигурационные файлы к RabbitMQ и какая топология сетевых портов у нас будет участвовать в эксперименте:


    Назначение портов:


    • 9092 — будет использоваться для Kafka протокола
    • 8080 — используется для отображения красивой картинки состояния Apache Kafka UI
    • 5672 — будет использоваться для протокола AMQP 0.9 и он же будет работать и как AMQP 1.0
    • 15672 — используется для красивой картинки управления RabbitMQ
    • 28082 — отладочный порт для управления через curl трансформатором протоколов

    В этот момент нужно остановиться и прокомментировать особенность развертывания RabbitMQ в Docker:


    • хорошей практикой является версионирование включенных плагинов расширений — enabled-rmq-plugins

    [
        rabbitmq_management, 
        rabbitmq_amqp1_0, 
        rabbitmq_mqtt, 
        rabbitmq_federation, 
        rabbitmq_federation_management,
        rabbitmq_shovel,
        rabbitmq_shovel_management,
        rabbitmq_prometheus
    ].

    • а также в крупных проектах когда нужно передать разработчику преднастроенную топологию точек обмена и очередей, можно и нужно добавлять это в виде конфигурационного файла — rmq_definitions.json

         "bindings":[
            {
               "source":"orders-send",
               "vhost":"/",
               "destination":"orders-amqp-10-consumer",
               "destination_type":"queue",
               "routing_key":"",
               "arguments":{
    

    Запускаем наши приложения


    Остается только запустить наши приложения эмулирующие подключения


    docker-compose -f dockers/infra.yml restart protocol-connect-sync
    
    docker-compose -f applications.yml build
    docker-compose -f applications.yml up

    Топология наших тестовых приложений достаточно простая



    Исходный код также максимально упрощён:


    • отправляется как-будто бы заказ Васи с периодичностью в 2 секунды

            producer = conn.Producer(serializer='json')
            producer.publish({'client': 'Вася', 'count': 10, 'good': 'АйФончик'},
                          exchange=order_exchange,
                          declare=[kafka_queue, amqp10_queue])
            time.sleep(2)

    RUN python -m pip install \
        kombu \
        librabbitmq

    причем используется для этого максимально производительная библиотека на Си для AMQP 0.9 — librabbitmq наследуется именно от неё.


    • создан подписчик который уже по протоколу AMQP 1.0 — смотрит в свою очередь и получает события, соответственно очередь очищается и больше мы заказов Васи не получим. В этом потоке нам это и не нужно.

                Attach recvAttach = new Attach()
                {
                    Source = new Source()
                    {
                        Address = "orders-amqp-10-consumer",
                        Durable = 1,
                    },

    
                ReceiverLink receiver = 
                    new ReceiverLink(session,"netcore_amqp_10_consumer", recvAttach, null);
    
                Console.WriteLine("Receiver connected to broker.");
    
                while (true) {
                    Message message = receiver.Receive();
                    if (message == null)
                    {
                        Console.WriteLine("Client exiting.");
                        break;
                    }
                    Console.WriteLine("Received " 
                      + System.Text.Encoding.UTF8.GetString((byte[])message.Body)

    Причем в качестве драйвера выбран


      <ItemGroup>
        <PackageReference Include="AMQPNetLite.Core" Version="2.4.1" />
      </ItemGroup>
    

    именно его https://github.com/Azure/amqpnetlite Microsoft использует для маркетинга своей реализации сервисной шины. Собственно именно AMQP 1.0 как протокол они и рекламируют.


    Ну и финально


    • создан подписчик по протоколу Kafka — который при каждом старте перечитывает с нуля журнал отправленных заказов Васи. Тот самый Exactly once.

                    AutoOffsetReset = AutoOffsetReset.Earliest

                    c.Subscribe("orders-from-amqp");

                        while (true)
                        {
                            try
                            {
                                var cr = c.Consume(cts.Token);

    Выглядит наш контур в итоге следующим образом:


    • 5 инфраструктурных контейнеров


    • 3 контейнера с приложениями


    • готовый журнал транзакций заказов который можно посмотреть через Kafka-Ui


    • и готовый контур связей для RabbitMQ


    А где же Java ?


    Не волнуйтесь — при таком гибридном подходе, без неё никуда, для того чтобы всё вышеуказанное заработало пришлось сделать форк и актуализировать версии Kafka-Connect-Base


    [submodule "dockers/rabbitmq-kafka-sink"]
        path = dockers/rabbitmq-kafka-sink
        url = https://github.com/aliczin/kafka-connect-rabbitmq
    

    Но самое интересное не это, самое интересное что в этом самом Kafka-Connect нет по сути никакой магии — только код трансформации.


    По сути нам предлагают:


    • создать наследника абстрактной задачи Источника

    public class RabbitMQSourceTask extends SourceTask {

    • выполнить подписку на очередь сообщений

            this.channel.basicConsume(queue, this.consumer);
            log.info("Setting channel.basicQos({}, {});", this.config.prefetchCount, this.config.prefetchGlobal);
            this.channel.basicQos(this.config.prefetchCount, this.config.prefetchGlobal);

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

      @Override
      public List<SourceRecord> poll() throws InterruptedException {
        List<SourceRecord> batch = new ArrayList<>(4096);
    
        while (!this.records.drain(batch)) {

    Отдельно можно выделить чудесный трансформатор сообщений из AMQP 0.9 в Кафка. У несведующего в Java глаз может задергаться. У автора чувствуется многолетний опыт работы в J2EE.


      private static final Logger log = LoggerFactory.getLogger(MessageConverter.class);
      static final String FIELD_ENVELOPE_DELIVERYTAG = "deliveryTag";
      static final String FIELD_ENVELOPE_ISREDELIVER = "isRedeliver";
      static final String FIELD_ENVELOPE_EXCHANGE = "exchange";
      static final String FIELD_ENVELOPE_ROUTINGKEY = "routingKey";
    
      static final Schema SCHEMA_ENVELOPE = SchemaBuilder.struct()
          .name("com.github.jcustenborder.kafka.connect.rabbitmq.Envelope")
          .doc("Encapsulates a group of parameters used for AMQP's Basic methods. See " +
              "`Envelope <https://www.rabbitmq.com/releases/rabbitmq-java-client/current-javadoc/com/rabbitmq/client/Envelope.html>`_")
          .field(FIELD_ENVELOPE_DELIVERYTAG, SchemaBuilder.int64().doc("The delivery tag included in this parameter envelope. See `Envelope.getDeliveryTag() <https://www.rabbitmq.com/releases/rabbitmq-java-client/current-javadoc/com/rabbitmq/client/Envelope.html#getDeliveryTag-->`_").build())
          .field(FIELD_ENVELOPE_ISREDELIVER, SchemaBuilder.bool().doc("The redelivery flag included in this parameter envelope. See `Envelope.isRedeliver() <https://www.rabbitmq.com/releases/rabbitmq-java-client/current-javadoc/com/rabbitmq/client/Envelope.html#isRedeliver-->`_").build())
          .field(FIELD_ENVELOPE_EXCHANGE, SchemaBuilder.string().optional().doc("The name of the exchange included in this parameter envelope. See `Envelope.getExchange() <https://www.rabbitmq.com/releases/rabbitmq-java-client/current-javadoc/com/rabbitmq/client/Envelope.html#getExchange-->`_"))
          .field(FIELD_ENVELOPE_ROUTINGKEY, SchemaBuilder.string().optional().doc("The routing key included in this parameter envelope. See `Envelope.getRoutingKey() <https://www.rabbitmq.com/releases/rabbitmq-java-client/current-javadoc/com/rabbitmq/client/Envelope.html#getRoutingKey-->`_").build())
          .build();

    Но… Не будем критиковать, мы же в самом начале договорились — что наша главная задача добиться конечного результата удобным на сегодня способом. А итоги у нас получаются следующие.


    Итоги


    Все что здесь продемонстрировано естественно лежит на Github.


    В репозитории — https://github.com/aliczin/hybrid-eventing. Лицензия выставлена простая до невозможности Creative Commons Attribution 4.0 International.


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


    Схема коммуникации в итоге для "разработчика интеграционных потоков" (с) выглядит следующим образом — для источника и брокеров


    orderEventsApp->Amqp09: send order
    Amqp09->Amqp10: fanout\n copy event
    Amqp09->KafkaQ: fanout\n copy event
    KafkaQ->KafkaConnect: consume\n on message
    KafkaConnect->KafkaConnect: transform\n message
    KafkaConnect->Kafka: publish to topic


    а для приемников — все упрощается


    Amqp10->orderEventSubApp: subcribe\n for event
    orderJournalApp->Kafka: read kafka journal


    Приемники берут нужные им данные только по нужному им протоколу

    Ключевые посылы


    Ключевые моменты которые я хотел раскрыть данной статьей


    • стройте эксперименты и продуктивы с Apache Kafka не со штатным Java клиентом, а librdkafka и базирующихся на ней адаптерах — это позволит вам отладить сценарии разных версий протоколов KafkaAPI. Java вам пригодится в другом месте.


    • не ввязывайтесь с священные войны, что лучше RabbitMQ/Kafka/Nats/ActiveMQ — просто развертывайте сервисы и публикуйте протоколы и пробуйте свои бизнес-сценарии.


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


    • реальный ИТ ландшафт почти всегда будет мультипротокольным



    Примечание для понимающих


    чтобы гибриды развивались дальше:


    • Mosquito — очень удобен как встраиваемый брокер на уровне контролера SCADA для преобразования из ModBus/OPC-UA. Хотя как вы уже поняли из статьи — интересны реализации "мостов из протокола в протокол" — пример https://github.com/mainflux/mainflux


    • ActiveMQ — удобен для Java разработчиков, потому что у них есть боязнь Erlang, но как мы выше уже сказали — мост RabbitMQ AMQP 1.0 -> ActiveMQ легко организуется средствами RabbitMQ, кстати также как и JMS.


    • NATs — интересен как часть OpenFaaS платформы, при внедрении "своего маленького" Amazon Lambda с преферансом. И опять же подход будет всё тот же — мультипротокольные мосты с трансформацией: https://github.com/nats-io/nats-kafka — если Вам не страшно посмотрите эксперименты с OpenFaaS веселых 1С-ников — 2.5 часа примеров.



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


    Функциональность: Мультипротокольный адаптер
        Как разработчик я хочу иметь абстракцию Produser/Consumer
        С возможностью изменения протокола интеграции
        Чтобы под каждую задачу выбирать разные протоколы 
        и единый интерфейс вызова для обеспечения независимости от вендора предоставляющего транспорт
    
    Сценарий: vmWare реализует протокол Stream средствами RabbitMQ 
        Когда vmWare закончит свой плагин для потоков
        Тогда я активирую новый протокол 
        И быстро воткну его в приложение
        И так как у меня есть продуктивный кластер RabbitMQ
        И мне нужно будет просто поменять канал для отдельных бизнес сценариев
    
    Сценарий: Завтра придут 1С-ники со своим ActiveMQ из Шины для 1С
        Когда мне нужно быстро включить очереди 1С в общий контур
        И чтобы на Питоне использовать старые наработки с Kafka API
        Тогда я добавляю трансформацию ActivemeMQ2Kafka
        и живу по старому а события ходят уже и из 1С
    
    etc

    А чтобы вы не думали, что данный подход — это нечто уникальное — вот Вам еще интересная ссылка — это когда нужен FTP сервер, а хочется S3.


    Ну и в качестве финального момента — обратите внимание: есть и риски данного подхода: но они я думаю Вам и так понятны.


    • Придется оркестрировать такой комплект сервисов и вручную это почти невозможно. Придется использовать DevOps штуки типа k8s, OpenShift, etc — но если вы уже решились на интеграцию в режимах слабой связаности приложений в режиме онлайн, у вас что-то на эту тему уже скорее всего есть.
    • Трансформаторы между протоколами приходится дорабатывать — ничего готового открытого и PRODUCTION-READY на данный момент найти почти невозможно.

    Финальное примечание для любителей писать ТЗ по ГОСТу


    так как Хабр читают любители цифровой трансформации (чтобы кто ни понимал под этим словом) советую в техническое задание добавлять не упоминание конкретных реализации серверов, а что-то примерно следующее:


    комплект программ для интеграции должен реализовывать коммуникацию конечных приложений по открытым протоколам HTTP, AMQP 0.9, AMQP 1.0, Apache Kafka не ниже версии 23, MQTT, WebSockets, <ЛюбойДругойХотьSOAPХотяЭтоЖуть> с возможность преобразования между протоколами дополнительными средствами администрирования

    Надеюсь моя публикация после долгого перерыва Вам будет полезна в ваших интеграционных проектах. Предполагаю что будет вопрос про 1С — и тут у меня совет только один. Используйте Google по ключевым словам 1С+RabbitMQ или 1С+Kafka или 1С+OpenFaas — и RabbitMQ и Kafka "в 1С" давно и непринужденно используются. Потому что 1С — это не только язык, но и несколько сообществ где уже давно сделаны все возможные адаптеры и платные и бесплатные. Собственно как и в Java/C#/Python/C++/Rust/etc.


    Данная статья написана с применением расширения https://shd101wyy.github.io/markdown-preview-enhanced для Visual Studio Code — за что автору летят дополнительные лучи добра.


    Ну и в качестве финального момента хотел бы заметить, что выбор Cunfluent Inc в качестве платформы разработки Kafka-Connect — экосистемы JDK выглядит все таки странно. Не удивлюсь если их конкуренты сделают такое же, но на GoLang, NodeJS (что-нибудь типа Kafka-Beats-Hub).



    Красивые картинки в формате GraphViz я делаю при помощи хитрого проекта Docker2GraphViz — помогает поддерживать актуальный контур и техническую документацию в формате Markdown


    set CURPATH=%~dp0
    set DOCKER_DIR=%CURPATH%\dockers
    
    docker run --rm -it --name dcv -v %DOCKER_DIR%\:/input pmsipilot/docker-compose-viz render -m image --force --output-file=infra-topology.png infra.yml
    docker run --rm -it --name dcv -v %CURPATH%\:/input pmsipilot/docker-compose-viz render -m image --force --output-file=apps-topology.png applications.yml
    
    copy /b/v/y dockers\infra-topology.png content\assets\infra-topology.png
    copy /b/v/y apps-topology.png content\assets\apps-topology.png

    Similar posts

    Ads
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More

    Comments 73

      +16
      Поздравляем, вы получили достижение «Кровь из глаз!», поиспользовав все возможные варианты оформления текста внутри предложения не менее десяти раз за статью.
        +3
        Утащил в копилку… Оставлю себе вместе с другим достижениями. А по сути статьи есть что-нибудь?
        +7
        прошу прощения за глупый вопрос, но мне интересно, а в каких случаях можно обойтись без этого кафкианского зоопарка и в каких случаях без кафки ну никак не обойтись?

        типа есть критерии, вот если больше 500к запросов в секунду, то обяз кафки и без нее никак не обойтись?

        может простой кластер postgresql/mysql/mongodb полностью заменить головную боль с кафкой для 99% случаев, куда эту кафку все пытаются впихнут?
          +2
          Да, может заменить, вопрос только в железе. А вообще, если зоопарка не хочется, а событийную БД хочется — посмотрите redpanda, это как раз то про что автор пишет
          «Не удивлюсь если их конкуренты сделают такое же, но на GoLang»
            +1
            Я не стал её (`redpanda`) указывать из-за их странной политики включить `Inline WASM Transforms` — в Enterprise лицензию. Хотя SDK у них под это открыт.

            До конца не понял что они будут делать со Регистратором схем — но проект действительно интересный.
            +2

            Как по мне, так как раз примерно в 99% Кафка в проекте не нужна и можно обойтись использованием СУБД для очередей. Только при очень большом потоке персистентных (т.е. которые должны храниться на диске и их нельзя терять) событий, условно больше 10к/сек, действительно Кафка становится хотя бы теоретически полезной, если Вы готовы тратить время на ее настройку и поддержку и готовы разбираться в её «тонкостях».

              0
              Ну, не совсем. Мне кажется, оценка 99% тут слегка от балды. Все-таки, хранилища сообщений, имеющие место в условном ActiveMQ или QPID, из коробки сильно лучше для тех случаев, когда у вас очередь. Т.е. ваши 10к/сек вы с большей вероятностью получите без геморроя с настройкой.

              При этом некий условный брокер (тот же ActiveMQ) разворачивается вообще одним пинком левой ноги, и поддерка его не сложная. Сильно проще, чем СУБД, обычно. Все равно СУБД, в которую льется непрервыный приличный поток сообщений такого масштаба, придется вероятно тюнить.

              Ну т.е. соглашусь в целом, только я бы ввел в это уравнение кроме кафки и субд, как крайних случаев, еще другие брокеры сообщений, которых есть достаточно много. И они могут откусить от потребностей в кафке еще некий кусок.
            +6
            Я что-то читал читал долго упорно и потерялся — а зачем?
            Ну т.е. типовое применение — засунуть в конкретное общение двух приложений rabbitmq или kafka, зачем делать вот этого монстра, который кучу раз перезасовывает сообщения в разные очереди\сервисы?
            Как это потом поддерживать, отлаживать, как делать сквозное логирование и контроль доставки?
              +2
              Да, присоединюсь к вопросу. Я тоже этого не уловил (хотя сам в реальности имел дело с приложениями, где было более одного брокера, и даже сам такие строил). Но тут автору удалось успешно скрыть эту важную мысль за тоннами наверное интересных, но мелких деталей.
                +1
                Начну с конца — Контроль доставки и трассировка — если абстрагироваться от вопроса «Контроль для кого и трассировка для кого», а остаться только в контексте вопроса — то последние 2 года чаще всего используется www.jaegertracing.io — это у OpenFaaS подсмотрено. А вот контроль доставки на уровне брокера — это их штатная функция. Собственно в примерах кода C# получатель сознательно делает NACK. Если нужно сохранить поведение Flow с трасировкой — это чаще всего некое комплексное событие — и тогда у нас в наш монстр добавляется что-то управляющее github.com/s8sg/faas-flow — но обратите внимание: это уже и не брокер даже, а другой сервис — потоков микрофункций.

                И вообще это тема еще одной статьи — про opentelemetry.io.

                И тут мы переходим к поддержке — поддерживать и оркестировать и управлять подобным в основном приходится через те самые инженерные практики (ManageIQ как пример) и конечно ситуационные центры: Zabbix, Graphana, Graylog, ElasticBeats, прочее.

                Поэтому вопросы поддержки, трассировки я не скрыл — я про них вскользь упомянул сославшись на ITILv4, все таки тема статьи немного не про поддержку монстров… Хотя почему монстров уже мне непонятно… В действующей инфраструктуре почти всегда есть комплект софта — одним сервисом больше, одним меньше. Зато потенциал для автоматизации максимальный.
                Скорее всего вы сторонник развертывания «под задачу» — а я сторонник избыточного развертывания «до задачи». Это даже не разница это просто 2 параллельных подхода.
                  +3
                  Звучит как худший вариант преждевременной оптимизации — преждевременная архитектура.
                    +1
                    «Архитектура прямо пропорционально команде ее создающей» — это я так вольно интерпретирую закон Конвея. Преждевременная команда… По моему это что-то неизвестное.

                    Что касается преждевременности — отчасти вы правы, избыточность она же преждевременность. С другой стороны — начиная делать какой-то проект мы закладываем в него определенный потенциал «на будущее» — потому что уровень неопределённости всегда велик. Я сознательно использовал слово избыточность вместо преждевременности. Вот сделали товарищи некий государственный проект для межведомственного взаимодействия, и почему-то явно прописали RabbitMQ — а не расширяемые протоколы AMQP/Kafka/etc, и теперь формально — чтобы отмигрироваться на какой-либо другой протокол, придется делать новый продукт (а это уже другой бюджет). И вот у нас готовый «легаси» продукт — уже на старте использования.

                    И опять же — вот этот избитый штамп

                    > преждевременная оптимизация

                    Это антишаблон процесса разработки (я его знаю) — но когда мы применяем BDD/TDD — мы оптимизируем код постоянно, и нам не страшно, потому что «покрытие кода тестами и т.д.»

                    Давайте взглянем на ситуацию по другому — близко к реальности

                    Я как DevOps инженер точно знаю что разработчики читают Хабр и ходят по Хайлодам, поэтому чтобы завтра не было пожара когда они у меня попросят Кафку, КликХаус, Постре, Редис,etc- мне нужно обеспечить избыточность протоколов на уровне инфраструктуры сервисов компании


                    и соответственно

                    Я как разработчик выбираю тот протокол интеграции внутри приложения и с внешними приложениями, который мне позволит сделать задачу максимально качественно — поэтому я создаю Интерфейсы, Абстрактные классы чтобы иметь возможность быстро переключать низкоуровневые протоколы. И мне очень не хочется чтобы меня тормозили инфраструктурщики которые умеют только ODBC и HTTP


                    При моем подходе — отсутствует 2 ключевых проблемы

                    * «блокировка» разработки инфраструктурной командой
                    * «пожар» у команды инфраструктуры при поступлении новой заявки на развертывание

                    Архитектору (архитектурному комитету) в этом контексте получается еще проще — они просто начинают смотреть на интеграционные потоки между приложениями и внутри приложения, как на комплект композитных приложений и сервисов — получается удобней рисовать стрелочки и кубики. Тем более сейчас это можно делать автоматически через API различных оркестраторов.

                    Надеюсь мысль отразил.
                      +3
                      Вы упускаете один небольшой момент — за чей счёт такой банкет? Например, «когда они у меня попросят Кафку, КликХаус, Постре, Редис» вообще не возникнет пожара уже просто имея хоть что-то одно из вашего списка (хоть кафка, хоть rmq). Какой смысл иметь описанный вами «зоопарк» из дублирующих друг-друга систем, иметь кратное увеличение затрат на ops?

                      Я понимаю, если бы вы просто описали имевший место быть кейс конкретной ГИС, но ведь вы вещаете это как «подход» которой стоит рассматривать — тут я с вами не могу согласиться.

                      P.S.
                      Пожалуйста, если можно, пишите комментарии поменьше, а то мне кажется что вы просто хотите меня закидать баззвордами.
                        0
                        Ок. Буду поменьше. Хотел мысль пошырШе отразить.
                        За чей счет банкет — за счет имеющихся ресурсов. В реальности когда копнешь поглубже — оказывается что есть НЕдоутилизированное железо, недотюнинговые контура СУБД, а дальше обкладываешься всякими автоматизаторами из DevOps и нормально… если еще и мониторинг прикрутить. Последнее время с друзьями пользуемся RancherOS/ManageIQ для тестовых контуров, даже для себя (это когда мы OpenSource пилим всякий) — а там железки то уровня персональный компьютер стоящий дома у участников сообщества.
                          +2
                          Я даже оторопел от осознания того, что в вашем понимании косты владения такой системой — это сугубо стоимость железа.
                            0
                            А где я написал что это только железо? Я тоже оторопел от того что вы вынесли с моего комментария именно это.

                            вы спросили за чей счет банкет — я ответил: за счет имеющихся ресурсов. Имелось ввиду классическое — текущие люди+текущее железо и т.д. Сами же просили отвечать коротко. ;-)

                    +3
                    Скорее всего вы сторонник развертывания «под задачу» — а я сторонник избыточного развертывания «до задачи». Это даже не разница это просто 2 параллельных подхода.
                    Ну, я понимаю такой подход в военке или там авиации — безопасность, все дела. Но в обычном софте?..

                    В целом, воды у вас много, а что вы хотели показать-сказать, я так и не понял.
                    И так и не ответили на основной вопрос — Зачем?
                      +1
                      Зачем: В самом начале написано — чтобы НЕ тратить деньги на исследование — какой протокол лучше.

                      В обычном софте: ИМЕННО в обычно софте… Чтобы не иметь **ProtocolLock** это во первых, а во вторых для повторного использования данных. Сегодня событие нужно только приложению, а завтра кому-то еще.

                      К вопросу о воде: это я еще с Вами не поделился своими наработками по CloudEvents github.com/cloudevents/spec#cloudevents-documents — вот там воды приходится лить от часа до двух.
                        +3
                        Ну т.е. вместо исследования что лучше, мы просто начинаем пользоваться всеми протоколами сразу?
                        Т.е. команда должна быть компетентна сразу во всех?
                        Или команда в итоге на месте все таки вынуждена решать, что она использует?

                        Как с этим жить то?
                          +1
                          Честно говоря довольно много текста для этого вышло, при этом если бы я не знал, в чем различия, то довольно быстро бы увяз и ничего не понял. Суть то в том, что оба инструмента достаточно разные, обоим есть место в архитектурном ландшафте в зависимости от требований. А то, для каких задач каждый из них лучше применять, как мне кажется, кратко и емко расписано например тут: stackoverflow.com/questions/42151544/when-to-use-rabbitmq-over-kafka
                            +1
                            Таких сравнений тысячи — но люди все равно спрашивают. Я же предлагаю вам не сравнивать совсем инструменты/бренды — а сравнивать протоколы. По указанной же Вами ссылке есть ссылки на блог от 84Codes — где также сравниваются бренды а не протоколы.
                            Вот вы пишите — много текста — и все равно даете ссылку на сравнение Kafka-vs-RabbitMQ — а не AMQP-vs-KafkaProtocol. Почему так? Почему вы сравниваете бренды/инструменты?
                              +1
                              Kafka-vs-RabbitMQ — а не AMQP-vs-KafkaProtoco

                              А какая разница? По умолчанию говорим Rabbit, подразумеваем общение через AMQP, говорим Kafka — подразумеваем общение через KafkaProtocol. Можно всего придумать и расширить, но зачем? Если мы можем себе позволить наиболее дефолтные настройки, тем нам им в будущем легче будет поддерживать.
                                +1
                                Вот как у вас получается? RabbitMQ может MQTT/Stomp и еще много чего. И вот уже и Кафка экосистему добавляют MQTT github.com/confluentinc/kafka-mqtt-images и не только. Но вы старательно используете в глоссарии бренд — подразумевая что все в курсе чтобы там за брендом скрывается. к сожалению — не все. Дешевле в команде оперировать словом протокол, его реализацией где-то и кем-то.
                                  0
                                  Дешевле в команде оперировать словом протокол

                                  А вот не соглашусь. Специалистов понимающих детали реализации «протоколов» намного меньше, чем тех кто «знаком с брендами». Поэтому в долгосрочной перспективе быстрее и дешевле найти готового сотрудника со знанием брендов, чем потом объяснять, зачем у нас такой зоопарк «адаптеров» под пучок протоколов. Из-за теоретического «вендор лок».
                                    0
                                    Это разный подход — я остерегаюсь сотрудников и членов команды, которые оперируют брендами: это дорого выходит. Но это мой опыт и знания. У вас он другой. Это мы сейчас про ИТ подбор начнем спорить.
                                0
                                Тем не менее я и в вашей статье не увидел сравнения протоколов. Более того, нет и сравнения инструментов, приведен лишь пример, где один сервис публикует событие в рэббит, а двое других забирают, причем второй — это кафка. Почему в примере не наоборот? Что должен был показать/доказать пример?
                                  0
                                  А я не сравнивал протоколы — статья называется гибридная мультипротокольность. Пример (если вы его запустите) покажет вам что можно отдавать подписчику Кафка протокол если ему хочется, а источники оставить на AMQP 0.9 / AMQP 1.0 — что дешевле чем мигрировать всё на Кафка или все на RabbitMQ.
                                    0
                                    Теперь идея статьи стала понятна. Непонятно только зачем такой монстр, но у меня видимо просто опыта такого не было. В любом случае спасибо за разъяснения.
                                0
                                ну, человек объяснил же, что суть его «призыва» в том, чтобы вместо сравнения тулов заниматься сравнением концепций (что, очевидно, более логично, потому как тулы меняются и появляются куда чаще, нежели концепции, которым они следуют))
                                  +1
                                  И насколько хорошо здесь сравнились концепции? И какие конкретно?
                                    0
                                    Во-первых, насколько хорошо — воспрос субъективный, во-всторых, если я верно уловил, то суть статьи не в этом. А призыв имхо толковый. Многие действительно сравнивают инструменты, которые меняются каждый день.
                                      0
                                      Так-то оно может и так, но вот Рэббиту скоро 14 лет стукнет. Кафке тоже скоро десяток. Многие из тех, кто активно программирует практически всю свою профессиональную жизнь провели при жизни этих инструментов.
                        +3

                        Я испытываю сильное недоверие к обоим. Одно написано на эрланге, второе на java. Оба идут со своим волшебным миром виртуальных машин, изолированных от ОС, со своими менеджерами памяти, своими методами управления процессами, своими скедулерами и вообще, идут они со всем этим своим куда-нибудь подальше. В операционной системе надо использовать технологии этой операционной системы, соглашения этой ОС о том, что такое процесс, как он запускается и перезапускается.


                        Я как оператор крайне неодобрительно отношусь и к beam{.smp} и r /usr/bin/java.

                          +1
                          это вы на ZeroMQ так намекаете? Плюсую однозначно — в свое время меня порадовал вот такой проект habr.com/ru/post/262977
                            +1

                            Я ни на что не намекаю, я говорю, что все инфраструктурные проекты, написанные на птичьих недо-ос вызывают значительный оверхед в администрировании и очень много wtf'а при эксплуатации. Не то, чтобы segmentation fault был сильно приятнее java-трейса, но по-крайней мере видно, что именно свалилось. А то при должном везении можно получить полупустой beam.smp, который вроде бы есть, но уже более дохлый, чем живой (например, потому что epamd перезапустился и кука не подходит больше). То же касается трешинга при зациклившемся рестарте, шаренной памяти между псевдопроцессами, когда oom приходит, чешет в затылке и говорит "ага, вот этот beam — убить". И после чего вся замечательная супервизорная хрень молча отправляется на рестарт, включая невинные процессы, и т.д.


                            Короче, чужеродная система, ввинчивающася в систему со своими правилами и wtf'ами в трудных случаях. Любой бинарь на приличном языке программирования себя при этом ведёт в разы лучше. Даже некоторые интерпретируемые языки (p-семейства, например) куда более предсказуемы и управляемы (потому что там по интерпретатору на процесс и с точки зрения ОС что оно там интерпретируемое, что бинарь — поведение почти не меняется).

                              +1

                              Так можно и до bare metal дойти, а то все эти лишние функции универсальной os, универсального процессора :)
                              Но стоимость/время разработки под os на "любом нормальном языке" почти всегда выше/больше чем под jdk.

                                0

                                Вы уверены? Я, конечно, не спец по java, но по моим ощущениям, код на расте, например, писать значительно приятнее, чем на эрланге.

                                  0

                                  Java как язык решает вопрос удобства написания, jvm как vm решает вопрос совместимости одного и того же кода (в большинстве случаев) с различным api os.
                                  Про erlang только что-то слышал, не могу комментировать но у меня нет основания вам не доверять но в Rust мы точно упираемся в os и должны с ней работать, а в случае чего не можем просто накатить патч для *VM чтобы обеспечить совместимость с почти такой же но немного другой os либо должны использовать только совсем базовые функции...

                                    0

                                    у jvm есть ещё задача — бэкенд для разных языков. В посте вон Scala явно упоминается. И основная, имхо, причина писать на Java всё-таки не удобно.

                                0
                                >по-крайней мере видно, что именно свалилось
                                Э, и часто у вас падает скажем кафка? Ну и потом, можно сколько угодно не любить условно java, но покажите мне аналог хадупа? Или спарка? Есть случаи, когда они незаменимы.

                                Помнится, года три назад один чувак тут на хабре мне вещал, что будь на то божья воля большое желание, анало хадупа появится бы на .net быстро-быстро. Однакож сегодня аналога нет и не предвидится (надо было записывать и пари устроить — выиграл бы без вариантов).

                                Ну т.е. это я к чему? Как и с ОС, пользователю ообычно важно приложение, а не сама ОС, т.е. скажем Фотошоп или Автокад, так же в общем-то и тут — кафка пропускает наши терабайты — а другие нет. Поэтому на ее недостатки нам пофиг. А другим — ну каждый сам должен думать, возможно для вас ваш вывод вполне верный.
                                  +2

                                  пожалуйста, не надо инфраструктурный софт сравнивать с десктопным. На десктопе человеку нужно, чтобы "оно работало". А в инфраструктурном софте нужно, чтобы оно не только работало, но и правильно неработало. Я не работал с кафкой, но много изучал странные глюки рэббита. Поверьте мне, они более странные, чем вы себе представляете. Например, был-был рэббит и вдруг перестал. А процесс с точки зрения ОС — нет. И сокеты остались занятые. И при перезапуске случилось бобо.


                                  А посмотреть во внутрь beam.smp уже нельзя, потому что epamd уже того. (Это было до systemd с его божественным раскладыванием юнитов по cgroup'ам, которые могут снести всю ахинею за раз).


                                  Аналогичные истории я могу рассказать про java — когда визуально кажется, что java кушает 350% и ей есть ещё 1000+ процентов ядра, а на самом деле нет, потому что в jps выясняется, что внутренний тред джавы сожрал 100% cpu и больше не может.


                                  Короче, чужеродные системы. На десктопе — пожалуйста. На серверах, лучше не надо.

                                    0
                                    >пожалуйста, не надо инфраструктурный софт сравнивать с десктопным.
                                    Это почему? Для меня это верное сравнение. Вот для смеху, сколько у вас ядер в самом крупном… э, кластере? Ну так чтобы это было одно приложение, или одна база?
                                      0

                                      Видимо, вы хотели сказать, "чтобы это был один процесс", потому что самые крупные кластеры у нас в эксплуатации — ceph и swift, и поверьте, там много стоек. По процессам у нас экстрима нет, и самое толстое приложение в окрестностях моего администрирования — 16 ядер и 96 гигов памяти. Джава, увы.


                                      А, не, ещё у товарищей рядом толстый эластик есть с холодными шардами. Но я туда не лазаю. Там тоже джава, к несчастью.

                                        0
                                        Ну, мне на самом деле интересно понять, откуда такое мнение берется. Масштабы другие, или что? У меня типовой аптайм на java приложениях — месяцы, при этом часть таких приложений — скажем хадупы, включая дев стенды, где вообще каждый делает почти все что хочет — и те месяцами не перегружают (иногда). И это десятки тысяч ядер местами. А вот такое, где одна или две машинки — т.е. близкое к 16 ядрам и 96 гигам, у меня было свое на позапрошлом проекте — и там аптайм тоже был между двумя обновлениями линукса. Ну т.е. приходят линуксоиды, и говорят — тут вот redhat выкатил пачку фиксов, накатим? Ну ок, завтра прихожу с утра, пока биржа не работает московская, накатываем, рестартуем — и снова полгода. Ну т.е. откуда мнение, что вообще что-то падает «патамучто Java»?

                                        У меня вообще был единственный случай, когда java-приложение «висло» непредсказумо, и нам пришлось потратить кучу времени на диагностику — ну так то был вендор, и не было исходников (и все общение было очень медленное). И что в итоге нашли — баг и линуксном fast mutex…
                                          0
                                          Ну т.е. откуда мнение, что вообще что-то падает «патамучто Java»?

                                          ОС ничего внятного не сообщает, и вообще может не понимать, что приложение "упало". Какие ещё выводы можно сделать? )

                                            +1
                                            Ну вот у меня точно такая же нога — но не болит (с). Какие выводы? У меня просто есть повод не верить в такое, вот и все. Ибо 24 года наблюдаю это вот, и не видел никогда такого, как рассказывают. Вот про эрланг я допустим ничего не знаю — поэтому и не оспариваю. А тут у меня вокруг тысячи java приложений, без всякого преувеличения, и еще десятки тысяч я видел на других местах работы. И ничего. Ни одна поддержка никогда не сказала ни слова, вообще. Документацию прочитали — и вперед.

                                            >может не понимать, что приложение «упало».
                                            Такого не бывает. Оно выйдет с кодом возврата !=0, и возможно запишет дампы. Или просто запишет дампы. А если не запишет — то нужно просто добавить параметр при старте — тогда точно запишет (если будет куда записывать, разумеется).

                                            Ну т.е. понимаете, условный core dump проги на C++ в линуксе ничем ваще не отличается от дампов Java приложений, кроме того факта, что последние обычно проще читать. Это впрочем не значит, что ваще можно нихрена не читать документацию, отнють :) И условное приложение может вести себя непонятно, но во вполне понятных ситуациях — скажем, я как-то тупил с полчаса, почему на диск, где свободно 100 гигабайт, не пишутся логи. Ну и чего — потупил, потупил, а потом и понял, что inodes закончились. И чем это будет отличаться от того случая, если код написан на C++, кроме того факта, что его писать будет сложнее? Средства логирования, кстати, начиная с древнего log4j, у экосистемы jvm одни из лучших, или как минимум на уровне выше среднего. Средства диагностики — тоже. Ничего подобного flight recorder я просто не видел никогда и нигде.
                                              0

                                              Ну вот у меня точно такая же нога, но ходит плохо, хотя и не болит.


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

                                                0
                                                >даже нюансы настройки неочевидны
                                                Ну понятное дело. Нюансов же полно. Ну т.е. это дело надо изучать, с этим ничего поделать невозможно. Просто документацию открыть, да почитать)
                                                  0

                                                  Часть проблемы в том, что документация разрознена. В документации к конретному продукту какие-то возможные настройки могут вообще не упоминаться ("это же очевидно, что это не ответственность нашего софта, а jvm") или даваться без объяснений и направлений куда копать если что-то идёт не так.

                                                    0
                                                    Ну, это вообще типично для софта, который писали для себя, а потом выяснилось, что можно и продать — есть кому. В общем случае не лечится, кроме как наймом людей уже с опытом (хотя на самом деле опыт — он такой, я вот знаю всего пару людей, которые реально анализировали дампы памяти с нашего кластера — тупо потому, что на кластере у процесса вполне может быть 128Gb, а может и больше, а на рабочей машине всего 16, а чтобы прочитать дамп и побегать по нему, нужен или сопоставимый объем памяти, или специальные ухищрения). Ну т.е. бывает и такой опыт, специфический. Не у всех он есть, даже если общего опыта навалом.
                                                      0

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

                                                        0
                                                        Вы думаете, это ежедневное занятие? Я примерно за 24 года делал это раз 10, ну может 50. Т.е. пару раз в год, не чаще.

                                                        Предпочел бы вообще не делать, но бывает что нужно. Ну и потом, обычное простое ковыряние сводится к запуску Eclipse Memory Analyzer, который сразу показывает, что память закончилась, потому что мы создали… объектов такого то типа — и на этом все уже ясно. Так чтобы сидишь час — и ничего еще не понял, воообще не припомню (кроме описанного выше случая с багом в линуксе). Ну т.е. может 50 часов за много лет — разве это много?
                                                          0

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

                                                            0
                                                            Ну, нет. Я, было дело, чуть ли не каждый день дизассемблировал код и читал дампы, но это было еще на S/370.
                                      0

                                      "потому что в jps выясняется, что внутренний тред джавы сожрал 100% cpu и больше не может"
                                      "Другой язык" в этом случае поможет? Внутренний это системный? (В принципе реализации JVM очень сильно продвинулись лет за 10+ последних, Но это с т.з. читателя а не писателя), но ошибки бывают везде даже в os...

                                        0

                                        Тут дело не в языке, а в рантайме. Если бы java компилировалась в ELF и использовала бы системные треды, у меня к ней бы никаких претензий не было.


                                        Насчёт ошибок — дело же не в их наличии (они у всех бывают), а в том, что вместо того, чтобы фейлиться как все остальные, jvm/beam норовят фейлиться по-особенному, заставляя обращать на себя дополнительное внимание.

                                          0
                                          и использовала бы системные треды

                                          А разве в java есть какие-то другие треды?
                                          В ELF java тоже умеет, см. GraalVM, но это мало кому нужно.

                                          что внутренний тред джавы сожрал 100% cpu

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

                                              Не память, а процессор. Это был logstash, который бенчмаркали на пиковую производительность. Оказалось, udp reciever утыкается в 100% cpu и всё. Но оказалось это только внутри jtop'а, а не в обычном топе.

                                              0
                                              >использовала бы системные треды
                                              Поверьте, там именно такие. Как раз какие-то другие — редчайшая экзотика. И линуксные ограничения на них распространяются точно так же, как и на всех других. Ну еще они конечно память жрут сколько-то, так что при попытке создать их скажем сотню тысяч может выпасть ООМ, но уж у нашей поддержки это ну никогда не вызывало никаких особых проблем. Ни в одном проекте, я бы сказал.
                                      +3

                                      О, мою статью хоть кто-то прочитал. Везде есть нюансы.


                                      Кролик (RabbitMQ) хорош тем, что использует по умолчанию AMQP, который реализует несколько брокеров (те нет вендор лока). Его легко масштабировать в терминах штук/время, но плохо в терминах задержек. Также кролику очень плохо если очереди выросли, а демон упал/перезапустился (те восстановление нескольких миллионов сообщений). Последний раз мне пришлось руками парсить файлы очередей.


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


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

                                        +1
                                        Я читал. Мы в 2012 году пытались отмигрироваться с RMQ на ZeroMQ до продуктива не докатили, поэтому когда ваша статья вышла, я оставил в закладках.

                                        Зато у ZeroMQ мы подсмотрели хитрый ход развертывания RMQ… Когда — служба RabbitMQ ставится рядом (на localhost) с приложением источником — как будто это встроенный брокер внутрь приложения — а транспорта сделаны на Federation/Shovel до центрального кластера RabbitMQ. Потом — Андрей даже статью запилил по этому поводу habr.com/ru/post/422151

                                    +4

                                    Хочется отметить, что условная Кафка и условный RabbitMQ сделаны для совершенно разных задач, и одно другим не имеет смысла пытаться заменить.


                                    Условный RabbitMQ сделан для того, чтобы доставлять относительно небольшое количество событий (пусть это будет <= 5к в секунду), и обрабатывать каждое событие отдельно, с возможностью пометить каждое отдельное событие, как завершившийся с ошибкой, и которое будет возвращено обратно в очередь для повторной попытки.


                                    Условная Кафка сделана для потоковой обработки большого потока событий (условно >= 5к/сек). Поскольку обработка потоковая, то нет возможности пометить одно событие, как то, которое не удалось обработать, потому что вы просто указываете Кафке, до какого смещения вы дочитали, потому что по по факту Кафка хранит события из одной партиции в одном файле, и просто стримит содержимое оттуда — нет концепции обработки отдельных событий. Кстати говоря, в распределенной среде доставка exactly once это исключительно сложная задача, и одна Кафка здесь недостаточна.


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

                                      +2
                                      Вот кстати да, эта разница указана почти в каждом сравнении кафки и рэббита, и оно часто влияет на то, какой механизм и для чего будет прикручен в проект.
                                      А крутить сразу оба — это что-то странное. И автор так и не ответил — зачем…
                                        0
                                        Я 2 раза отвечал в комментариях, и внутри самой статьи ответил. Вариантов два — либо вы хотите услышать тот ответ который Вам понравится, а я его не даю, либо я плохо объясняю.
                                        Сейчас мне проще и дешевле согласится с тем что я плохо объясняю ;-). А вы молодец.
                                        +1
                                        а можно вопрос, вот допустим льются логи 10к в секунду (почти как зарплата у датасаентиста).
                                        А вот бизнесу оно надо оборабатывать в реалтайме эти 10к?
                                        Если не надо — тогда можно же пакетно обрабатывать по 6М в минуту используя один SQL сервак — в чем такой подход плох?
                                        и серваки сами линейно масштабируются и шардируются и в операционном управлении пара SQL серваков это ничто, по сравнению с зоопарком кафки
                                          0

                                          Я лично никогда ни то ни другое не использовал, и использовал только обычные СУБД, ClickHouse и scribe / lsd, так что совершенно точно RabbitMQ и Kafka мир не ограничивается :).

                                            +1
                                            я больше спец по базам, а не кафке и скорее всего мое мнение необъективное, но меня напрягает ситуация, когда люди не выжав даже 20% от возможностей базы начинают лепить кафку.
                                              0

                                              Полностью согласен.

                                            0

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

                                          +2
                                          Статья написана нейросетью?
                                            +1

                                            Ощущение, что Kafka, простите KafkaProtocol рассматривается как брокер событий. Но делается это без уважения. К её фичам по хранению логов событий, возможности перечитать все события новым клиентом с начала времён. Как тут RabbitMQ, простите AMQP себя поведёт?


                                            по открытым протоколам… Apache Kafka не ниже версии 23

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

                                              0
                                              Хм. Не было такого замечено (я про сокрытие факта единственной реализации). Имеется ввиду что указание протокола в ТЗ позволяет участнику выбрать: будет он брать Confluent Kafka или Apache Kafka.

                                            Only users with full accounts can post comments. Log in, please.