内容


WebSphere Application Server V8.x 如何处理有害消息

Comments

简介

IBM WebSphere Application Server Version 8 及更高版本 (V8.x) 根据 Java™ Message Service (JMS) 版本 1.1 规范为异步消息提供支持。无论是使用默认消息提供程序还是 IBM WebSphere MQ,您都可以编写消息驱动 bean(MDB),用于监听的地(消息队列或主题)。当消息到达目的地时,将会调用 MDB,并调用它的 onMessage() 方法。如果 “有害消息” 被传递给某个 MDB,应用程序可以选择拒绝它。

在这种情况下,消息会发生什么情况,应用程序服务器有何行为?

什么是有害消息?

有害消息只是一个接收方 MDB 应用程序无法处理的消息。出现这种情况可能是因为该消息已被损坏,使用了意想不到的格式,或者包含 MDB 的业务逻辑无法处理的信息。例如,假设有一个处理书籍订单的 MDB。如果 MDB 收到一本书的订单,但这本书并不存在,那么可以认为该消息是有害消息。

如果有害消息被传递给某个 MDB,bean 可以执行以下三种操作之一:

  • 将消息回滚到它的来源。

    如果 MDB 在一个事务内运行,而且可以消息没有丢失,那么可以实现回滚。将消息返回到其原始目的地,让 MDB 有机会再次处理该消息。如果应用程序由于暂时性的问题(比如数据库不可用)而无法处理消息,这种方法就会很有用。为了回滚消息,MDB 应该对与 bean 相关的消息驱动的上下文调用 setRollbackOnly() 方法。

  • 将消息移动到不同的目的地。

    这种方法对于 MDB 不在事务内运行的情况特别有用,因为它可以防止有害消息丢失。系统管理员可以在稍后的某个时间检查该消息,了解它为什么不能被处理,并有可能将其移回由 MDB 监控的目的地,以便可以重新处理它。

  • 什么都不做,丢弃消息。

    这意味着将永远失去该消息。

确定是否收到有害消息,以及应该如何处理它,这是 MDB 应用程序的责任。JMS 提供程序或应用程序服务器无法确定消息是否损坏或无法处理。

回滚有害消息

在事务内部运行的 MDB 可以选择回滚不能处理的消息。应用程序服务器在这种情况下应该做些什么?答案取决于正在使用什么 JMS 提供程序。

使用默认消息提供程序

MDB 被配置为使用默认消息提供程序监视由服务集成总线托管的队列或主题空间。当消息到达队列或被发布到主题上时,它们就被传递给 MDB。当 MDB 回滚消息时,应用服务器的行为取决于三个属性的值:

  • JMS 消息属性 Redelivery count 指示 JMS 消息已被传递给应用程序的次数。如果 MDB 在传递后拒绝消息,此属性将会递增。
  • JMS 目的地属性 Maximum failed deliveries 指定消息在一个目的地上被传递给 MDB 的次数,如果超过此次数,那么该消息将被移动到为此目的地定义的异常目的地。该属性的默认值是 5,这意味着如果一个消息被回滚五次,那么应用服务器就会将它移动到不同的位置。可以在 WebSphere Application Server 管理控制台的目的地配置面板上修改这个属性(图 1)。
图 1. TestDestination 的 Maximum failed deliveries 属性
TestDestination 的 Maximum failed deliveries 属性
TestDestination 的 Maximum failed deliveries 属性

JMS 目的地属性 Exception destination 告诉应用服务器如何处理那些被回滚次数已超过 Maximum failed deliveries 属性中所指定次数的有害消息。Exception destination 属性可以使用以下三个值之一:

  • System:将消息路由到系统异常目的地 _SYSTEM.Exception.Destination.<messaging engine name>
  • None:将消息保留在原始目的地。
  • Specify:将消息移动到用户指定的异常目的地。

此属性的默认值是 System,回滚次数超过 Maximum failed deliveries 的任何消息都会被移动到为托管目的地的消息引擎所定义的系统异常目的地。像 Maximum failed deliveries 属性那样,通过 WebSphere 管理控制台的目的地配置面板可以修改 Exception destination 属性(图 2)。

图 2. TestDestination 的 Exception destination 被设置为 "System"
TestDestination 的 Exception destination 被设置为 'System'
TestDestination 的 Exception destination 被设置为 'System'

如果 Exception destination 属性被设置为 “None”,那么,在默认情况下,应用程序服务器将查看消息引擎属性 Default blocked destination retry interval 的值来决定要等待多长时间才重新将有害消息传递给 MDB。该属性的默认值是 5000 毫秒,相当于 5 秒。

图 3. 默认的受阻目的地重试间隔
默认的受阻目的地重试间隔
默认的受阻目的地重试间隔

通过设置两个 JMS 目的地属性,可以为每个 JMS 目的地改写这个时间长度:

  • 必须选中 Override messaging engine blocked retry timeout default
  • 需要将 Blocked retry timeout in milliseconds 设置为 0 或大于 0 的值。该属性的默认值为 -1,这意味着,如果复选框 Override messaging engine blocked retry timeout default 被选中,那么有害消息将永远不会被重新传递。将属性值设置为 0 则表示,任何回滚的消息都将被立即重新传递给 MDB。
图 4. TestDestination 的 Blocked retry timeout in milliseconds 被设置为 10000 毫秒(即 10 秒)
TestDestination 的 Blocked retry timeout in milliseconds 被设置为 10000 毫秒(即 10 秒)
TestDestination 的 Blocked retry timeout in milliseconds 被设置为 10000 毫秒(即 10 秒)

当一个消息被回滚,其 Redelivery count 将会递增,并与消息的原始目的地的 Maximum failed deliveries 值进行比较。

如果 Redelivery count 小于 Maximum failed deliveries,那么消息将被返回目的地,以便可以得到重新处理。

如果 Redelivery count 等于或大于 Maximum failed deliveries,那么消息引擎会将消息移动到所指定的 Exception destination,或者,如果 Exception destination 被设置为 None,消息引擎会等待 sib.processor.blockedRetryTimeout 所指定的时长,然后尝试再次传递消息。该行为如图 5 所示。

图 5. 默认消息提供程序如何处理有害消息
默认消息提供程序如何处理有害消息
默认消息提供程序如何处理有害消息

默认行为

在默认情况下,Maximum failed deliveries 属性的值为 5,Exception destination 被设置为 System。如果使用这些默认值,当有害消息到达目的地,然后被传递给一个​​ MDB 时,将会发生什么?

  1. 由于 MDB 无法处理消息,所以它会回滚消息,这会导致 Redelivery count 增加至 1。消息引擎将消息返回给目的地,因为 Redelivery count 小于目的地的 Maximum failed deliveries。
  2. MDB 将再次收到消息,但仍然无法处理它,所以 MDB 像之前一样执行回滚。消息的 Redelivery count 现在被设置为 2,该值仍小于目的地的 Maximum failed deliveries,所以消息引擎将消息送回它的来源。
  3. 这种模式一直重复到消息被回滚了 5 次。
  4. 现在,Redelivery count 的值与目的地的 Maximum failed deliveries 相同。消息引擎没有将消息返回到其原始目的地,而是将消息移动到该目的地的异常目的地,它被指定为 _SYSTEM.Exception.Destination.<messaging engine name>

使用 WebSphere MQ 消息提供程序

WebSphere MQ 消息提供程序的 MDB 可以使用激活规范或监听端口来监测 WebSphere MQ 所托管的队列或主题。当一个消息被放到一个队列上,或被发布到一个特定的主题上,该消息就有可能被激活规范或监听端口检测到,并传递给 MDB。

当一个 MDB 回滚一个消息时,应用服务器的行为是不同的,具体行为取决于 MDB 是绑定到激活规范还是监听端口。

激活规范

如果 MDB 被配置为使用激活规范来回滚消息,那么应用服务器的行为将取决于以下五个属性:

  • 前两个属性是:
    • Stop endpoint if message delivery fails
    • Number of sequential delivery failures before suspending endpoint

    它们是激活规范的高级属性,相互配合使用,以便确定消息被回滚后激活规范是否应该停止。

    属性 Stop endpoint if message delivery fails 是一个复选框。在选中该属性时,激活规范将保持已经由使用它的 MDB 执行的回滚次数的计数。当一个消息被回滚时,回滚计数器就会增加 1。当一个消息被 MDB 成功处理时,回滚计数器将被重置为零。

    如果回滚计数器到达了 Number of sequential delivery failures before suspending endpoint 属性所指定的值,那么激活规范将会停止。

    在默认情况下,Stop endpoint if message delivery fails 复选框将被选中,而且 Number of sequential delivery failures before suspending endpoint 属性的值为 0。这意味着,只要 MDB 回滚一个消息,激活规范就会停止。可以在 WebSphere 管理控制台中该激活规范的 Advanced properties 面板上修改这些属性(参见图 6)。

    图 6. TestActivationSpec 的 Stop endpoint if message delivery fails 和 Number of sequential delivery failures before suspending endpoint 属性
    TestActivationSpec 的 Stop endpoint if message delivery fails 和 Number of sequential delivery failures before suspending endpoint 属性
    TestActivationSpec 的 Stop endpoint if message delivery fails 和 Number of sequential delivery failures before suspending endpoint 属性
  • JMS 消息属性 Redelivery count 指示 JMS 消息已被传递给应用程序的次数。如果 MDB 在传递后拒绝消息,此属性将会递增。
  • WebSphere MQ 队列属性 Backout threshold (BOTHRESH) 指定了在将消息移动到不同的位置之前可以将它放到队列中的最大次数。此属性的默认值是 0,这意味着激活规范将永远不会尝试让 MDB 回滚的消息重新排队。属性 Backout threshold 的值可以使用 WebSphere MQ 命令行实用程序 runmqsc 进行设置,或者在 WebSphere MQ Explorer 的 Queue Properties 面板上设置(图 7)。
    图 7. 测试队列的 Backout threshold 属性
    测试队列的 Backout threshold 属性
    测试队列的 Backout threshold 属性
  • WebSphere MQ 队列属性 Backout requeue queue (BOQNAME) 是当消息被回滚到队列上的次数达到在 Backout threshold 属性中所指定的次数时,该消息被移动到的队列位置。Backout requeue queue 没有默认值,这意味着应用服务器会将超出 Backout threshold 的所有消息都移动到 SYSTEM.DEAD.LETTER.QUEUE。使用 WebSphere MQ 实用程序 runmqsc,或 WebSphere MQ Explorer 可以设置 Backout requeue queue 属性。Queue Properties 面板如图 8 所示。
    图 8. 测试队列的 Backout requeue queue 属性被设置为 SYSTEM.DEAD.LETTER.QUEUE
    测试队列的 Backout requeue queue 属性被设置为 SYSTEM.DEAD.LETTER.QUEUE
    测试队列的 Backout requeue queue 属性被设置为 SYSTEM.DEAD.LETTER.QUEUE

    当激活规范检测到 JMS 目的地上的消息,它要做的第一件事就是比较该消息的 Redelivery count 与队列的 Backout threshold 的值。如果 Redelivery Count 小于 Backout threshold,那么消息将被传递给 MDB 进行处理。但是,如果 Redelivery count 等于 Backout threshold,那么 WebSphere MQ 消息提供程序会将消息移动到 Backout requeue queue 上。如果没有定义 Backout requeue queue,那么该消息将被移动到 SYSTEM.DEAD.LETTER.QUEUE。

    如果消息被传递给 MDB,然后被回滚,那么激活规范会将信息放回到消息原来的 JMS 目的地上,并递增 Redelivery count 的值。

    然后,激活规范会检查是否已经选中 Stop endpoint if message delivery fails 复选框。如果已经选中该复选框,激活规范将会递增其内部回滚计数器,并比较计数器的值与 Number of sequential delivery failures before suspending endpoint 属性的值。如果这两个值相等,那么激活规范将被停止。

    该行为如图 9 所示。

    图 9. 应用服务器在使用 WebSphere MQ JMS Provider 时如何处理有害消息
    在使用 WebSphere MQ JMS Provider 时,应用服务器如何处理有害消息
    在使用 WebSphere MQ JMS Provider 时,应用服务器如何处理有害消息

默认行为

在默认情况下,Stop endpoint if message delivery fails 复选框被选中,Number of sequential delivery failures before suspending endpoint 属性的值为 0,Backout threshold 和 Backout requeue queue 属性都没有设置值。那么,当有害消息被传递给使用激活规范来监视 WebSphere MQ 所托管的 JMS 目的地的 MDB 时,默认行为是什么?

MDB 回滚消息,这意味着该消息的 Redelivery count 将被增加到 1。现在,激活规范将检查 Stop endpoint if message delivery fails 复选框,并发现它已经被选中,所以它将递增回滚计数器。

然后,激活规范会检查 Number of sequential delivery failures before suspending endpoint 属性的值,并将它与回滚计数器的值进行比较。由于回滚计数器的值大于 Number of sequential delivery failures before suspending endpoint,激活规范将被停止。

在重新启动激活规范时,它会再次检测有害消息,并比较消息的 Redelivery count 与队列的 Backout threshold 属性的值。此属性没有值,所以消息被传递给 MDB。如果 MDB 仍然无法对其进行处理,该消息将被回滚到队列中,它的 Redelivery count 将增加到 2。激活规范将再次检查 Stop endpoint if message delivery fails 复选框,发现它被选中,并递增回滚计数器。回滚计数器现在的值为 2,该值大于 Number of sequential delivery failures before suspending endpoint 的值,所以激活规范将再次停止。

再次重新启动激活规范时,它会检测到消息,而且整个循环将重复进行。

作为这种行为的结果,最终的情况有可能是,有害消息将会阻碍队列中的其他消息的处理。

当一个消息被回滚时,它被返回到其队列上的原始位置。激活规范总是从队列的顶部开始处理消息,所以,如果在队列中的第一个消息是有害消息,那么激活规范将会检测到它,并将它传递给 MDB。由于消息无法被处理,MDB 将会回滚它,这会导致它再次回到队列的顶部。然后,激活规范将被关闭。在重新启动激活规范时,激活规范将再次检测到有害消息,并将它重新传递给 MDB。MDB 将回滚它,并再次造成激活规范停止。

修改默认行为

正如你可以看到,默认行为将持续,直到系统管理员从队列中删除有害消息。

为了防止这种情况发生,您需要执行以下操作:

  • 确保激活规范所监视的队列中已经定义了 Backout threshold 和 Backout requeue queue。
  • 或者:
    • 取消选中 Stop endpoint if message delivery fails 复选框,或
    • 保持选中 Stop endpoint if message delivery fails 复选框,并将 Number of sequential delivery failures before suspending endpoint 属性设置为大于 Backout threshold 的值。

例如,假设您已经定义了一个名为 TestActivati​​onSpecification 的激活规范,它负责监视 WebSphere MQ 队列测试的消息。该激活规范选中了 Stop endpoint if message delivery fails 复选框,并将 Number of sequential delivery failures before suspending endpoint 属性的值设置为 5。队列测试的 Backout threshold 值为 1,Backout requeue queue 的值为 SYSTEM.DEAD.LETTER.QUEUE。

当消息到达队列测试时,它将被激活规范检测到,并传递给您的 MDB。现在,假设您的 MDB 无法处理此消息并回滚它。该消息的 Redelivery count 现在被设置为 1。

WebSphere MQ 消息提供程序检查激活规范的 Stop endpoint if message delivery fails checkbox 复选框,发现它已被选中,所以回滚计数器将会递增。

然后,它会比较回滚计数器和 Number of sequential delivery failures before suspending endpoint 属性的值,该值为 5。该值大于回滚计数器的值,所以激活规范将继续运行。

在激活规范下一次检测到消息时,WebSphere MQ 消息提供程序将会检查消息的 Redelivery count,并发现它的值是 1。它现在会查看队列测试的 Backout threshold,它的值也是 1。因此,WebSphere MQ 消息提供程序决定收回消息。

WebSphere MQ 消息提供程序查询队列的 Backout requeue queue 属性。该属性被设置为 SYSTEM.DEAD.LETTER.QUEUE,所以 WebSphere MQ 消息提供程序将从测试队列中删除消息,并将它放到这个队列。

然后,激活规范将再次监控队列测试,检测到达该队列的更多消息。

Maximum server sessions 属性如何影响有害消息

激活规范高级属性 Maximum server sessions 定义了可同时处理的消息的最大数量。如果此属性的值为 10,并且在目的地上有 10 条消息被激活规范监视,那么所有 10 条消息都将在同一时间通过与激活规范有关联的一个内部服务器会话进行处理。

值得注意的地方是,如果激活规范的 Stop endpoint if message delivery fails 复选框被选中,而且 Number of sequential delivery failures before suspending endpoint 属性被设置为大于零的值,那么由该激活规范维护的回滚计数器将应用于所有服务器会话。

这意味着,如果不同的服务器会话同时回滚不同的有害消息,那么激活规范可能会停止,不再尝试将有害消息移动到回收队列。

除此之外,只要服务器会话成功地处理了被激活规范检测到的消息,激活规范的回滚计数器就会被复位到零。

例如,假设我们的激活规范 testActivati​​onSpecification:

  • Stop endpoint if message delivery fails 复选框被选中
  • Number of sequential delivery failures before suspending endpoint 属性被设置为 3。
  • Maximum server sessions 属性被设置为 5。

激活规范被配置为监视名为 test 的队列,其中 Backout threshold 属性被设置为 5,而且 Backout queue name 被设置为 SYSTEM.DEAD.LETTER.QUEUE。

在激活规范启动时,队列中有 10 条有害消息。此时会发生什么?这个问题问得很好。

激活规范检测到前五条消息,并将它们传递给五个服务器会话进行处理。

第一个服务器会话将第一个有害消息移交给一个 MDB。MDB 尝试处理它,因为无法处理该消息,所以它会将该消息回滚到队列中。消息的 Redelivery count 现在被设置为 1,并且与激活规范有关联的回滚计数器被设置为 1。

与此同时,第二个服务器会话将第二条有害消息交给相同 MDB 的另一个实例。此 MDB 实例尝试处理该消息,因为无法处理它,所以会将它回滚到队列中。此消息的 Redelivery count 现在已经设置为 1。激活规范的内部回滚计数器被设置为 2。

在进行此处理的同时,第三个服务器会话将第三条有害消息传递到另一个 MDB 实例。这个 MDB 实例也会回滚消息,因为它无法处理该消息。第三条有害消息的 Redelivery count 被设置为 1,而且更重要的是,激活规范的回滚计数器被设置为 3。

此时,WebSphere MQ 消息提供程序将会检测到,回滚计数器与激活规范的 Number of sequential delivery failures before suspending endpoint 的值相等。因此,WebSphere MQ 消息提供程序将会停止激活规范。

第 4 和第 5 条有害消息会由第四和第五个服务器会话进行处理,因为在激活规范停止前消息就已经交给了服务器会话。

在激活规范停止前,第 6 和第 7 条有害消息也有可能已经被处理。这是因为第一和第二个服务器会话回滚第 1 和第 2 条有害消息后,第 6 和第 7 条有害消息就马上被传递给这两个服务器会话。

为了改变这种行为,并确保激活规范始终试​​图将有害消息移动到指定的回收队列,而不是停止激活规范,所以需要确保 Stop endpoint if message delivery fails 复选框未被选中。

监听端口

自 WebSphere Application Server V5 开始已提供了监听端口,而且监听端口为 MDB 监视 JMS 目的地的消息提供了一种替代机制。监听端口的行为自 WebSphere Application Server V6.1 以来没有发生过改变,并且自 WebSphere Application Server V7 起已经很稳定,这意味着它们有一段时间没有添加新功能了。

这意味着在 developerWorks 文章《WebSphere Application Server V6 如何处理有害消息》中有关监听端口的信息对于 WebSphere Application Server V8 及更高版本仍然有效。

WebSphere MQ 安全考虑因素

被问得相当多的一个问题是:

我的 WebSphere Application Server 系统需要哪些 WebSphere MQ 授权才可以回收消息?

为了让 WebSphere Application Server 可以回收消息,运行应用程序服务器的用户 ID 需要拥有回收重新排队队列的以下权限:

  • Get
  • Inquire
  • Pass All Context
  • Put
  • Set All Context

如果应用服务器没有这些权限,那么应用服务器会将消息移动到为队列管理器定义的死信队列。

在 z/OS 上使用 WebSphere MQ 提供程序

在 z/OS® 上使用 WebSphere MQ JMS 提供程序处理有害消息的处理方式与上面的描述相同,但有一个细微的差别。

WebSphere MQ 在 z/OS 上使用了消息的内存中副本。在监听端口第一次检测到一个消息时,WebSphere MQ 将其副本存储在内存中,然后再将它传递给应用服务器。如果消息被成功处理,那么内存中的副本将被删除,并从存储中删除实际的消息。

在 MDB 回滚消息的情况下,WebSphere MQ 将递增内存中副本的 Redelivery count。然后,应用服务器将会查看该副本的这个属性值,以确定实际的消息是否应该被移动到 Backout requeue queue,以及是否应当停止监听端口。如果内存中副本的 Redelivery count 值大于 Backout threshold,那么实际的消息将被移动到 Backout requeue queue,并且内存中副本将被删除。

如果 WebSphere MQ 系统在消息被回收之前已经停止,那么这样做是有意义的。

假设您已经定义了一个激活规范,名称为 TestActivati​​onSpec2。激活规范被配置为监视 WebSphere MQ 队列 test2 的消息,并在 10 次连​​续传递失败后停止。该队列由 z/OS 上运行的一个 WebSphere MQ 队列管理器托管,并将 Backout threshold 属性设置为5:

消息到达队列中,并被 TestActivati​​onSpecfication2 检测到。然后会生成该消息的副本,并将该副本传递给一个 MDB。不过,由于 MDB 不能处理该消息,所以将其回滚。该消息的内存中副本的 Redelivery count 将会递增,现在其值为 1。

激活规范再次检测到消息,再一次将它传递给 MDB,然后 MDB 第二次回滚消息。该消息的内存中副本的 Redelivery count 值现在为 2。

假设 z/OS 队列管理器此时已关闭。由于应用服务器只处理消息的内存中副本,所以存储在队列中的实际消息的 Redelivery count 仍被设置为 0。当队列管理器重新启动后,激活规范将再次检测到消息。此时将会生成该消息的一个新的内存中副本,其 Redelivery count 值为 0。当 MDB 回滚消息时,该副本的 Redelivery count 的值将被递增到 1。

这种行为一直持续到 MDB 将消息回滚了 5 次。此时,应用服务器确定消息的内存中副本的 Redelivery count 等于队列的 Backout threshold,并将实际的消息移动到由 Backout requeue queue 属性指定的队列。

在这种场景中,有害消息在被回收前其实已经被处理了七次,大于为队列所定义的 Backout threshold。

这种行为是不理想的。

为了防止这种情况发生,在 z/OS 上的 WebSphere MQ 需要被配置为:在发生回滚时,要同时更新存储器中的实际信息和内存中副本的 Redelivery count。这意味着 Redelivery count 值将被保存,因此可以在队列管理器重新启动后仍然保持不变。为此,需要将 MDB 监视的队列的 HardenGetBackout (HNDBKTCNT) 属性设置为 YES。

结束语

本文介绍了什么是有害消息,并解释了 JMS 应用程序在遇到有害消息时可以做些什么。您还学习了默认消息提供程序和 WebSphere MQ JMS 提供程序如何处理 MDB 回滚有害消息的情况,如何修改默认行为,以及在使用 WebSphere MQ JMS 提供程序时,某些监听端口属性如何影响应用服务器的行为。


相关主题


评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=WebSphere
ArticleID=984014
ArticleTitle=WebSphere Application Server V8.x 如何处理有害消息
publish-date=09232014