IBM®WebSphere®Application Server V7和V8支持基于Java消息服务(JMS)规范的异步消息传递。 通过使用IBM MQ消息传递提供程序,您可以编写在IBM MQ目标(消息队列或主题)上侦听的消息驱动Bean。 当消息到达目标时,消息驱动bean的onMessage()方法将开始处理消息。
在WebSphere Application Server V7和V8中,IBM MQ消息传递提供程序支持使用激活规范来监视由IBM MQ队列管理器托管的目标。 本文显示了激活规范如何连接到分布式平台上的MQ。 它描述了用于监视正在寻找邮件的目标的机制。 然后,它显示了在检测到合适的消息之后如何启动消息驱动的Bean。 本文假定您具有JMS和IBM MQ的基本知识。
激活规范
一般而言,J2C激活规范是受管理的对象,其中包含有关如何连接到JMS提供程序的信息,以及该JMS提供程序上将受到消息监视的目的地的详细信息。 部署包含消息驱动的Bean的应用程序时,需要指定消息驱动的Bean将使用的激活规范。 激活规范启动时,它将连接到JMS提供程序,打开JMS目标,然后监视它以查找消息。
图1和2显示了示例MQ激活规范,该示例是通过使用WebSphere Application Server集成解决方案控制台中的激活规范窗口定义的。 当此激活规范启动时,它将与称为pault的本地MQ队列管理器建立BINDINGS模式连接,打开目标jms / TestQueue,然后开始监视此目标中的消息。
图1.指定队列管理器名称和传输类型
可以将激活规范配置为使用消息选择器,从而使它们仅将满足选择条件的消息传递给消息驱动的Bean。 在图2中,未指定消息选择器。 因此,所有到达目的地的消息都适合通过此激活规范进行处理。
图2.指定激活规范将监视的JMS目标
当激活规范找到合适的消息时,它将在应用程序服务器中安排一项工作来对其进行处理。 每个消息都需要运行JMS服务器会话,并且可以同时处理多个消息。
每个激活规范都有一个关联的服务器会话池,其大小控制着一个激活规范可以同时处理的消息数。 服务器会话池的默认大小为10,这意味着一个激活规范最多可以同时处理10条消息。 要更改服务器会话池的大小,请修改激活规范的高级属性Maximum server Sessions ,如图3所示。
图3.指定可以同时处理多少条消息
![指定可以同时处理多少条消息](https://i-blog.csdnimg.cn/blog_migrate/69b72241230ac7b95748a9496cbcaed7.png)
检测消息
激活规范用来检测MQ队列管理器上托管的JMS目标上的消息的机制根据所使用的MQ消息传递提供程序模式而有所不同,如下所述。
MQ消息传递提供程序正常模式
如果激活规范连接到MQ V7队列管理器,并且提供程序版本属性设置为未指定(默认值)或7,则使用MQ消息传递提供程序普通模式。在这种操作模式下,激活规范利用IBM MQ V7连接到队列管理器并获取消息时的几种功能。 启动时,激活规范:
- 激活规范会创建一个与设置使用的MQ队列管理器的连接。
- 如果激活规范配置为使用队列目的地,则激活规范通过使用MQ API调用MQOPEN打开队列。
- 如果激活规范配置为使用主题目的地,那么激活规范将发出MQ API MQSUB调用以订阅适当的主题。
- 在打开队列或预订主题之后,激活规范使用MQ API调用MQCB来注册回调。 使用以下MQ GetMessageOptions设置回调:
- MQGMO_BROWSE_FIRST
- MQGMO_UNMARKED_BROWSE_MSG
- MQGMO_MARK_BROWSE_CO_OP
- 注册回调之后,激活规范将发出MQ MQCTL API调用,该调用将通知队列管理器激活规范已准备好开始接收消息。
现在,当适当的消息到达激活规范正在监视的队列上或在激活规范已订阅的主题上发布时,队列管理器会标记该消息以防止其他激活规范检测到它。 然后,它使用先前设置的回调将消息的详细信息传递给激活规范。
MQ消息传递提供程序迁移模式
激活规范可以连接到MQ队列管理器的另一种方法是使用MQ消息传递提供程序迁移模式。 如果满足以下条件之一,则使用此模式:
- 激活规范配置为连接到IBM MQ V6队列管理器。
- 激活规范配置为连接到IBM MQ V7队列管理器,并且Provider Version属性设置为6。
- 激活规范配置为使用CLIENT传输连接到IBM MQ V7队列管理器,并且使用的MQ通道的“ 共享对话” (SHARECNV)属性设置为0。
当激活规范以迁移模式启动时,它:
- 创建与设置使用的MQ队列管理器的连接。
- 如果激活规范配置为监视队列目的地,那么它将发出MQOPEN API调用以打开队列。
- 如果激活规范配置为使用主题目的地,则它:
- 打开该主题的订阅。
- 检查激活规范Broker Properties Broker连接使用者订阅队列和Broker持久订阅者连接使用者队列的值,以查看Broker将向该WebSphere MQ队列发布此激活规范的消息。
- 调用MQ API MQOPEN打开适当的订阅队列。
- 在队列管理器上打开队列之后,激活规范通过发出MQGET API调用浏览正在寻找消息的队列。 激活规范结合使用MQ GetMessageOptions MQGMO_BROWSE_FIRST和MQGMO_BROWSE_NEXT来从上到下扫描队列。
处理消息
当检测到激活规范时,目标上的消息(由于IBM MQ V7队列管理器通过使用回调传递了关于消息的信息,或者因为激活规范浏览了合适的消息),它会:
- 构造一个表示消息的消息引用。
- 从激活规范服务器会话池中获取服务器会话。
- 使用消息引用加载服务器会话。
- 通过应用程序服务器工作管理器安排工作。
然后,激活规范将返回以查找更多消息。
获取服务器会话
如前所述,默认情况下,激活规范将最多同时处理10条消息。 如果激活规范尝试处理消息并且所有10个服务器会话都已经在忙于处理消息,会发生什么情况? 在这种情况下,激活规范将阻塞,直到服务器会话变为空闲为止。 一旦有服务器会话可用,激活规范就将其与消息引用一起加载,然后安排新的工作,以便服务器会话可以再次运行。
安排工作
当激活规范通过消息引用加载服务器会话时,它会安排一些工作,以便可以处理消息。 工作会怎样? 工作经理:
- 从WebSphere Application Server中的MQ消息传递提供程序资源适配器线程池获取线程。 该线程池的名称为WMQJCAResourceAdapter。
- 在此线程上运行工作。
安排工作后,应用程序服务器工作管理器会在将来的某个时候运行此工作。 工作开始时:
- 根据消息驱动bean是否需要XA事务(在消息驱动bean的部署描述符中指定),启动本地或全局(XA)事务。
- 如果这是第一次使用服务器会话,则:
- 创建与MQ的连接。
- 发出MQOPEN API调用以打开消息所在的队列。
- 通过发出破坏性的MQGET API调用从MQ获取消息。
- 运行消息驱动的bean的onMessage()方法。
- 当onMessage()完成时,服务器会话将在退出之前完成本地或全局事务。
为了提高性能,在处理消息并完成工作之后,服务器会话使用的与队列管理器的连接保持打开状态。 然后,下次将服务器会话用于处理消息时,不需要重新连接到MQ并重新打开包含消息的队列。 默认情况下,与激活规范关联的未使用的服务器会话在关闭之前会保持打开状态30分钟。 您可以通过修改激活规范高级属性“ 服务器会话池超时”的值来延长此超时时间,如图4所示。
在轻负载的系统上,计划的工作与工作管理器开始工作之间的时间可能只有几毫秒。 在繁忙的系统上,开始工作之前可能会有很长的延迟。 这是延迟的两个可能原因:
- WMQJCAResourceAdapter线程池中没有可用的线程来运行工作。
- 工作管理器能够从线程池中获取线程,但是由于应用程序服务器太忙而无法启动工作。
工作管理器记录何时安排工作,以及何时开始工作,它检查自激活规范计划工作以来经过了多少时间。 默认情况下,激活规范期望工作在计划的10秒内开始。 如果在工作管理器开始工作之前已超过10秒钟,则将WorkRejected异常返回到激活规范,从而导致类似于以下异常的异常出现在应用程序服务器SystemErr.log中:
Exception in thread "WMQJCAResourceAdapter : 1" java.lang.RuntimeException:
javax.resource.spi.work.WorkRejectedException: Work timed out (id=4), error code: 1
: : : : : : : : : : : : : : : : : : : : : :
Caused by: javax.resource.spi.work.WorkRejectedException: Work timed out
(id=4), error code: 1
当发生此类异常时,队列管理器将“消息参考”中的消息“未标记”,以便可以对其进行重新处理。 您可以使用Start timeout在激活规范Advanced properties面板上更改此10秒的时间限制,如图4所示。
图4.修改服务器会话超时和等待工作开始的时间
前面提到过,如果WMQJCAResourceAdapter线程池没有足够的线程,则可能会延迟工作。 这就引出了一个明显的问题:“该线程池的大小应该是多少?”
激活规范使用每个应用程序服务器一个线程池来运行服务器会话。 每个激活规范都有一个称为“ 最大服务器会话数”的高级属性,该属性定义可以同时运行的最大并发服务器会话数。 因为每个服务器会话都用于处理消息,所以此属性实质上表示使用此激活规范的消息驱动Bean可以同时处理多少个消息。
若要确定WMQJCAResourceAdapter线程池的大小,请为应用程序服务器上的每个MQ消息传递提供程序激活规范添加“ 最大服务器会话数”属性的值。 例如,假设您定义了25个激活规范,每个激活规范的“ 最大服务器会话数”属性设置为3。在这种情况下,最多可以同时运行75个服务器会话,每个会话都使用WMQJCAResourceAdapter线程池中的线程。 因此,将此线程池的最大大小设置为75。图5显示了WebSphere Integrated Solutions Console中的WMQJCAResourceAdapter线程池面板,您可以在其中更改该线程池的大小。
图5.更改可用于应用程序服务器中定义的所有激活规范的最大线程数
![更改可用于应用程序服务器中定义的所有激活规范的最大线程数](https://i-blog.csdnimg.cn/blog_migrate/e52902c7d5c614f4fff445e6fde57f09.png)
如果WorkRejected错误开始出现在应用程序服务器SystemOut.log文件中,请确保WMQJCAResourceAdapter线程池足够大以处理激活规范所需的所有服务器会话。 如果线程池大小正确,则错误是由工作管理器无法在指定的时间段内启动工作请求引起的。 在这种情况下,或者增加激活规范高级属性Start Timeout的值 ,或者研究减少应用程序服务器系统上的负载。
使用MQ消息传递提供程序普通模式
如前所述,在以下情况下,检测到的消息与消息驱动的bean正在处理该消息之间可能会发生延迟:
- 正在使用与激活规范关联的所有服务器会话。
- WMQJCAResourceAdapter线程池中的所有线程都用于处理消息。
- 在计划的工作与工作管理器开始工作之间会发生延迟。
如果激活规范以MQ消息传递提供者普通模式运行,那么队列管理器会在消息传递给激活规范之前将消息标记。 标记该消息意味着在同一应用程序服务器或不同应用程序服务器上运行的其他激活规范(或WebSphere Application Server侦听器端口)都看不到该消息。 此方法可防止另一个消息驱动的Bean在服务器会话有时间处理消息之前获取消息。
默认情况下,邮件被标记5秒钟。 要更改此时间段,请修改MQ队列管理器属性消息标记浏览间隔(MARKINT)。
MQ将消息的详细信息传递到激活规范后,将启动5秒钟计时器。 在这5秒钟内:
- 激活规范必须从服务器会话池中获取服务器会话。
- 必须在服务器会话中加载要处理的消息的详细信息。
- 必须安排工作。
- 工作经理必须启动工作请求。
从WMQJCAResourceAdapter线程池获取服务器会话或线程时可能会发生延迟。 或者,如果系统繁忙,则工作管理器可能需要很长时间来安排工作。 MQ传递消息的详细信息与实际使用之间的时间可能超过5秒。 在这种情况下会发生什么?
好吧,如果消息在队列中的时间超过5秒钟,则队列管理器将取消标记该消息,然后可以自由地使用另一个激活规范或侦听器端口来获取消息。 如果发生这种情况,当先前获得有关此消息详细信息的服务器会话尝试获取它时,它将发现该消息不再位于目标位置,并将以下消息写入应用程序服务器SystemOut.log中:
CWSJY0003W: JMSCC0108: WebSphere classes for JMS attempted to get
a message for delivery to an message listener that had previously been
marked using browse-with-mark, but the message was not there.
如果看到此消息,则有三个选项:
- 增加MQ队列管理器属性的消息标记浏览间隔(MARKINT)的值,以使激活规范有更多时间来获取消息。 如果您有多个应用程序监视相同的目标并希望快速处理消息,请考虑采用此方法,因为增加标记消息的时间将阻止其他应用程序获取消息。
- 调整应用程序服务器,以使其既不会等待服务器会话也不会等待WMQJCAResourceAdapter线程池中的线程。 为此,请增加服务器会话池和线程池的大小。 此更改意味着可以在默认的消息浏览标记间隔内处理消息,尽管在应用程序服务器中将使用更多资源,因为它将能够同时处理更多消息。
- 没做什么。 不建议使用此选项,因为激活规范将浪费时间和资源,以致于试图获取已被另一个应用程序拾取和处理的消息。
结论
本文介绍了激活规范用于从MQ队列管理器获取消息的机制。 它解释了激活规范如何创建与队列管理器的连接,以及它们用于监视JMS目的地的机制,这些目的地正在寻找合适的消息进行处理。 本文还介绍了找到合适的消息后,应用程序服务器如何安排消息的处理。