java - 使用 MDB 进行滚动升级

标签 java jakarta-ee glassfish

我们在 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 .我们经常对应用程序进行重大更改,这使得新版本“不兼容”(这就是我们使用两个集群的原因)。

我们现在必须为应用程序提供一个消息队列接口(interface),以实现一些高吞吐量的内部消息传递(来自 C++ 生产者)。但是,使用消息驱动的 Bean,我看不出如何在不中断任何服务的情况下升级应用程序?

我研究过的选项是:

单个远程 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),也许其中之一能够平衡来自一组特定消费者的流量?

我假设仅禁用该应用程序将“杀死”所有未完成的交易。如果禁用该应用程序允许完成现有事务,那么我可以在启动第二个集群后这样做。

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

最佳答案

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

这很好video这有助于解释 glassfish 的高可用性 jms。

关于java - 使用 MDB 进行滚动升级,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11053694/

相关文章:

java - 如何使用相同类型的对象创建对象

java - Android ArrayList 奇怪的空指针异常

java - 如何更改我的导航栏的颜色

java - 我可以同时使用 Eclipse 和 GlassFish 吗?

deployment - 我如何在 glassfish 中使用共享库来避免部署巨大的库?

java - org.glassfish.deployment.common.DeploymentException : LLog;

java - 如何为 Java 程序创建 MSI Windows 安装程序?

java - 如何在 Hibernate 中形成这个复杂的查询?

java - BufferedReader.readLine()不读取并挂起系统

java - 使用 hibernate 的 JPA 2 标准查询无法左连接