gifts2017

Организация обмена с помощью шины сообщений MSMQ

Опубликовал Андрей Межов (mini_root) в раздел Программирование - Практика программирования

В данное статье приводится пример организации обмена через шину сообщений MSMQ.

 

С выходом восьмой версии 1С в руки разработчиков попали сразу несколько совершенно замечательных вещей, которые позволяет строить сложные распределенные системы с участием 1С. Во-первых, сериализация в XML, а во вторых - планы обмена. Сериализация предоставила возможность представлять данные хранящиеся в базе 1С в нейтральном формате, пригодном для дальнейшей обработке любой системой, а планы обмена позволили описывать перечень данных для которых будут регистрироваться изменения, и которые будут выгружаться. При этом выгрузка, загрузка и регистрация ведется в разрезе логических узлов обмена. Узлы обмена в свою очередь позволяют легко реализовать схему обмена один к одному или один ко многим.
По сути единственная вещь, которая отдана на реализацию разработчикам - это собственно транспорт. А вот тут все оказалось довольно банально - почти во всех случаях все сводится к обмену файлами. Файлы выгружаются на FTP или любое другое общедоступное место одним из узлов обмена и загружаются другим. Такая схема имеет ряд достоинств, прежде всего довольно высокую надежность и простоту реализации. Но она и не лишена недостатков, прежде всего связанных с масштабируемостью и производительностью, особенно если требуется организовать какую-то произвольную обработку выгружаемых данных для их последующей загрузки в систему отличную от 1С. 
Уже достаточно давно люди пришли к осознанию того, что для интеграции разнородных сильнораспределенных систем требуется некая общая точка, интеграционное ПО, которое будет гарантировать доставку, обеспечивать возможность промежуточной обработки, да и вообще скроет разнообразные системы друг от друга. И при так взгляде на вещи, обмен файлами через общую шару уже не является идеальным. 
В данной статье, мы рассмотрим пример интеграции двух баз 1С с помощью шины сообщений. В качестве шины сообщений будем использовать MSMQ (хотя для меня привычней JMS, но в этом случае ценность примера будет гораздо ниже, так как вряд ли кто-то будет поднимать ActiveMQ, для которого тоже есть адаптеры на C#, и заниматься противоестественным играми с быдложабкой).  Тема судя по всему свежа, c учетом того, что поиск msmq или jms на том же Инфостарте не дает никаких результатов.
Для начало немного теории, шина сообщений - это промежуточный механизм для обмена сообщениями, который обладает следующими свойствами:
1. Клиенты шины сообщений не взаимодействуют друг с другом непосредственно, они даже не знают друг о друге почти ничего.
2. Все взаимодействие ведется через шину сообщений, шина сообщений считается априори надежной и транзакционной.
3. Логическим структурами, с помощью которых клиенты шины сообщений обмениваются информацией, являются очереди и топики.
4. Отправитель помещает сообщение в некоторую очередь, а получатель забирает сообщения из некоторой очереди, при этом между ними может быть сколько угодно промежуточных узлов-ретрансляторов/преобразователей. Отправитель видит только место куда он должен поместить сообщение, а получатель - откуда забрать. При этом гарантируется что сообщение будет получено в нужном порядке и только одним получателем (кстати, несколько конкурирующих получателей позволяют организвовать параллельную обработку там где сообщения не зависят друг от друга).
5. Отправитель публикует сообщение в топик, при этом его получает все подписчики, слушающие топик в данный момент времени.
6. Некоторые шины сообщений имеют уже готовый набор обработчиков, которые позволяют фильтровать сообщений, разбивать поток сообщений и вновь агрегировать его, здесь стоит упомянуть проект Camel для ActiveMQ.
Таким образом шина сообщений разделяет разнородные и системы и позволяет организовывать обмен между ними не связывая их между собой непосредственно.
Но вернемся примеру. Итак, в нем мы реализуем обмен XML сообщениями между двумя базами 1С, для обмена мы будем использовать очереди сообщений MSMQ, при этом мы таки будем сохранять сообщения на файловую систему для организации следа, в отладочных целях и для организации возможности быстрой повторной выгрузки. Кроме того в данном пример даже в случае отстуствия изменения генерируется сообщение, для наглядности. Дополнительно мы реализует систему оповещения об ошибках возникших при обмене, используя протокол XMMP и любой клиент (в моем случае - Pidgin).
Общая схема будет выглядеть так:
schema
Для начала нам потребуется установить MSMQ.
установка:
ocsetup.exe MSMQ-Container;MSMQ-Server;MSMQ-DCOMProxy /log:D:\msmq-install.log

удаление:
ocsetup.exe MSMQ-Container;MSMQ-Server;MSMQ-DCOMProxy /uninstall

под Windows XP также можно установить через установку и удаление программ.
    

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

exchange_nodes

Дальше будет необходимо создать и определить ряд констант (в D:\ExchangeOut выгружаются сообщения для следа):
constants
    
Следующий момент состоит в том, что создать адаптеры для подключения к MSMQ и Jabber-серверу - они уже есть в архиве (в готовом виде и в виде исходников). Для обоих адаптеров определим одинаковый интерефейс, как пример того, что можно делать взаимозаменяемые адаптеры для разных систем обмена сообщениями (хотя jabber использовать не стоит из-за отсутствия транзакций, а вот JMS таки да).

using System;
using System.Runtime.InteropServices;

namespace MSMQAdapter
{
    [ComVisible(true)]
   
public interface IAdapter
    {
        void SetParameter(string _name, string _value);
       
void ClearParameters();

       
void SendFile(string _text);
       
void Send(string _text);
       
bool HasMessage();
       
string Receive();

       
void Start();
       
void Stop();

       
void Begin();
       
void Commit();
       
void Rollback();
   
}
}

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

Процедура Получение(adapter, узел)
   
adapter.Begin();
    Попытка
        Пока
adapter.HasMessage() Цикл
           
xml = adapter.Receive();

            Если
СтрДлина(xml) > 500 Тогда
               
ЗаписьВЖуранал("Получение: "+Сред(xml, 1, 500));
            Иначе
               
ЗаписьВЖуранал("Получение: "+xml);
            КонецЕсли;
           
чтениеXML = Новый ЧтениеXML();
           
чтениеXML.УстановитьСтроку(xml);

           
чтениеСообщения = ПланыОбмена.СоздатьЧтениеСообщения();
           
объектУзла = узел.ПолучитьОбъект();
           
исходныйНомерПринятого = Неопределено;

            Попытка
               
чтениеСообщения.НачатьЧтение(чтениеXML);
            Исключение
                Если Не
ФлажокСтрогийПорядокСообщений Тогда
                    Если
СтрЧислоВхождений(
                                   
ОписаниеОшибки(),
                                   
"Номер сообщения меньше или равен номеру ранее принятого сообщения"
                                         
) Тогда
                       
//Автокоррекция номера принятого
                       
исходныйНомерПринятого = объектУзла.НомерПринятого;
                       
объектУзла.НомерПринятого = 0;
                       
объектУзла.Записать();

                       
чтениеXML.Закрыть();
                       
чтениеXML = Новый ЧтениеXML();
                       
чтениеXML.УстановитьСтроку(xml);
                       
чтениеСообщения.НачатьЧтение(чтениеXML);
                    КонецЕсли;
                Иначе
                    ВызватьИсключение
ОписаниеОшибки();
                КонецЕсли;
            КонецПопытки;

            Если
чтениеСообщения.Отправитель <> узел.Ссылка Тогда
                ВызватьИсключение
"Неверный узел отправителя. Ошибка маршрутизации.";
            КонецЕсли;

           
НачатьТранзакцию();

            Попытка
                Пока
ВозможностьЧтенияXML(чтениеXML) Цикл
                   
данные = ПрочитатьXML(чтениеXML);
                   
ЗаписьВЖуранал("Данные: "+данные);
                   
//данные.ОбменДанными.Загрузка = Истина;
                   
данные.Записать();
                   
ПланыОбмена.УдалитьРегистрациюИзменений(
                                       
чтениеСообщения.Отправитель,
                                       
данные
                                                       );
                КонецЦикла;

                Если Не
исходныйНомерПринятого = Неопределено Тогда
                    Если
чтениеСообщения.НомерПринятого > исходныйНомерПринятого Тогда
                       
объектУзла.НомерПринятого = чтениеСообщения.НомерПринятого;
                    Иначе
                       
объектУзла.НомерПринятого = чтениеСообщения.НомерПринятого;
                    КонецЕсли;
                Иначе
                   
объектУзла.НомерПринятого = чтениеСообщения.НомерПринятого;
                КонецЕсли;

               
ЗафиксироватьТранзакцию();

               
чтениеСообщения.ЗакончитьЧтение();
               
чтениеXML.Закрыть();
            Исключение
                ВызватьИсключение
ОписаниеОшибки();
            КонецПопытки;
        КонецЦикла;
       
adapter.Commit();
    Исключение
       
adapter.Rollback();
        ВызватьИсключение
ОписаниеОшибки();
    КонецПопытки;
КонецПроцедуры


Обработка включена в обе базы в архиве.

Теперь, прежде чем начать тестирование, надо позаботиться о jabber-сервере (или закомментировать соотвествующие строчки в обработке), я использовал OpenFire, поднятый в виртуалбоксе - такие извращения были связаны с тем, что библиотека agsXMPP, разыменовывает под вистой localhost не как 127.0.0.1, а как ::1 (IPv6), в то время как OpenFire там не висит.
Итак запуск.... http://www.youtube.com/watch?v=5wolQ2STjdY. На видео демонстрируются изменения в центральной базе и их отображение в переферийной после обмена, а также отправка сообщения об ошибке через XMPP.
Что еще можно сделать:
1. Вынести обмен из обработки в регламентное задание.
2. Оформить сообщение об ошибке в виде структурированного XML, и написать специальную программу клиент (или конфигурацию к 1С), которая будет их принимать, сохранять и определенным образом отображать.
3. Переделать интерфейс JabberAdapter'а.
4. Вообще отказаться от jabber'а и использовать MSMQ для транспорта сообщений об ошибках.
Открытые вопросы:
1. Насколько такой механизм будет эффективен при большом количестве переферийных баз и необходимости обмена с другми системами, отличным от 1С?
2. Насколько легко его будет контроллировать?
3. Любые другие.
Архив со всеми файлами приведен здесь http://infostart.ru/projects/4993/
P.S. С учетом того, что я ковыряю эску чуть более трех месяцев, в моем быдлокоде может быть какая-нибудь глупость - любая конструктивная критика приветствуется.
P.P.S. Если кому интересно во что такая система может вылиться в пределе, ищете в гугле "Enterprise Integration Patterns RUS.djvu" - ооочень занимательная книжка...

См. также

PowerTools от 1 000
Подписаться Добавить вознаграждение

Комментарии

1. Андрей Межов (mini_root) 10.07.09 21:49
2. Андрей Межов (mini_root) 10.07.09 21:56
а как кошерно вставить 1с'вский код в редакторе статей?
3. Андрей Межов (mini_root) 10.07.09 22:24
Мдааа... вот скажите, зачем было разукрашку выкладывать только для зарегистрированных и тремя разными файлами. Ну шо, ждем 00 часов чтобы скачать xml'ник...

4. Андрей Межов (mini_root) 10.07.09 22:34
ступил... ну вот, кажись все, жду комментариев и конструктивной критики
5. Сергей (Che) Коцюра (CheBurator) 11.07.09 03:34
интересно, а можно с помощью этой шины сообщенйи организовать обмен между 2-я сеансами 1Ски?
6. Сергей (Che) Коцюра (CheBurator) 11.07.09 03:36
Качество мультика - отвратное
7. Андрей Межов (mini_root) 11.07.09 11:27
(5) Элементарно, если каждому сеансу будет присвоена своя очередь, например, можно сопоставить справочник сотрудников пользователям 1С и дописать в справочник реквизитом очередь, которую надо будет опрашивать. Таким образом каждый экземпляр/сеанс будет знать откуда ему получать сообщения, плюс у него будет "адресная книга" с очередями всех остальных экземпляров. Экземпляры/сеансы должны в данном случае отличаться друг от друга по пользователям.
(6) Ютуб, шо ты хочешь, там еще кнопочка HD есть - чуть получше будет.
8. Андрей Межов (mini_root) 11.07.09 11:36
(7) Собственно, чтобы организовать обмен между двумя совместимыми по данным системами тебе нужно знать только откуда читать и куда писать. Ну и учесть те или иные особенности систем (типа удаления регистрации и игры с номерками в 1С).
9. Андрей Межов (mini_root) 11.07.09 11:48
(8) Обмен сообщениями может идти даже в рамках одного процесса, есть у ActiveMQ такой режим - транспорт внутри JVM. В приложении с большим количеством потоков позволяет обменивать данными не через общие переменные, и, как следует, избежать синхронизации. Аналогично сделано в эрланге, там это вообще основной способ взаимодействия.
10. Андрей Межов (mini_root) 11.07.09 12:07
(9) Более того, в рамках многопоточного процесса(ов) можно даже использовать внешнюю шину, сохраняющую сообщения в некоем постоянном хранилище - это позволит получить восстановление состояние процесса(ов) после сбоя. По крайней мере в границах транзакций шины сообщений, если кто-то успел что-то положить и сказать commit - его это уже больше не волнует, если кто-то не успел получить что-то и сказать commit - он получит это еще раз.
11. steban (steban) 11.07.09 13:19
чтобы собрать проект в VS2008 пришлось добавить NUnit в GAC
12. steban (steban) 11.07.09 13:21
Хорошее начинание. Можно сделать из этого конфетку.

и да, EIP рулит :)
13. steban (steban) 11.07.09 13:26
было бы неплохо не пинать очередь на предмет наличия сообщений, а привязать событие прихода сообщения к какому-нибудь обработчику в 1С.
14. Андрей Межов (mini_root) 11.07.09 15:42
а обработчик как вызывать из ВК? прокинуть во внешнюю компоненту экземпляр обработки и дергать у нее методы? Или оформить все в виде псевдо активикса? какие еще возможны варианты?

P.S. Или поднять опрос очереди в виде отдельного сервиса, а из него при поступлении сообщений поднимать V8.Application и вызывать обработчик, передавая ему в качестве аргумента адаптер, чтобы можно было полностью контролировать транзакцию.

15. Андрей Межов (mini_root) 11.07.09 15:53
(12) Можно и конфетку, самое главное найти этому применение...

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

16. Андрей Межов (mini_root) 11.07.09 15:55
(11) Там огрызок от юнит теста, которым я отлавливал глюк в agsXMPP.

17. steban (steban) 11.07.09 23:13
(14) угу, прокинуть экземпляр обработки и дергать методы.
или вызывать методы глобального контекста.
18. Андрей Межов (mini_root) 12.07.09 01:46
(17) А как передать глобальный контекст текущего сеанса в ВК?
19. steban (steban) 13.07.09 12:08
(18) ВК может запросить свойство AppDispatch у указателя, полученного в Init.
Это и будет "глобальный контекст".
Только это должен быть объект ВК, а не просто COM-объект.
21. Андрей Межов (mini_root) 13.07.09 13:08
22. dushelov (Душелов) 13.07.09 16:17
А если ВК, значит никакого серверного варианта.
23. Андрей Межов (mini_root) 13.07.09 16:47
А если COM? GetCOMObject на сервере доступен?
24. dushelov (Душелов) 13.07.09 16:50
(23) Ком работает, так, но не передается контекст 1С
25. Андрей Межов (mini_root) 13.07.09 16:52
тогда возможно стоит отказаться от идеи обработчика и вызывать HasMessages в регламентом задании
26. dushelov (Душелов) 13.07.09 16:55
А зачем нужен контекст 1С? Вообще, стоит подобную систему организовать в качестве службы, которая при получение входящих сообщений подключалась бы к 1С и производила необходимые действия.
27. Андрей Межов (mini_root) 13.07.09 17:43
(26) как вариант

А чем принципиально плохо опрашивать очередь из 1С? Например, из регламентного задания.
28. dushelov (Душелов) 14.07.09 00:57
(27) А то, что ты будешь опрашивать каждый заданный интервал времени, когда можно инициировать обработку данных только после получения сообщения.
29. Андрей Межов (mini_root) 14.07.09 11:53
(28) И? Опрашивать в регламентном задании раз в 5-10 минут - интервал зависит от интенсивности и размера сообщений, можно хоть раз в час.
30. Сергей (Che) Коцюра (CheBurator) 14.07.09 22:14
(29) не нравится! почувствуй разницу в двух задачах: выполнить действие при приходе сообщения извне и проверять, а не случилось ли сообщение и если да - тогда что-то сделать... Допустим у меня есть в сутки 5 критичных сообщений, которые д.б. обработаны не позже чем через 5 сек после их прихода. и мне что - каждые 5 сек дергаться-проверять? вместо того, чтобы по приходу сообщения тут же выполнить то, что надо...
31. Андрей Межов (mini_root) 14.07.09 22:36
(30) можно узнать, что за задача требует такой реакции? вряд ли это обмен
32. Сергей (Che) Коцюра (CheBurator) 14.07.09 22:45
обмен как таковой меня не интересует пока.
если сможете "нарисовать" красивую схему когда разные сеансы 1Ски, работающие в одной базе, обмениваются инфой/сообщениями. полученное сообщение может породить длинную цепочку действий. Я НЕ ХОЧУ ПРОВЕРЯТЬ ПРИШЛО ЛИ СООБЩЕНИЕ, я хочу после прихода сообщения получить "сигнал", и по наличию этого сигнала что-то сделать.
33. Андрей Межов (mini_root) 14.07.09 23:51
(32) Как уже выше предлагалось оформить все в в виде ВК, тем более, что судя по всему Вас вполне устроит работа в на клиентской стороне.
В метод Init ВК приезжает контекст одинэски а в SetParameter скармливается имя процедуры в глобальнике. При получении сообщения эта процедура дергается и ей скармливается аргументом сам адаптер, чтобы внутри процедуры можно было иметь полный контроль на транзакцией, ну а там в цикле точно также получаются все сообщения. В следующей версии можно попробовать реализовать.
34. Александр Аверков (Аверков) 15.07.09 10:58
Скиншот 1
Кеды "Престарелый гопник" экстрим эдишн
Охренеть - дайте две! :)
35. Allexey (alex_4x) 17.07.09 10:32
А зачем такой геморой ? Уж если применять шину данных, то пользоваться серьзным, промышленным решением, типа BizTalk.
36. Андрей Межов (mini_root) 17.07.09 12:09
(36) Можно и так, но я с ним не сталкивался - это первое. Особого геморроя я тут не вижу - это второе, дешево и вполне способно заменить файловый обмен, особенно с учетом того, что сообщения в файлы все равно сохраняются и повторная отправка делается на счет раз. Ну а если в середину вставить XSL трансформатор, то можно и с другими системами меняться.

Ну и наконец, с таким же интерфейсом можно сделать адаптеры к другим системам обмена сообщениями, например, к ActiveMQ - а это уже быдложабка 2 EE (я специально сделал один интерфейс для MSMQ и для XMPP, чтобы это продемонстрировать). Интеграция с BizTalk'ом вряд ли будет чем-то отличаться от вариантов приведенных в статье и в обсуждении. И опять же, не бизтолком единым, есть и другие решения - COM, XML сериализация и планы обмена дают большой простор для фантазии, например, я знаю как можно интегрировать эску с практически любым ESB (пробовал на OpenESB).

37. steban (steban) 17.07.09 12:44
>я знаю как можно интегрировать эску с практически любым ESB (пробовал на OpenESB)

с этого момента, пожалуйста, поподробней
38. Андрей Межов (mini_root) 17.07.09 13:20
(37) будет время, постараюсь еще одну статейку накатать
39. Михаил Кузнецов (hotey) 22.07.09 09:03
А кто-нибудь пробовал в сети этот пример запустить? Проходят сообщения?
40. desty (lustin) 23.07.09 02:19
(39)
Я пробовал, все работает ;-)
41. Михаил Кузнецов (hotey) 23.07.09 08:12
(40) А у меня всё получилось только после целого ряда дополнительных телодвижений. Большая часть была произведена возможно по своей неопытности, но пришлось даже свойства сборки менять и dll перекомпилировать. Я правда пытался связь между XP и 2003 Server наладить...
42. Андрей Межов (mini_root) 23.07.09 10:44
(41) Интересно, а какие компоненты MSMQ дополнительно ставили? На висту хоум басик многих вещей не поставишь.

43. Михаил Кузнецов (hotey) 24.07.09 03:29
(42) Локально на одной машине заработало так как и было. То есть на XP пришлось только прорегистрировать DLL с помощью regasm.exe.
А вот на Win2k3 Server пришлось в AssemblyInfo.cs прописать:
using System.Security;
[assembly: AllowPartiallyTrustedCallers()]
И перекомпилить - только после этого пошло...
Что касается непосредственно компонентов MSMQ, то в итоге стоят почти все доступные. :)
Сейчас только осталось разобраться с роутингом и прочими наворотами, чтобы сообщения проходили между хостами, которые не пересекаются во времени.
44. Андрей Межов (mini_root) 24.07.09 20:03
(43) Спасибо, если будет возможность и желание - поделитесь опытом, например, в виде статьи.

P.S. А я постараюсь через недельку подогнать еще одну, на этот раз на тему интеграции 1С с шиной веб-сервисов OpenESB.
45. Михаил Кузнецов (hotey) 27.07.09 02:52
(44) Да собственно на статью материала маловато. Все полезные выводы уместились в предыдущий комментарий.
46. Андрей Межов (mini_root) 31.07.09 11:28
А вот взгляд на интеграцию с другой точки: http://infostart.ru/blogs/1236/

Хотя для взаимодействия через план обмена предпочтительнее использовать таки обычную шину сообщений.
47. igor-bts (igor-bts) 04.08.09 16:51
Вопрос, а как эта система будет работать в распределенной (через интернет) сети?
48. Андрей Межов (mini_root) 04.08.09 17:17
Ну, во-первых, у MSMQ есть множество разных компонентов (с TCP транспортом, с HTTP и пр.).

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

DIRECT=TCP:IPAddress\QueueName;

Это ж у меня все локально аля ".\Private$\...."

В-третьих, вон там выше есть товарищ с ником hotey, он наладил обмен между разными узлами внутри локалки.


P.S. Кроме того там есть еще такая вещь как каналы http://www.codeproject.com/KB/IP/msmqchannel.aspx
49. Андрей Межов (mini_root) 04.08.09 17:20
http://msdn.microsoft.com/en-us/library/ms700996(VS.85).aspx

>Direct format names are used to reference public or private queues without accessing the directory service. Direct format names are used when performing the following operations:

* Sending messages directly to a computer.
* Sending messages to computers over the Internet.
* Sending messages across forest boundaries.
* Sending messages to any queue while operating in domain, workgroup, or offline mode.
* Reading messages while operating in domain, workgroup, or offline mode.

там же:

> DIRECT=TCP:157.18.3.1\MyQueue
50. Андрей Межов (mini_root) 04.08.09 17:22
Но:

>Security Limitations

>Opening a remote queue for sending messages with a direct format name signals Message Queuing not to query the directory service when it opens the queue. This enables Message Queuing to send messages in workgroup and offline mode and to transmit messages across forest boundaries, but it eliminates the possibility of using some of the security functionality provided by Message Queuing for access control, authentication, and encryption. When security services performed by Message Queuing are unavailable, it is the responsibility of your application to implement the missing functionality.
51. Андрей Межов (mini_root) 04.08.09 17:27
Хотя если есть VPN, то наверное не страшно.

Вот вроде бы вариант с использованием HTTPS: http://technet.microsoft.com/en-us/library/cc736680(WS.10).aspx

52. Андрей Межов (mini_root) 04.08.09 17:35
В случае с HTTPS все сводится к разрешению подключения только доверенных клиентов и раздаче этим клиентам сертификатов. Сертификат есть, подключишься, сертификата нету:

IIS 5.0: HTTP 403.16 Forbidden: Client Certificate Untrusted or Invalid.

или что-то подобное

Ну и у сервера свой сертификат должен быть.

53. Евгений Матыцин (matytsin_new) 28.11.11 12:56
Поправьте меня, если я ошибаюсь.
1) MSMQ позволяет сохранять сообщения для отправки в очереди.
2) а что будет, если адресат, которому эта очередь предназначена не будет регулярно получать сообщения?
Т.е. ситуация: Имеем нерадивого подписчика обмена, который не хочет, не умеет, забывает делать обмен, в мерцающем режиме появляется в Интернете и как результат не забирает сообщения, которые ему предназначены.
Далее. Характер данных, передаваемых в обмене имеет существенно древовидную структуру, такую, что загрузка последующих сообщений без загрузки предыдущих - просто разрушит целостность дерева у клиента. Т.о. мы не можем очистить его очередь или оптимизировать его сообщения так, чтобы их количество и объем уменьшились.
Тогда мы получаем потенциальную опасность безграничного разрастания очереди для получателя обмена.
Если количество получателей будет измеряться многими сотнями, а то и тысячами, то данная схема должна предусматривать возможность защиты от пожобных ситуаций, иначе мы просто впустую сожрем место на сервере MSMQ
54. Андрей Межов (mini_root) 28.11.11 21:37
Все хорошо в меру и шина сообщений имеет целый ряд ограничений и специфических приемов при построении той или иной схемы. По большей части они происходят из асинхронной природы очередей: отсутствует блокировка для ожидания ответа. Тут есть как плюсы, так и минусы: главный плюс - возможность отложенной асинхронной и параллельной обработки, минус - сложность получения привычного "синхронного поведения".
Например, вот так реализуется схема запрос-ответ (на примере JMS, оно мне роднее): http://eaipatterns.com/RequestReplyJmsExample.html. Там же вроде есть и полный список паттернов интеграции: http://eaipatterns.com/toc.html.
Надо сказать что далеко не всегда требуется передавать данные учетных систем, которые должны следовать строго непрерывно и в полном объеме, данные вполне могут иметь "срок годности" (http://docs.oracle.com/cd/E17802_01/products/products/jms/javadoc-102a/javax/jms/MessageProducer.html - методы xxxTimeToLive).

Конкретно в вашем случае:
1. Если просто распихивать сообщения push'ем по очередям, без учета режима активности клиентов, то да - это приведет к затариванию очереди.
2. Если же усложнить схему:
- клиент отправляет сообщение с запросом в одну из очередей, указав кто он, что ему нужно и куда отвечать (replyTo в JMS).
- на другой стороне обработчик не спеша по этому запросу собирает ответный пакет, при этом транзакция на чтение из очереди запросов = транзакции на работу с БД с данными = транзакции на отправку ответного пакета (конструкция либо дорабатывает до конца, либо откатывается назад к состоянию, когда сообщение с запросом все еще стоит в очереди), после чего ответный пакет готов к забору со стороны клиента.
- клиент в одной транзакции получает пакет из шины и приземляет его к себе.
- при возникновении ошибки клиенту отправляется сообщение с ошибкой, которое он должен обработать тем или иным способом.

И вот во втором варианте, как мне кажется, вполне можно использовать timeToLive, причем и на запрос и на ответ. Клиенту будет достаточно сохранить id исходного сообщения (или другой уникальный признак), а серверу - возвращать ответные пакеты с указанием этого исходного id (то, что в JMS называется correlationId). Таким образом, всегда будет возможность узнать в ответ на какой запрос пришел этот ответный пакет, а зная порядок id запросов всегда можно восстановить соответствие, просто используя фильтр для выборки сообщения с тем или иным значением поля:

QueueReceiver receiver = session.createReceiver(myQueue, "JMSCorrelationID='id'")

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

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

клиент -> [очередь запроса] -> обработчик(и) запросов <-> БД (или другой источник данных)
клиент <- [очередь ответа/ошибки] <------------------

Из push'а схема превращается в асинхронный poll с самообслуживанием со стороны клиента (он сам изъявляет желание получить данные).

При такой схеме клиент может "мерцать" как ему угодно, к затариванию это не приведет. С другой стороны имеем асинхронность и параллельность обработки.

Навскидку как-то так...
55. Андрей Межов (mini_root) 29.11.11 10:43
В качестве иллюстрации того, что при желании схему можно закрутить как угодно: при некоторой степени извращенности можно собрать кластер для бедных, в виде фоновой службы запущенной на офисных компах, которая через специальные очереди (или еще как) выгребает код скрипта или готовую библиотеку с точкой входа, а потом обрабатывает сообщения-запросы в соответствии с загруженной логикой, потихоньку отъедая избыточную вычислительную мощность у секретарши Маши и кадровички Любы.
Пнул новый скрипт/библиотеку - изменил логику обработки. Маша выключила компьютер? Не страшно, ведь осталась Люба! Правда остается еще вопрос с источником данных, в него тоже можно упереться (производительность/блокировки).
Для написания сообщения необходимо авторизоваться
Прикрепить файл
Дополнительные параметры ответа