一. 消息的轮询和执行
1. 轮询机制
消息路由到MessageBox数据库中,只是在数据库中写入了相关记录,表示哪个消息需要由哪个服务实例去执行,并没有付诸实施,还需要在进程中实实在在的去实例化这个服务对象,运行服务实例对象,并把消息交给这个实例对象处理。
轮询主机队列是由订阅服务器的那些类先实例化为对象后,由服务实例去查询主机队列中的消息队列,找到是自己订阅的消息就拿过来处理,否则继续轮询下去。
服务实例轮询的时间间隔和同时运行的线程数由在BizTalkMgmtDb管理数据库中的adm_ServiceClass表中设置,此表中有两个字段:
MaxReceiveInterval ―― 设置此类服务连续轮询数据库的时间间隔
MaxDequeueThread ―― 最大出列线程的数目
adm_ServiceClass表中目前有四条记录,表示有四类可用的订阅服务类别。前面章节已经有介绍,分别是:
XLANG/s – 业务流程(orchestration)
Messaging InProcess – 表示一般的发送端口、Solicit- Response发送端口
MSMQT – MS消息队列
Messaging Isolated –表示请求/响应(Request-Response)接收端口,目前基本上就是指HTTP和SOAP的Request-Response双向接收端口。
每个服务相应的 MaxReceiveInterval 字段表示此类服务轮询主机队列的时间间隔(单位毫秒,默认轮询间隔都是 500 毫秒),就是说每隔这么多时间就要新开一个线程实例化一个这个服务类,这个实例去查询主机队列。MaxDequeueThread字段表示同时处理本类服务的线程数,就是可以同时生成多少个本类服务的实例,去查询主机队列(默认都是5个)。这些实例去查询主机队列时有锁定机制进行保障,保证具体某一个时刻只能有一个实例对主机队列就行操作。
2. 轮询过程
2.1. 产生轮询的服务实例
一类服务的轮询包括两种情况,一种是激活订阅的情况,一种是实例订阅的情况。
激活订阅的情况,Biztalk先按照adm_ServiceClass表中规定的某一服务类的轮询间隔时间一次性生成MaxDequeueThread字段规定的多少个本类服务实例,就是新建多个线程,每个线程把某个服务类实例化为对象,由这些对象去查询主机队列。 这类实例是用来查询激活订阅的,因为激活订阅需要有新的实例来运行接收消息。
实例订阅的情况,原先“请求/响应接收端口”服务实例在接收消息发并发布出去后,本身会产生一个对返回消息的订阅,这就是实例订阅的情况。这类服务实例也会对主机队列进行轮询,查看是返回消息是否已经路由过来了。
2.2. 查询主机队列中的消息
2.2.1. 激活订阅的实例
每个新生成的服务实例都是由一个线程实例化并在其中运行,每个线程都有一个线程的guid来标识这个线程,就是说每个服务实例都可以对应到一个由线程guid标识的线程。运行中的服务实例到主机队列中进行查询,查看是否有可以处理的消息,主机队列要符合一个条件:
l 主机队列中订阅消息的服务类型跟本服务实例类型一致
运行的服务实例找到符合条件的,转入下一步,处理消息。
2.2.2. 实例订阅的实例
实例订阅的时候,同样在线程中运行的服务实例去查询主机队列,同样查看是否有路由到自己这的消息,主机队列要符合两个条件:
l 主机队列中订阅消息的服务类型跟本服务实例类型一致
l 主机队列中服务实例uidInstanceID字段值跟本服务实例的uidInstanceID一致。
如果有符合条件的消息,转入下一步,处理消息。
2.3. 处理消息
轮询的服务实例一旦在主机队列中匹配到待处理的消息,开始处理消息,大致过程如下:
l 把线程的guid写入到实例表的uidProcessID字段,表示这个实例由本线程进行处理。
l 将实例表的nState字段置为2,表示实例在运行中
l 根据主机队列表指示的消息guid,到spool表和parts表中获得消息具体内容进行处理
l 删除主机队列中的本条记录,表示此消息已经开始处理。
l 在服务实例运行过程中,原先在主机队列表中服务实例跟消息实例是有关联的,在删除主机队列中的本条记录后,服务实例跟正在处理的消息就失去了关联,故此,biztalk在删除主机队列记录的同时,把跟本实例的关联的消息guid记入到InstanceStateMessageReferences_BizTalkServerApplication实例与消息引用表,这个表主要字段:
uidInstanceID ―― 服务实例的guid
uidInstanceStateID ―― 含义不明
uidWorkID ―― 含义不明
uidMessageID ―― 消息的guid
uidServiceID ―― 服务guid
这样能保证服务实例在运行中能够知道跟本身相关联的消息是哪一个。
2.4. 消息处理完毕后
服务实例处理一个消息,处理完毕后要做的工作:
l 如果是“请求/响应接收端口”服务请求部分订阅产生的激活订阅服务实例完成后,服务实例在实例表中不删除,依然保留,以便这个实例继续处理返回的消息。
l 如果是一般的激活实例或“请求/响应接收端口”服务响应部分订阅产生的实例订阅服务实例完成后,会把这个服务实例的记录从实例表中删除。
l 删除InstanceStateMessageReferences_BizTalkServerApplication实例与消息引用表中跟此实例相关记录。