我们在Glassfish 3.1.2集群上部署了一个Java EE应用程序,该集群使用JAX-RS提供REST API。我们通过将EAR部署到重复的集群实例来定期部署新版本的应用程序,然后更新HTTP负载均衡器以将流量发送到更新的实例而不是旧实例。
这使我们可以在不损失可用性的情况下进行升级,如下所述:http://docs.oracle.com/cd/E18930_01/html/821-2426/abdio.html#abdip。我们经常对应用程序进行重大更改,这使得新版本“不兼容”(这就是我们使用两个集群的原因)。
我们现在必须为应用程序提供消息队列接口,以实现某些高吞吐量内部消息传递(来自C ++生产者)。但是,使用Message Driven Beans我看不出如何在没有任何服务中断的情况下升级应用程序?
我调查的选项是:
单个远程JMS队列(openMQ)
生产者将消息发送到单个消息队列,消息由MDB处理。当我们启动第二个集群实例时,应该将消息负载平衡到升级后的集群,但是当我们停止“旧”集群时,未完成的事务将会丢失。
我考虑过使用JMX在升级过程中禁用生产者/消费者到该消息队列,但这只会暂停消息传递。当我们禁用旧群集时,Oustanding消息仍会丢失(我认为?)。
我还考虑过抛弃@MessageDriven注释并手动创建MessageConsumer。这看起来确实有效,但MessageConsumer无法使用EJB注释访问其他EJB(据我所知):
// Singleton bean with start()/stop() functions that
// enable/disable message consumption
@Singleton
@Startup
public class ServerControl {
private boolean running=false;
@Resource(lookup = "jms/TopicConnectionFactory")
private TopicConnectionFactory topicConnectionFactory;
@Resource(lookup = "jms/MyTopic")
private Topic topic;
private Connection connection;
private Session session;
private MessageConsumer consumer;
public ServerControl()
{
this.running = false;
}
public void start() throws JMSException {
if( this.running ) return;
connection = topicConnectionFactory.createConnection();
session = dbUpdatesConnection.createSession(false, Session.DUPS_OK_ACKNOWLEDGE);
consumer = dbUpdatesSession.createConsumer(topic);
consumer.setMessageListener(new MessageHandler());
// Start the message queue handlers
connection.start();
this.running = true;
}
public void stop() throws JMSException {
if( this.running == false ) return;
// Stop the message queue handlers
consumer.close();
this.running = false;
}
}
// MessageListener has to invoke functions defined in other EJB's
@Stateless
public class MessageHandler implements MessageListener {
@EJB
SomeEjb someEjb; // This is null
public MessageHandler() {
}
@Override
public void onMessage(Message message) {
// This works but someEjb is null unless I
// use the @MessageDriven annotation, but then I
// can't gracefully disconnect from the queue
}
}
每个群集的本地/嵌入式JMS队列
备用邮件队列提供程序
我假设只是禁用应用程序只会“杀死”任何未完成的交易。如果禁用应用程序允许现有事务完成,那么我可以在启动第二个集群后执行此操作。
任何帮助将不胜感激!提前谢谢。
答案 0 :(得分:0)
如果使用高可用性,则群集的所有消息都将存储在单个数据存储中,而不是每个实例上的本地数据存储。然后,您可以将两个群集配置为使用同一个存储。然后,当关闭旧的并启动新的时,您可以访问所有消息。
这是一个很好的video,有助于解释glassfish的高可用性jms。
答案 1 :(得分:0)
我不明白你假设当我们停止“旧”群集时,未完成的交易将会丢失。在应用程序停止之前,MDB将被允许完成其消息处理,并且任何未确认的消息将由“新”集群处理。
如果旧版本和新版本之间的负载均衡存在问题,我会将MDB放入单独的.ear
并在新MDB联机时立即停止旧MDB,或者甚至在此之前,如果您的用例允许延迟在消息处理中,直到部署新版本。