深入biztalk消息以及消息订阅发布路由机制(三)-消息发布和路由

消息的发布有几种情况,上面讲述发布服务器时说过的三种发布服务都可以发布消息,他们的发布原理基本一致,这里以适配器发布消息为主进行描述消息发布和路由的过程。
上面的消息流程章节中描述了消息从接收端口接收进入biztalk后的处理过程,但是消息如何进入到MessageBox,如何路由到订阅此消息的服务的过程还没详细说明,这里将详细描述消息的发布和路由过程。
消息代理处理整个消息发布和路由的过程。
消息在经过了接收管道处理后,相关的属性已经升级到消息上下文(使用了默认接收管道XMLReceive或自建的管道中使用了xml拆装器的情况下biztalk会根据schema升级属性,使用默认接收管道PassThruTransmit不会升级属性)。
消息代理获得消息后,先把消息的属性写入到MessageBox数据库的消息属性表MessageProps表,包括了此消息的系统属性和从消息本身升级的属性。
MessageProps表的结构如下:
uidBatchID -- 消息批次id。 此字段还不是很清楚,可能是一次可能处理多个消息,同一批进行处理的作为一个批次。
uidMessageID -- 消息的uid
uidPropID -- 这个消息的某一个属性,属性都用guid来表示。
vtPropValue -- 这个属性的值
 
1. 调用bts_FindSubscriptions过程
消息代理调用bts_FindSubscriptions存储过程来查找订阅了消息的相关订阅。这个存储过程把订阅表和各个订阅谓词表定义的订阅跟消息的属性表中的属性比较,找出所有所有符合此消息条件的订阅,返回到一个结果集中。这个结果集中最主要包含字段有:订阅guid(uidSubID)、此订阅所属主机实例名( nvcApplicationName)、消息guid(uidMessageID),服务的guid(uidServiceID)、服务实例的guid(uidInstanceID),结果集表示订阅表中的哪些订阅匹配到了这个消息,每个订阅了此消息的订阅为一条记录。如果一个消息被两个服务订阅了,这个结果集中将会有两条记录。
消息代理根据这个结果集,对每条记录调用存储过程bts_InsertMessage。以下的步骤,结果集中的每条记录都要执行一遍。
2. 第一次调用bts_InsertMessage过程
这次调用bts_InsertMessage过程主要任务是调用int_EvaluateSubscription过程。int_EvaluateSubscription过程根据当前处理的订阅所属的应用主机实例名,再调用对应此主机实例的存储过程进一步处理,调用的存储过程名称是“int_InsertIntoQueue_主机实例名”这样的命名形式,比如服务属于BizTalkServerApplication主机,则调用int_InsertIntoQueue_BizTalkServerApplication。
存储过程“int_InsertIntoQueue_主机实例名”的作用:
如果是订阅类型是激活订阅,即uidInstanceID为空,说明需要新建一个处理订阅消息的服务实例,这一步骤新建一个guid,作为新建实例的实例guid。
之后要新建实例记录,即在实例表中插入一条实例记录表示要处理这条消息的实例。
Instances实例表主要字段:
主要字段
含义
uidAppOwnerID
所属主机实例的guid
uidInstanceID
此服务实例的guid
uidServiceID
此服务的guid
uidClassID
此服务的类型guid
uidProcessID
运行这个实例的线程guid
nState
实例状态:
1-准备运行,已激活但尚未开始运行的服务实例,通常由于资源暂时不可用,例如服务器的处理负载过大
2-已启动,正在运行的服务实例。
4-可恢复的挂起,实例已挂起,但可恢复该实例。
8-已冻结,实例状态保持在 MessageBox 数据库中,并且没有 Windows 服务运行该实例。
32-不可恢复的挂起,实例已挂起,且不可恢复该实例。可以保存该实例所引用的消息,然后终止该实例。
64 -- 在断点处
256-已计划要运行
 
如果订阅的状态是处于正常的活动状态,则在Instances实例表中插入一条记录,只记入四个字段:uidAppOwnerID, uidInstanceID, uidServiceID, uidClassID, nState。uidAppOwnerID为此主机实例的guid,uidInstanceID为新建的服务实例的guid,uidServiceID为订阅消息的服务guid,uidClassID为订阅服务的类型guid,nState实例状态为256,表示已计划要运行。
如果订阅的状态是处于停用状态,在插入Instances实例表(插入的状态字段nState4)的同时还会在InstancesSuspended挂起实例表中都插入一条记录,挂起实例表中除了上面上面提到的四个字段,还包括一些错误代码和错误描述字段,可能是描述挂起原因的一些内容。此时nState实例状态为4,表示这个实例是可恢复的挂起。
我没看出来这个状态码的含义,有知道的朋友请告知
 
如果是实例订阅,由于订阅的主体服务实例已经存在(在实例表中有这个服务的一条记录),不必再新建一个订阅服务的实例。
如果订阅是处于活动状态,这一步骤要将这个订阅内容插入到相应的主机队列表中,主机队列表为“<主机实例名>Q”形式,表示路由到此主机的还未被处理的消息队列。如果相应的主机实例是BizTalkServerApplication,那就将此消息订阅内容插入到BizTalkServerApplicationQ表中。
主机队列表BizTalkServerApplicationQ主要字段:
主要字段
含义
nID
自动标识
uidMessageID
消息guid
uidSubscriptionID
订阅guid
uidClassID
订阅此消息的服务类别guid
uidServiceID
订阅此消息的服务guid
uidInstanceID
订阅此消息的服务实例guid
uidAppInstanceID
主机实例guid
如果订阅处于停用(订阅状态码为2),或者订阅状态码为8( 此码含义不清楚)时,订阅内容不被插入到主机队列表中,而是插入到主机队列挂起表中,表示订阅此消息的订阅不处于活动状态,此消息被挂起。挂起表为“<主机实例名>Q_Suspended”形式,此表大部分内容跟主机队列表相同,增加了一些表示为何挂起的字段,比如挂起原因nvcAdditionalInfo字段,挂起是否可恢复nIsResumable字段等。
3. 其后调用bts_InsertMessage过程
接下来的过程将把消息的所有内容写入到MessageBox数据库中,一条消息本身内容在数据只有一个副本,所有订阅了此消息的服务都参考引用这一个消息的副本。消息本身是不能修改的,如果哪个服务需要修改消息,必然是需要生成另外一条消息。
其后的第一次调用bts_InsertMessage过程将传递消息上下文,然后将该消息上下文以及有关消息的元数据(例如,部分数、正文部分名称和 ID)插入到 SPOOL 表中。SPOOL 表是对一条消息的总体性描述和消息的上下文属性,一条消息在此表中有一条记录。另外,消息正文部分也在这一步使用 int_InsertPart 存储过程插入到 PARTS 表中,一条消息的多部分中只能有一个正文部分。
SPOOL 表主要字段:
主要字段
含义
uidMessageID
消息的guid
UserName
用户名,运行主机实例的用户
PublishingServer
biztalk所在服务器的名称
OriginatorSID
创建者的安全id,即启动biztalk服务的帐户
OriginatorPID
创建者参与方id,一般是“s-1-5-7”
nvcMessageType
消息的类型,由正文部分决定的
nNumParts
消息包含的部分数
uidBodyPartID
正文部分的guid
nvcBodyPartName
正文部分名
nCounter
部分计数
imgContext
上下文的内容
MessageParts表是SPOOL消息队列表跟PARTS消息部分表之间的中间关系表,MessageParts. uidMessageID字段跟SPOOL.uidMessageID字段关联,PARTS. uidPartID字段跟MessagePart. uidPartID段关联。

主要字段
含义
uidMessageID
消息guid
uidPartID
消息部分的guid
nvcPartName
消息部分名
nBodyPart
是否正文
1 -- 正文
0 -- 不是正文

   PARTS

uidPartID
消息部分guid
nPartSize
部分的尺寸
imgPart
部分的数据
 
实例表Instances表跟消息队列SPOOL表之间关系,就是哪个服务实例订阅了哪个消息是靠主机队列BizTalkServerApplicationQ表的关联起来,Instances. uidInstanceID字段跟BizTalkServerApplicationQ. uidInstanceID字段相关,BizTalkServerApplicationQ. uidMessageID字段跟SPOOL.uidMessageID字段相关。
 
这一步的最后还有做一件事就是把消息代理写入到MessageBox属性表MessageProps中这个批次的所有属性记录都删除,因为它们已经不再有用。

随后,除了消息正文部分为每个剩余的消息部分调用 bts_InsertMessage 存储过程,把这些消息部分一一写入到PARTS 表中。
4. 消息发布和路由总结
一个消息有从适配器进来,到消息代理把消息路由到MessageBox数据口中相应的表中,这个过程就是消息的发布和路由过程。
路由完毕后,在主机队列表中存在待处理的消息队列,这个表可以简单的理解为哪个消息将要由哪个服务实例处理。
实例表Instances表存放要处理这些消息的服务实例记录,一个待处理的消息对应一个实例,实例表每条记录可以简单的理解为这个实例是哪个服务类型的服务,服务目前是什么状态。其实Instances表中的实例还需要由具体的服务线程来运行它,这时才是真正的服务实例化,这点下一章“消息的轮询和执行”中会有详细讲解。
消息的具体内容存放在SPOOL 表和PARTS 表中,Spool表存放消息的总体性描述和消息的上下文属性,PARTS 表存放消息的各个部分。
表存放多部分消息的各个部分,一个部分在此表中占一条记录。哪一个是正文部分由spool表中的uidBodyPartID标识。
 
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值