7 причин, почему интеграцию необходимо строить на очередях. Практика RabbitMQ. Отказ от Zato ESB и OData в 1С

Petro Bazeliuk —  Март 18, 2016 — 8 комментариев

Этот набросок является продолжение предыдущей статьи 7 причин, почему интеграция стала приятной. Не упускайте ряд потрясающих возможностей. В большей части это описание боли через которую пришлось пройти на практике, используя сервисную шину данных Zato ESB и OData протокол совместно с «1С:Предприятие 8». 

Практические минусы Open Data Protocol

В 1С Предприятие 8.3.5.1068 появилась поддержка автоматического REST-сервиса. Теперь платформа может автоматически формировать REST интерфейс для всего прикладного решения.

Это был глоток свежего воздуха, все данные как на ладони бери и получай. Конечно, в скором времени появились простые и небольшие сервисы и работали они стабильно как часы. Соответственно гений инженерной мысли думает вот она: «серебряная пуля». Что ж, в порыве эйфории, один глобальный проект решено было выполнить используя: Zato ESB (что же это?) и использовать REST интерфейс OData «1С:Предприятие 8» для обмена между двумя большими системами.

Проблемы связанные с Open Data Protocol

Для реализации проекта на стороне Zato ESB были нанята команда программистов питонщиков. Основной задачей команды было брать данные из «1С:Предприятие 8» по протоколу OData, а так же получать данные при помощи фоновых заданий «1С:Предприятие 8», которые, в свою очередь, передавали изменения данных необходимых для сторонней системы. На этапе технического задания все выглядело прозрачно, но во время реализации возникли проблемы:

  • работа с большими таблицами (некоторые таблицы имели более 100 млн. записей). Получить срез данных было очень проблематично, что часто вызывало падение всех служб 1С;
  • получение данных в несколько потоков. Соединения бывало, часто, зависали и лицензии заканчивались без видимой на то причины, спасал только рестарт службы «1С:Предприятие 8». Забавно было видеть несколько тысяч соединений, которые нельзя удалить;
  • танцы с бубнами и велосипедами, чтобы гарантировать доставку сообщений;
  • так как обмен работал в две стороны, возникла проблема в контроле логики и верности создания данных в «1С:Предприятие 8»;
  • при изменении бизнес-процесса одной системе, приводил к необходимости внесения изменений в Zato ESB — в итоге получилась очень большая связность;
  • команда питонщиков, по сути, реализовывала буферные копии функционала 1С конфигурации — на лицо дублирование кода;
  • ребятам питонщикам пришлось учить платформу «1С:Предприятие 8», что бы понимать как с этим работать;
  • ошибки в самом протоколе OData, что заставляло нас использовать только вышедшие обновления платформы «1С:Предприятие 8» с новой порцией ошибок, уже не связанных с OData.

Проблемы связанные с Zato ESB

  • дорогие программисты, которым пришлось постигать азы платформы 1С;
  • ограничиваемся только одним языком программирования для выполнения обменов между системами;
  • в промышленных масштабах еще рано использовать, если, конечно, у вас много лишних серверов — можно попробовать на свой страх и риск;
  • иногда сервис падал без видимой причины и докопаться до «почему?» не удалось.

Проект сейчас в режиме «заморожен» и чувствую, что вскоре будет полностью закрыт, в связи с техническими причинами описанными выше.

7 причин, почему интеграцию необходимо строить на очередях

На данном этапе были переосмыслены все ошибки, было принято решение интеграцию строить на очередях, пока видны только одни плюсы, недостатки незаметны:

  1. используя очереди RabbitMQ, мы не ограничиваем себя одним языком программирования. Мы можем использовать, в большинстве случаев, родные языки систем которые интегрируются для отправки и приема сообщений;
  2. для гарантии доставки, нам не нужно доставать бубны и велосипеды, если сообщение не может быть положено в очередь, то и транзакция будет безболезненно отменена;
  3. интеграция одной системы к многим и наоборот выполняется одной единственной настройкой роутинга в RabbitMQ;
  4. простота формата сообщений, это бинарные данные — мы используем JSON, который переводится в бинарный формат;
  5. при высокой нагрузке, на довольно слабом виртуальном сервере, в очередь были доставлены все сообщения;
  6. каждый елемент системы не связан с другими елементами другой системы и бизнес-логика не дублируется, контроль целостности данных проверяется в едином месте в той системе для которой эти данные предназначены;
  7. множество типов очередей, даже такие что позволяют выполнять remote procedure call, но нужно стараться что бы системы были минимально связаны, бизнес-логика в «1С:Предприятие 8», а рабочие места, например, это мобильное приложение или веб-сайт.

Передача сообщения из  «1С:Предприятие 8» в RabbitMQ

Для реализации этого механизма было принято решение отказаться от веб-сервиса 1С в пользу NativeAPI компоненты, так как планируется передавать большие объемы данных. Весь инструментарий, который понадобится:

Исходный код, компоненты:

using System;
using System.Text;
using RabbitMQ.Client;

namespace _1CV8Publisher
{
    public class V8Publisher
    {
        public string UserName { get; set; }
        public string Password { get; set; }
        public string HostName { get; set; }  

        public string Exchange { get; set; }
        public string RoutingKey { get; set; }

        public string SengMessage(string message)
        {
            try
            {
                var factory = new ConnectionFactory()
                {
                    HostName = HostName,
                    UserName = UserName,
                    Password = Password
                };
                using (var connection = factory.CreateConnection())
                {
                    using (var channel = connection.CreateModel())
                    {
                        var body = Encoding.UTF8.GetBytes(message);
                        channel.BasicPublish(exchange: Exchange, 
                                            routingKey: RoutingKey,
                                            basicProperties: null,
                                            body: body);
                    }
                }
            }
            catch (Exception e)
            {
                return e.ToString();
            }
           
            return "Data successfully delivered!";
        }       
    }
}

С помощью NuGet console выполняем команду «install-package RabbitMQ.Client». В проекте должны появится необходимые ссылки на RabbitMQ.Client. Компилируем и компонента готова.

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

#Область ПрограммныйИнтерфейс

Функция ПолучитьОбъектКласса1CV8Publisher() Экспорт
	
	ПодключитьВнешнююКомпоненту("ОбщийМакет.NETLoader", "NET", ТипВнешнейКомпоненты.Native);
	
	Попытка
		Компонента = Новый("AddIn.NET.NETLoader");
	Исключение
		ТекстСообщения = НСтр("ru = 'Ошибка при подключении компоненты ""AddIn.NET.NETLoader"": %ТекстСообщения%'");
		ТекстСообщения = СтрЗаменить(ТекстСообщения, "%ТекстСообщения%", ОписаниеОшибки());
		ЗаписьЖурналаРегистрации("AddIn.NET.NETLoader", 
						УровеньЖурналаРегистрации.Ошибка, 
							,
							,
							ТекстСообщения,
							);
		Возврат Неопределено;
	КонецПопытки;
	
	КаталогКомпонент = КаталогВременныхФайлов() + Новый УникальныйИдентификатор;
	СоздатьКаталог(КаталогКомпонент);
	ПолучитьОбщийМакет("RabbitMQ").Записать(КаталогКомпонент + "\RabbitMQ.Client.dll");
	ПолучитьОбщийМакет("V8Publisher").Записать(КаталогКомпонент + "\1CV8Publisher.dll");
	
	Попытка		
		Компонента.CreateObject(КаталогКомпонент, "1CV8Publisher", "_1CV8Publisher.V8Publisher", , Истина);
	Исключение
		ТекстОшибки = Компонента.GetLastError();
		Если ПустаяСтрока(ТекстОшибки) Тогда
			ТекстОшибки = ОписаниеОшибки();
		КонецЕсли;
		ТекстСообщения = НСтр("ru = 'Ошибка при вызове метода ""CreateObject"": %ТекстОшибки%'");
		ТекстСообщения = СтрЗаменить(ТекстСообщения, "%ТекстОшибки%", ТекстОшибки);
		ЗаписьЖурналаРегистрации("1CV8Publisher", 
						УровеньЖурналаРегистрации.Ошибка, 
							,
							,
							ТекстСообщения,
							);
		Возврат Неопределено;
	КонецПопытки;
	
	Компонента.HostName = "hostname";
	Компонента.UserName = "admin";
	Компонента.Password = "admin";
	Возврат Компонента;	
КонецФункции // ПолучитьОбъектКласса1CV8Publisher()

Функция ВыполнитьОтправкуДанныхВОчередь(Компонента, Exchange, RoutingKey, Message) Экспорт
	Компонента.Exchange = Exchange;
	Компонента.RoutingKey = RoutingKey;	
	Результат = Компонента.SengMessage(Message);
	Если Результат <> "Data delivered successfully!" Тогда
		ВызватьИсключение Результат; 	
	КонецЕсли;
	Возврат Результат;
КонецФункции // ВыполнитьОтправкуДанныхВОчередь()

#КонецОбласти

Теперь создадим очереди в RabbitMQ (связь систем 1 к 1, для связей 1 к 2 и больше необходимо создать дополнительные очереди которые будут заполняется с помощью routing):
1-1

Создадим exchanges, в которых укажем routing:exch-1exch-2

ВыполнитьОтправкуДанныхВОчередь(Компонента, "users", "users.event.create", Message);

Соответственно, после выполнения данной строки кода, в очередь users-create-queue упадут данные из параметра Message. Обратите внимание, нигде не указывается в какую очередь отправляются данные, а указывается exchange и routing key. Для обмена с двумя системами просто нужно добавить новую очередь, которая предназначена для системы №2 и в exchange добавить тот же routing key, но указать очередь №2. Вот так осуществляется подписка на простые события.

Послесловие

Этот подход работает лучше чем Zato ESB + OData. Время рассудит, станет ли это — «серебряной пулей» или простой рабочей лошадкой для специфических задач интеграции.

Petro Bazeliuk

Записи

Опыт работы с «1С:Предприятие 8» — более 10 лет, за это время реализовано 30 успешных проектов по итеративным методологиям Scrum и Kanban. Оптимальные решения для высоконагруженных ИБ с онлайном от 400 человек. Занимаюсь продвижением в массы системы контроля версий — git и методики git-flow, TDD, BDD, а также проработкой паттерна минимальной модификации конфигурации и внесением изменений без обновления базы данных. Время от времени участвую в проекте xUnitFor1C.

8 комментариев to 7 причин, почему интеграцию необходимо строить на очередях. Практика RabbitMQ. Отказ от Zato ESB и OData в 1С

  1. 

    Можно поподробнее про компиляцию RabbitMQ.Client.dll? Что для этого требуется? Есть ли готовая либа в сети?

    Нравится

  2. 

    Здравствуйте
    клиент 1С падает на этой строке:
    ПолучитьОбщийМакет(«RabbitMQ»).Записать(КаталогКомпонент + «\RabbitMQ.Client.dll»);

    RabbitMQ — нужно завести в макетах?

    Нравится

Trackbacks and Pingbacks:

  1. Интеграция POS-терминалов Ingenico iCT220, iCT250 («Приватбанк») « Bazeliuk Petro - Май 29, 2017

    […] для больше надежности присутствует возможность подключения сервиса очередей RabbitMQ. […]

    Нравится

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход /  Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход /  Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход /  Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход /  Изменить )

w

Connecting to %s