Привет Хабр!

Меня зовут Дмитрий Гаврин, я заместитель директора департамента «Цифровые решения» компании «Диасофт».

Есть тип совещаний, которые я узнаю с первой секунды по интонации приглашения. Когда директор проекта пишет «зайди, поговорим по цифрам» - это не про то, что кто-то перевыполнил план. Это про интеграцию. Почти всегда про нее.

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

Причины всегда разные, но из одного и того же набора. Смежники прислали спецификацию после того, как мы уже написали половину кода. Клиент добавил одно поле в объект - и это «одно поле» потребовало недели переработки. Западный вендор что-то тихо изменил в своем API. Или - классика - в самом начале никто не спросил, как именно одна система должна реагировать на недоступность другой, и это выяснилось в проде.

Я участвовал в одной дискуссии, где коллеги рассуждали: а вот если бы заказчик принял единый корпоративный стандарт интеграции внутри компании, было бы все иначе. Я их, конечно, расстроил. Этого не бывает. Никогда. В любом достаточно взрослом предприятии живет зоопарк: одна система на SOAP из 2008 года, рядом REST-сервис, написанный три года назад другой командой, и где-то в углу что-то, что умеет только читать файлы из SFTP-папки. Это не недостаток организации - это физика роста любой IT-инфраструктуры. Со стандартами или без.

Параллельно с зоопарком систем существует зоопарк решений внутри самой команды разработки. За годы в Диасофте я видел не меньше десяти разных реализаций одного и того же компонента по работе с файлами. Все от разных разработчиков, все написаны с нуля, и почти ни одна не учитывала полный набор крайних случаев. В Windows файл при чтении блокируется - если соседний поток попытается его подхватить в тот же момент, получишь ошибку. В Unix логика другая, но там свои нюансы с правами. При перезапуске сервиса необработанное сообщение может уйти повторно - и к утру в системе тысячи дублей. Не потому что разработчики плохие. Просто каждый раз задача звучала как «нам нужно считать файл и передать данные», а не «нам нужен надежный компонент, который знает обо всех граничных случаях». И каждый раз это был новый велосипед - чуть другой формы.

После 2022 года ко всему этому добавился еще один пласт. Oracle Service Bus, IBM Integration Bus, MuleSoft - все это либо ушло с рынка, либо оказалось под угрозой отключения. Казалось бы, вот он момент: все начнут переписывать интеграционные решения на отечественное. Но этого массово не произошло. И я понимаю почему. Когда интеграция собиралась десятилетиями, риск ее переписывания не меньше, чем риск того, что она однажды перестанет работать на иностранной платформе. Страх «сломаем то, что работает» оказался сильнее страха «а вдруг отключат». Это не трусость - это вполне рациональное поведение людей, которые отвечают за боевые системы.

Мы понимали все это по собственному опыту задолго до 2022 года. И в какой-то момент перестали воспринимать происходящее как данность, с которой надо просто мириться. Выписали на бумажку все проблемы, с которыми сталкивались в проектах раз за разом, и задали себе неудобный вопрос: почему каждый следующий интеграционный проект начинается так, как будто предыдущих не было? Почему накопленный опыт не работает как инструмент, а каждый раз остается только в головах конкретных людей?

Ответ оказался простым и неприятным одновременно: потому что не было платформы, которая бы этот опыт кодифицировала. Не в документах, не в регламентах - а непосредственно в инструменте, которым работает разработчик.

Так начался проект Digital Q.Integration.

Точка-точка, шина и почему обе крайности больно

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

Самый первый и самый естественный подход - прямые соединения между системами, то самое point-to-point. Есть система A и система B, есть два разработчика, есть задача передать данные. Почему бы просто не написать? Быстро, дешево, понятно. Никакой инфраструктуры. И это действительно работает - пока компания маленькая, пока систем три, пока все разработчики сидят в одном кабинете и помнят, что они писали.

Проблема начинается не тогда, когда добавляется четвертая система, и даже не тогда, когда добавляется десятая. Проблема начинается, когда кто-то из тех разработчиков уходит. Или когда одна из систем меняет формат данных. Оказывается, что это «простое» соединение между A и B завязано еще на C, потому что там была какая-то бизнес-логика, которую удобнее было положить именно туда. Схема интеграций к этому моменту похожа на схему московского метро после добавления МЦД - формально все связано, но объяснить, как именно добраться из точки X в точку Y, уже требует мануала.

Количество связей растет квадратично. При десяти системах это уже потенциально 45 пар. При двадцати - 190. 

Следующий эволюционный шаг - централизованная шина, ESB. Идея красивая: не соединяем системы друг с другом напрямую, а подключаем каждую к одной центральной точке. Вся логика трансформации, маршрутизации, обработки ошибок - там. Звучит как решение. И на протяжении примерно десяти лет это действительно было индустриальным стандартом - WebSphere, TIBCO, Oracle Service Bus, позже MuleSoft. Серьезные продукты, серьезные деньги, серьезные команды внедрения.

Мы работали с ESB в проектах. И мы видели, как эта красивая идея начинает трещать по швам, когда предприятие вырастает до определенного масштаба. Централизованная шина - это единая точка отказа. Когда она падает, падает все. Когда ее нужно масштабировать, это вертикальное масштабирование: покупай более мощный сервер. А еще - и это, пожалуй, самое болезненное - классический ESB со временем превращается в монолит, куда стекается вся прикладная логика. Интеграция между A и B? Окей, положим правило трансформации на шину. А вот здесь нужна маленькая бизнес-проверка? Тоже на шину, куда же еще. Через несколько лет шина знает о бизнесе компании больше, чем любая из систем, которые к ней подключены. Разобраться в этом и что-то изменить - отдельная проблема.

Ну и 2022 год поставил жирную точку в истории с западными ESB-платформами. Независимо от того, насколько хорошо они работали.

Мы долго думали над тем, что именно нас не устраивает в обоих подходах, и сформулировали для себя следующее. Point-to-point плох тем, что не масштабируется и не управляется. ESB плох тем, что единая точка отказа и единая точка сложности. Что если взять лучшее из обоих? Отдельные сервисы - как в point-to-point, без централизованной бизнес-логики. Но с общим транспортом, общим мониторингом, общими инструментами разработки - как в ESB.

Так появилась концепция, которую мы назвали «умные сервисы, надежные каналы». Для каждой интегрируемой системы создается отдельный микросервис-адаптер, который содержит ровно ту логику, которая нужна для взаимодействия с этой системой - и ничего лишнего. Адаптеры общаются через транспортный уровень, который отвечает за доставку, надежность и очередность. Никакой централизованной точки отказа - если один адаптер падает, остальные продолжают работать. Масштабировать можно каждый сервис независимо: если система-получатель захлебывается под нагрузкой, мы поднимаем дополнительную реплику именно ее адаптера, не трогая все остальное.

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

Один вопрос при этом оставался открытым: как сделать так, чтобы «умные адаптеры» было легко писать? Потому что иначе мы просто перекладываем сложность из одного места в другое. Разработчик вместо того, чтобы разбираться в конфигурации ESB, будет писать кастомный Java-код с нуля - и мы возвращаемся к тем же десяти разным реализациям файлового компонента.

Apache Camel, 300 компонентов и честный разговор про low-code

Когда мы решали, на чем строить исполнительный движок, долго не колебались. Apache Camel - это open source фреймворк, которому уже больше пятнадцати лет, и за это время он собрал в себе, пожалуй, самую полную библиотеку интеграционных паттернов из всего, что существует в природе. Более 300 компонентов из коробки: HTTP, JMS, Kafka, AMQP, SFTP, SQL, SOAP, REST, работа с файлами, очередями, топиками, облачными сервисами - практически все, с чем разработчик встречается в реальных проектах, уже описано, протестировано и поддерживается сообществом. Camel интегрируется с Spring, Quarkus, MicroProfile - то есть встраивается в любой современный микросервис без боли.

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

Теперь про DSL. Camel позволяет описывать интеграционные маршруты на своем Domain Specific Language - по сути, это набор конструкций, которые описывают, откуда пришло сообщение, что с ним надо сделать и куда отправить. Выглядит как код, читается почти как текст. Но разработчики в проектах - люди с разным уровнем погружения, и не у всех есть время разбираться в синтаксисе Camel DSL, когда им нужно просто передать данные из одной системы в другую.

Поэтому мы сделали визуальный дизайнер интеграционных потоков. Разработчик видит перед собой схему: откуда данные приходят, через какие компоненты проходят, куда уходят. Каждый шаг - это кубик на холсте с настраиваемыми параметрами. Источник - Kafka-топик, значит нужно указать bootstrap servers, topic name, group id. Трансформация - выбираешь нужный паттерн из библиотеки. Назначение - очередь Artemis, REST-endpoint, файл, база данных - на выбор. Все это собирается визуально, без написания кода.

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

Это то место, где я должен сказать честную вещь про low-code, потому что на Хабре за красивые презентации или любовь к «low-code» принято спрашивать.

Low-code не значит «без кода вообще». Это значит, что типичные задачи решаются без кода - или с минимальным его количеством. Когда нужно передать данные из Kafka в REST-сервис с трансформацией формата - это собирается кубиками. Когда нужно добавить новое поле в существующий поток - открываешь дизайнер, добавляешь маппинг, публикуешь. Аналитик, который участвовал в этом разговоре, мог бы сказать: «ну так это же просто, что тут такого». Именно. В этом и смысл - сделать простые вещи действительно простыми.

Но граница есть. Если нужна нестандартная бизнес-логика, специфическая обработка, компонент для работы с какой-то экзотической системой, которой нет в стандартной библиотеке - разработчик пишет компонент на Java. Компонент регистрируется в дизайнере и становится таким же кубиком, как и все остальные. То есть low-code расширяется до hard-code там, где это нужно, а не останавливается перед стеной «это уже за пределами платформы». Это важно: у нас нет ограничений по функциональности - есть только вопрос, нужно ли писать код или достаточно настроить готовое.

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

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

Гарантированная доставка: что это на самом деле значит

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

Разница между интеграцией в финансовой системе и, скажем, стримингом видео в том, что пропущенный кадр в Netflix никто не заметит. Но если из одной системы в другую не дошло сообщение о погашении кредита - это уже не технический инцидент, это прямые потери для клиента и для банка. Интеграция в финансовом секторе - это не «передай данные», это «гарантируй, что данные дошли, и докажи это».

Что конкретно входит в понятие гарантированной доставки в нашей платформе.

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

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

Третье - подтверждения. Это как заказное письмо с уведомлением о вручении: мы отправили, получатель подтвердил, что принял. Если подтверждение не пришло - брокер знает, что нужно повторить попытку. Без этого механизма «отправил» и «дошло» - не одно и то же.

Четвертое - политики повторной доставки. Система-получатель может быть недоступна временно, или отвечать с ошибкой, или просто тормозить. Вместо того чтобы программировать логику «попробуй еще три раза с интервалом в минуту» вручную в каждом адаптере, это настраивается декларативно: сколько попыток, какой интервал между ними, нужна ли экспоненциальная задержка. Причем это работает в обе стороны - не только «долби получателя», но и «не завали его запросами, если он еле живой».

Пятое - Dead Letter Queue. Если после всех попыток сообщение все равно не доставлено, оно перемещается в отдельную очередь «мертвых писем». Там оно хранится, его можно просмотреть, проанализировать причину и - самое важное - безопасно повторить доставку вручную, когда проблема устранена. Это не просто техническая деталь: без DLQ администратор вынужден либо молиться, либо лезть напрямую в брокер и делать что-то руками в продакшне.

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

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

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

После этого мы переосмыслили подход к чтению: одна заявка - один поток, всегда, с сохранением порядка. И идентификация дублей по уникальному ID сообщения. Казалось бы, очевидные вещи. Но именно такие «очевидные вещи» и есть то, что должно быть зашито в платформу по умолчанию - а не открываться каждый раз заново в каждом проекте.

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

Отдельная история - эксплуатационный инструментарий. В open source брокерах, которые мы анализировали, интерфейс управления очередями выглядит примерно так: есть очередь, есть две кнопки - «удалить очередь» и «очистить очередь». Давать такие права прикладному администратору в банке из топ-5 - нереально. Мы спроектировали ролевую модель: есть администраторы с полными правами и есть прикладные администраторы, которые могут просматривать очереди, перемещать сообщения, повторно отправлять - но не могут случайно уничтожить данные одной кнопкой. Это звучит как мелочь, но именно такие мелочи определяют, может ли платформа работать в боевом контуре крупного финансового учреждения или остается лабораторным инструментом.

Цифры, импортозамещение и один честный разговор про миграцию

Когда мы показываем платформу потенциальным клиентам, рано или поздно звучит вопрос про производительность. Это правильный вопрос, и мы к нему готовились заранее - не в смысле «придумали красивый ответ», а в смысле провели нормальное нагрузочное тестирование с открытой методикой.

Методика опубликована на нашем сайте, отчет доступен для скачивания - это принципиальная позиция. Мы говорим клиентам: хотите - повторите тест сами на своей инфраструктуре. Никаких «звездочек» в духе «результаты получены в специально подготовленных условиях на сервере, которого нет в продаже». Тестовый стенд описан, конфигурация указана, сообщения были по 2 килобайта.

Результаты получились такие. Сначала тестировали скорость самого брокера в чистом виде - без трансформаций, без обработки: отправили сообщение в очередь, забрали из очереди. Конфигурация намеренно скромная: Intel Celeron 2.4 GHz, один поток отправителя, один поток получателя, один узел. Брокер держит 2 000 сообщений в секунду. Это важная точка отсчета: транспортный уровень сам по себе не является узким местом.

Следующий шаг - тестирование полноценного интеграционного потока, разработанного на Q.Integration: с трансформациями форматов сообщений, прокидыванием через несколько очередей и комплексной обработкой на каждом шаге. Конфигурация: одна реплика брокера, 4 ядра, 4 гигабайта оперативной памяти, сообщения по 2 килобайта. Пиковая нагрузка - 4 000 сообщений в секунду. При добавлении второй реплики, то есть при простейшем горизонтальном масштабировании, цифра удваивается до 8 000. Это не линейная зависимость в общем случае, но на двух репликах она сохраняется хорошо - и это важный показатель того, что архитектура реально масштабируется, а не просто декларирует такую возможность. Отдельно тестировалась стабильность: 2 500 сообщений в секунду непрерывно на протяжении 10 часов без деградации.

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

Как я уже писал выше, уход западных вендоров не вызвал волны массовых миграций. Причина понятна: переписать интеграционное решение, которое строилось десятилетиями, - это риск, сопоставимый с риском от самого факта использования иностранной платформы. Многие компании выбирают стратегию «работает - не трогай» и живут с этим. Это их право.

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

Дело в том, что Apache Camel - это не изолированный инструмент. Вокруг него существует целая экосистема: Apache ServiceMix, Red Hat Fuse, Talend ESB - все они в разное время использовали Camel как исполнительный движок. Это значит, что интеграционные маршруты, написанные на этих платформах, технически близки к тому, что работает под капотом нашего решения. Не идентичны, но близки - и это создает возможность для конвертации, которая значительно дешевле, чем написание с нуля.

У нас есть реальный опыт такой конвертации - с Talend на Digital Q.Integration. Клиент не переписывал интеграционное решение, оно переносилось. За счет общей экосистемы Apache это удалось сделать значительно быстрее, чем если бы исходной платформой был, например, Oracle Service Bus. Клиент при этом непубличный - это внутренняя структура одного из крупных банков, они работают в закрытом контуре и не делают таких вещей референс-кейсами. Но факт остается фактом: конвертация возможна, и мы ее делали.

С Oracle Service Bus или IBM Integration Bus история сложнее - там другая экосистема, прямой конвертации нет, и это надо проговорить честно. Там речь идет о переносе с переписыванием логики, а не об автоматической миграции. Это дороже и дольше, но при наличии силы воли - выполнимо.

Отдельно стоит сказать про лицензирование, потому что это напрямую влияет на то, как клиент вообще принимает решение о внедрении. Мы лицензируем платформу по ядрам процессора. Это значит, что клиент может начать с одного ядра - и получит доступ ко всей функциональности платформы без каких-либо ограничений по возможностям. Ограничение только по вычислительной мощности. Хочешь попробовать на одной интеграции - пожалуйста, это не будет стоить как enterprise-лицензия на весь зоопарк. Мы готовим trial-версию для самостоятельного скачивания и установки - чтобы до принятия любых коммерческих решений можно было просто пощупать руками.

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

Что получилось и о чем стоит поговорить

Я начал эту статью с совещаний про превышение бюджета. Хочу закончить честным ответом на вопрос: стало ли лучше после того, как у нас появилась собственная платформа?

Да, стало. Но не в том смысле, что интеграция перестала быть сложной. Она по-прежнему сложная. Клиенты все еще меняют спецификации в середине проекта, смежники все еще присылают «финальную» версию API после того, как мы уже написали половину адаптеров, а требования к надежности в финансовом секторе никуда не делись. Это данность, и платформа ее не отменяет.

Но она меняет то, как мы на эту данность реагируем. Когда клиент говорит «добавьте поле», это больше не недельная история с аналитиком, разработчиком, тестировщиком и циклом релиза. Открываем дизайнер, добавляем маппинг, публикуем. Когда нефункциональное требование возникает постфактум - «а сделайте так, чтобы при недоступности системы сообщения копились и потом доходили» - это не переработка архитектуры. Это настройка политики в брокере. Когда в три часа ночи сообщения начинают падать в DLQ, дежурный администратор видит это в мониторинге, а не узнает утром от клиента.

Это и есть та самая экономия на нефункциональных требованиях, ради которой все затевалось. Прикладная логика - «передай вот эти поля из системы A в систему B» - это процентов двадцать от реального объема интеграционной задачи. Остальные восемьдесят - это надежность, эксплуатация, изменения, мониторинг, обработка исключений. Именно эти восемьдесят процентов платформа закрывает из коробки.

Что еще предстоит сделать - тоже скажу честно, потому что статья не пресс-релиз про продукт, а рассказ про наш опыт. Консоль администрирования брокера, которую я описывал в части про гарантированную доставку, появилась в третьем квартале 2025 года. Коннектор к SAP и функционал работы с WSDL/WADL - в четвертом. Файловый коннектор с нормальной обработкой всех граничных случаев - тот самый, про который я рассказывал в самом начале, - тоже теперь есть, один, стандартный, со всеми нюансами платформ под капотом. Список того, чего еще нет, у нас тоже имеется, и он честный.

Платформа внесена в реестр отечественного ПО - реестровая запись №22375 от апреля 2024 года. В рейтинге ESB-решений 2025 года по версии CNews мы заняли первое место, что приятно, но я бы не делал из этого главный аргумент. Рейтинги - это срез на момент оценки, а не гарантия качества в вашем конкретном проекте.

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

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