2

我们在 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++ 生产者)。但是,使用消息驱动 Beans 我看不到如何在不中断服务的情况下升级应用程序?

我调查的选项是:

单个远程 JMS 队列 (openMQ)

生产者将消息发送到单个消息队列,消息由 MDB 处理。当我们启动第二个集群实例时,消息应该负载均衡到升级后的集群,但是当我们停止“旧”集群时,未完成的事务将会丢失。

我考虑在升级期间使用 JMX 禁用该消息队列的生产者/消费者,但这只会暂停消息传递。当我们禁用旧集群时,未完成的消息仍然会丢失(我认为?)。

我还考虑放弃 @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 队列

  • 客户端必须连接到两个不同的消息队列代理(每个集群一个)。
  • 必须通知客户端集群实例正在关闭并停止向该代理上的队列发送消息。
  • 通常比现有的 http 解决方案更不方便和整洁。

替代消息队列提供程序

  • 将 Glassfish 连接到不同类型的消息队列或不同的供应商(例如 Apache OpenMQ),也许其中一个能够平衡来自特定消费者集的流量?

我假设只是禁用应用程序只会“杀死”任何未完成的交易。如果禁用应用程序允许现有事务完成,那么我可以在启动第二个集群后执行此操作。

任何帮助,将不胜感激!提前致谢。

4

2 回答 2

0

如果您使用高可用性,则集群的所有消息都将存储在单个数据存储中,而不是每个实例上的本地数据存储中。然后,您可以将两个集群配置为使用同一个存储。然后,当关闭旧的并启动新的时,您可以访问所有消息。

这是一个很好的视频,有助于解释 glassfish 的高可用性 jms。

于 2012-06-15T16:19:47.903 回答
0

我不明白您的假设,即当我们停止“旧”集群时,未完成的交易将会丢失。MDB 将被允许在应用程序停止之前完成它们的消息处理,并且任何未确认的消息将由“新”集群处理。

如果新旧版本之间的负载平衡是一个问题,我会将 MDB 分开.ear并在新 MDB 上线后立即停止旧 MDB,或者甚至在此之前,如果您的用例允许延迟消息处理直到新版本上线部署。

于 2012-06-20T21:50:01.943 回答