MessageBox - это центральная часть BizTalk Server, которая служит для ведения сообщений и их адресации. MessageBox представляет собой базу данных, реализованную на Microsoft SQL Server, в основе дизайна которой лежат следующие фундаментальные принципы :
Для повышения эффективности сообщения записываются в MessageBox как batch. Batch генерируется в MessageAgent и может считаться набором сообщений, рассматриваемых как одна транзакция. Многие batches однако, состоят только из одного сообщения.
Как часть batch, сообщения попадают в MessageBox в два этапа. На первом этапе вызывается stored procedure bts_InsertProperty, задачей которого является занести все контекстные properties сообщения в таблицу MessageProps в сопровождении соответствующего batchID. Сразу же после этого вызывается другая stored procedure - bts_FindSubscriptions, кот. должна проверить subscription predicates на сравнение с записанными properties, т.е. найти хотя бы одного подписчика для записываемого сообщения. Если не удалось вычислить ни одного подписчика, сообщение удаляется из рассмотрения с сопроводительной ошибкой. (Error event 5778 - "Could not find a matching subscription for the message.").
Если хотя бы один подписчик найден, сообщение записывается в таблицу spool, где оно и будет находиться на все время своей жизни внутри BizTalk. Еще до записи в таблицу MessageProps, сообщению присваивается уникальный GUID, кот. для таблицы spool записывается в колонку uidMessageID. Это и есть уникальный номер сообщения, на который, начиная с этого момента, будут ссылаться все остальные записи в других таблицах, или, другими словами, все BizTalk-services, которые тем или иным способом будут иметь дело с этим сообщением. Stored procedure, исполняющая запись сообщения в MessageBox, называется bts_InsertMessage. Она же, зная связанный с сообщением batchID, удалит только что записанные MessageProps, если запись завершилась успешно.
Сообщение состоит из parts. В простейшем случае из одной, называемой body. Но и в более сложных случаях невозможна ситуация, когда подписчик получит только part сообщения, а не его целиком. Тем не менее, с точки зрения MessagedBox, сообщение хранит свои parts отдельно от самого сообщения, в таблице MessageParts. Название bts_InsertMessage не совсем отвечает предназначению этой stored procedure : для каждого вносимого в MessageBox сообщения она вызывается несколько раз, причем каждый эта процедура исполняет несколько различные функции, в зависимости от передаваемых параметров. При первом вызове bts_InsertMessage просто внесёт в таблицу spool контекст сообщения (поле imgContext), а последующие вызовы запишут parts сообщения в таблицу Parts. Запись в Parts осуществляется "внутренней" stored procedure под названием int_InsertPart.
Вообще все db-процедуры, оперирующие сообщениями, рассматривают их как image. В этот image записывается stream из IBaseMessagePart.Data, который, в свою очередь, представляет собой сериализированную форму сообщения : в большинстве случаев XML, но можер быть и любой объект, поддающийся сериализации и де-сериализации.
Вернемся к bts_InsertMessage. Помимо занесения сообщения в таблицы Spool и Parts, эта процедура (с помощью bts_EvaluateSubscription) сообщает о нём BizTalk host'у, просматривая имеющиеся subscriptions на предмет найти нужного подписчика. Как только подписчик найден, это означает для MessageAgent, что ему известен host, который должен обработать данное сообщение. В самом деле, смысл создания subscription состоит не только в назначении предикатов, но и в сопоставлении их равенства определенному сервису, который назначен на обработку сообщений, удовлетворяющих проверенным предикатам. Поэтому в таблице Subscription поле nvcApplicationName содержит имя host'a. Теперь по этому имени MessageAgent знает, в workQ какого host'a нужно передавать сообщение. Делается это с помощью stored procedure int_InsertIntoQ_<HostName> и, как уже говорилось, в workQ заносится только ID обрабатываемого сообщения, само сообщение остается в spool. При переносе сообщения количество ссылок на него увеличивается в таблице <HostName>_MessageRefCountLog. Заметим здесь, что поскольку host может быть запущен на нескольких машинах, на самом деле MessageAgent вычисляет (как?), какому именно host instance передается сообщение, и именно по этой instance идет дальше управление сообщением, включая только упомянутые ссылки на него.
В BizTalk Server group должен быть хотя бы один host. Во время установки такой host определяется с именем BizTalkServerApplication и он становится default host. Определение нового host создает много новых объектов в MessageBox, которых мы коснемся чуть позже, а пока заметим, что появление нового host (т.е. появление нового NT Service) записывает информацию о нем в таблицу Instances, а создание host instance приводит к заполнению в этой таблице колонки uidProcessID. Запуск host'a начинает циклически вызывать stored procedure bts_DeQueueMessages_<HostName>, задачей которой является извлечь из workQ (таблица <HostName>Q) batch сообщений, ожидающих обработки этим host. uidProcessID бегущего host'a передается в эту процедуру параметром. Период цикла определяется одним и тем же для всех host'ов определенного типа в административной таблице adm_ServiceClass (колонка MaxReceiveInterval) базы данных BizTalkMgmtDb. По умолчанию он равен 500 мс., но часто уменьшается, чтобы повысить производительность BizTalk (увеличивая при этом нагрузку на SQL Server). В той же таблице adm_ServiceClass содержится еще одно значение - MaxDequeueThread - играющее важную роль в процессе извлечения сообщений из workQ. Это количество threads, которое использует BizTalk для вызова bts_DeQueueMessages. Подробности об этих параметрах - здесь.
После завершения жизненного цикла сообщения, оно удаляется из <HostName>Q процедурой bts_UpdateMessageBox_<HostName> , вызванной с параметром articatType = 2, а точнее "внутренней" процедурой int_AlterMessage_<HostName>, которая вызывается из bts_UpdateMessageBox_<HostName>. Практически из workQ удаляется только запись, содержащая MessageID удаляемого сообщения; само сообщение будет находиться в таблицах Spool и Parts до тех пор, пока MessageBox_Message_Cleanup_BizTalkMsgBoxDb и MessageBox_Parts_Cleanup_BizTalkMsgBoxDb jobs не обнаружат, что его reference count обнулен и на основании этого сочтут, что сообщение (т.е. его контекст из Spool и parts из Parts) может быть безопасно удалено.