Сейчас работаю над проектом интеграции вновь внедряемой централизованной бизнес-системы с другими системами, установленными в филиалах заказчика. При этом основная задача заключается в том, чтобы синхронизировать данные в филиалах и центре с помощью сервисной шины предприятия (ESB), реализованной на платформе Oracle Service Bus. Мы смогли обеспечить передачу с гарантированной доставкой боле 5 000 000 сообщений в сутки. В данной статье хочу рассказать о том, как это было сделано.
Нам необходимо передавать изменения данных из одной системы (системы-источника) в другую - систему-приемник. Данные должны передаваться сразу, а не с помощью пакетной обработки. Соответственно, нужно каким-то образом захватывать события об изменении данных и публиковать их для сервисной шины. Хорошо зарекомендовал себя следующий паттерн: при изменении данных пользователем с помощью триггера в БД системы-источника формируется событие, которое записывается в специальную таблицу. У события есть идентификатор, признак типа - какая именно сущность была создана или изменена, тип операции: создание, изменение или удаление, статус: новое, на обработке, обработанное успешно или обработанное с ошибкой. По идентификатору события мы с помощью соответствующего типу сущности представлению можем получить актуальные на момент обработки события данные. Сервисная шина последовательным опросом таблицы событий (по-другому это называется "полинг") считывает порцию измененных данных, затем для каждого считанного события обращается к соответствующему представлению и получает данные. Данные трансформируются в канонический формат шины, при этом на одну считанную запись может быть сформировано от нуля до пяти сообщений. Сообщения записываются в JMS-очередь, а записям в таблице событий проставляется статус "на обработке". Другой компонент адаптера - прокси-сервис, использующий транспорт JMS, считывает сообщения в каноническом формате из очереди, преобразует их в формат системы-приемника и вызывает веб-сервис, предоставляемый данной системой. Адаптер ждет окончания работы сервиса, после чего получает статус обработки сообщения и записывает его в специальную очередь ответов. Статус считывается шиной из очереди ответов и обновляется в таблице событий системы-источника.
На диаграмме UML данный процесс будет выглядеть следующим образом:
Стоит заметить, что с одной стороны события считываются из базы порциями, по 120 событий за один раз. Таким образом 5 000 000 событий в сутки это 41 600 транзакций. С другой стороны каждая запись раскладывается на от нуля до пяти сообщений, в среднем примем два. Каждое такое сообщение должно быть передано в систему-приемник, получается 10 000 000 транзакций. После этого для каждого события необходимо обновить статус - 5 000 000 транзакций. При этом все транзакции распределенные, т.к. в них участвует по меньшей мере два ресурса: база - очередь или очередь - очередь. Итого получается, что производительность системы должна быть не меньше 180 транзакций в секунду. Это конечно не то, что пафосно называют словом HighLoad, но уже возможно всего в одном - двух порядках от него.
Постановка задачи
Нам необходимо передавать изменения данных из одной системы (системы-источника) в другую - систему-приемник. Данные должны передаваться сразу, а не с помощью пакетной обработки. Соответственно, нужно каким-то образом захватывать события об изменении данных и публиковать их для сервисной шины. Хорошо зарекомендовал себя следующий паттерн: при изменении данных пользователем с помощью триггера в БД системы-источника формируется событие, которое записывается в специальную таблицу. У события есть идентификатор, признак типа - какая именно сущность была создана или изменена, тип операции: создание, изменение или удаление, статус: новое, на обработке, обработанное успешно или обработанное с ошибкой. По идентификатору события мы с помощью соответствующего типу сущности представлению можем получить актуальные на момент обработки события данные. Сервисная шина последовательным опросом таблицы событий (по-другому это называется "полинг") считывает порцию измененных данных, затем для каждого считанного события обращается к соответствующему представлению и получает данные. Данные трансформируются в канонический формат шины, при этом на одну считанную запись может быть сформировано от нуля до пяти сообщений. Сообщения записываются в JMS-очередь, а записям в таблице событий проставляется статус "на обработке". Другой компонент адаптера - прокси-сервис, использующий транспорт JMS, считывает сообщения в каноническом формате из очереди, преобразует их в формат системы-приемника и вызывает веб-сервис, предоставляемый данной системой. Адаптер ждет окончания работы сервиса, после чего получает статус обработки сообщения и записывает его в специальную очередь ответов. Статус считывается шиной из очереди ответов и обновляется в таблице событий системы-источника.
На диаграмме UML данный процесс будет выглядеть следующим образом:
Стоит заметить, что с одной стороны события считываются из базы порциями, по 120 событий за один раз. Таким образом 5 000 000 событий в сутки это 41 600 транзакций. С другой стороны каждая запись раскладывается на от нуля до пяти сообщений, в среднем примем два. Каждое такое сообщение должно быть передано в систему-приемник, получается 10 000 000 транзакций. После этого для каждого события необходимо обновить статус - 5 000 000 транзакций. При этом все транзакции распределенные, т.к. в них участвует по меньшей мере два ресурса: база - очередь или очередь - очередь. Итого получается, что производительность системы должна быть не меньше 180 транзакций в секунду. Это конечно не то, что пафосно называют словом HighLoad, но уже возможно всего в одном - двух порядках от него.