随着Internet服务的发展,其分布越来越广泛,这使得企业消息传递逐渐成为Web应用基础架构最重要的部分之一。应用程序可以在短时间内传输大量的消息,而且通常传输的数据是底层的业务流程非常必需的。
但是,无论这些数据有多么重要,很多企业应用程序的配备不足以使它们在碰到常见的消息传递问题时恢复正常。当然,消息可以保存在数据存储区中,但系统经常缺少可靠且足够灵活的监控和治理机制——像失败消息的适当处理这么重要的功能也可能被忽略掉。
本文将从治理的角度讨论WebLogic消息传递和Java消息服务(Java Message Service,JMS)。我们将看看如何给予业务要害型消息以应有的关注,以及如何使用治理工具确保应用程序的消息流顺畅无阻。
企业应用程序中介体
企业消息传递基本上全是异构系统间的数据交换,是一种计算机间通信形式,它始终都需要专门的措施以确保其成功运行。假如缺少某种中介体,那么维护跨网络的进程间通信会非常困难,因此我们使用诸如WebLogic JMS之类的面向消息中间件(message-oriented-middleware,MOM)系统来为我们解决保证交付、消息通知以及其他所有的固有复杂问题。可以将MOM视为企业应用程序的邮政服务。
Weblogic JMS是一种高度可靠的服务,假如它对已发送的消息做出确认,那么用户就完全可以确信该消息已被接收。但是,确切地说,保证就到此为止了;客户端应用程序(消息生产者)无法了解接收端应用程序(消息消费者)是否已成功地处理了该消息,除非用户实现自己的确认系统。
假如存在问题,那到底是什么问题呢?
只要两台计算机进行通信,那么迟早会出现故障。无法访问子系统、网络故障、消息溢出、死锁等等,这些全是用户可能碰到的一些常见问题。不要试图保证永远不会发生故障,而是要确保做好应对故障的预备。需要针对每一种处理失败的情况找出其各自的纠正措施。通过自动重试可以很轻易地修复某些问题(如:子系统忙),而另外一些问题则需要人工干预。况且,许多服务不支持任何形式的重新处理或错误处理等,这使得故障恢复必须由客户端应用程序来完成。
我们假设:用户的业务模型将首先使用户尽一切可能处理消息,不行的话才会放弃并向客户端应用程序发出否定确认。在这种情况下,用户可能要自动重试几次处理;若无效,那么应有人能够对失败消息做人工检查。现在来看一种在实践中达成此目的的常见方法。
消息治理的两种方法
一种非常健壮的消息治理技术是将全部的失败消息发送至一个错误队列,并让消费者将其包括的数据和属性保存到一个数据库中。随后,治理员会对该消息进行分析,并选择是否要重新创建消息,然后再次发送。使用数据库来存储消息使得数据具有高度完整性且操作方便。下面是该实现所需的主要步骤:
1.在config.XML文件中为目的地配置一个持久性错误队列。错误队列又称为死消息队列,失败消息将被自动发送到这个常规JMS目的地。通过在用户的当前目的地(active destination)中添加ErrorDestination参数可将消息定向至错误队列。
2.为错误队列配置消费者,通过使用javax.jms.Message类的Accessor方法使其读取已存储的失败消息的数据和属性。
3.将恢复性数据与消息的原始目的地名称一起保存到一个数据库表格中。可以通过使用Message类的getJMSDestination()方法获得原始目的地。
4.编写几个方法,以便从数据库读取数据,显示数据,通过根据已保存的数据重新创建消息、并将其发送至原始目的地,从而提供重新发送消息的选择。
完成上述步骤后,就可以得到一个非常灵活的治理消息传递问题的系统。该实现需要大量的工作,但是假如用户熟悉JMS并了解其基本知识,那么执行起来就十分简单。虽然这种解决方案非常不错并且经常被使用,但是还有一种更易于实现的方法,它无需使用数据库,并且可以为用户提供额外的好处,即,可以使用户在运行时看到任何队列的内容。
用于浏览队列的QueueBrowser
JMS API中包括支持全面访问排队消息的工具。下面要讨论的工具是javax.jms.AueueBrowser接口及消息选择器(message selector)。QueueBrowser是一种可在给定队列中检索消息而不消费这些消息的接口。它可返回全部消息,在消息选择器的帮助下还可以返回全部消息的一个子集。
另一种可供选择的队列治理方法是使用消极错误队列来存储失败消息,并使用QueueBrowser列出这些失败消息。然后可挑选出单个消息,对其进行重新发送、复制或删除操作。
下文是关于开发简单的处理失败消息的队列治理系统的分步说明:
在config.xml文件中为目的地配置持久性错误队列。不需要为错误队列配置或编写任何消费者。
使用QueueBrowser接口显示错误队列中的全部消息。对队列中消息的浏览非常简单,只需编写几行代码即可实现(见清单)。
清单1:浏览队列内容
public Enumeration getQueuedMessages(
javax.jms.QueueSession qSession,
javax.jms.Queue queue)
throws javax.jms.JMSException
{
javax.jms.QueueBrowser browser =
qSession.createBrowser(queue);
return browser.getEnumeration();
}