当前位置: 首页 > 知识库问答 >
问题:

使用MDB进行滚动升级

章涵蓄
2023-03-14

我们在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),也许其中一个有能力平衡远离特定消费者集的流量?

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

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

共有2个答案

越安翔
2023-03-14

我不理解你的假设,即当我们停止“旧”集群时,未完成的事务将丢失。MDB将被允许在应用程序停止之前完成消息处理,任何未确认的消息将由“新”集群处理。

如果旧版本和新版本之间的负载平衡是一个问题,我将把MDB放在单独的中。耳朵,并在新MDB上线后立即停止旧的MDB,甚至在此之前,如果您的用例允许延迟消息处理,直到部署新版本。

欧桐
2023-03-14

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

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

 类似资料:
  • SWarm mode 与滚动升级 在 部署服务 一节中我们使用 nginx:1.13.7-alpine 镜像部署了一个名为 nginx 的服务。 现在我们想要将 NGINX 版本升级到 1.13.12,那么在 Swarm mode 中如何升级服务呢? 你可能会想到,先停止原来的服务,再使用新镜像部署一个服务,不就完成服务的 “升级” 了吗。 这样做的弊端很明显,如果新部署的服务出现问题,原来的服务

  • 我试图在一个libgdx游戏中实现触摸滚动。我有一个很宽的图像,是一个房间的全景。我希望能够滚动图像,让用户可以看到房间的四周。我有它,所以我可以滚动一定的距离,但当一个新的触摸拖动事件被注册的图像被移回到原来的位置。 这就是我实现它的方式 } 在InputProcessor中 在这个问题LibGdx如何使用OrthographicCamera?滚动的帮助下,我做到了这一步?。然而,这并没有真正解

  • 问题内容: 我一直在做一个项目,内容已经完成。但是对于设计,我正在考虑使用视差滚动技术。 但是,我所能找到的全部还是JavaScript或Jquery,而我只精通CSS3。 可以仅使用CSS3(如果需要使用HTML5)而不是使用jquery插件来实现视差滚动吗?如果我能指出一些相同的教程,那就太好了。 注意:这接近于我想要产生的效果 问题答案: 要产生非常基本的视差滚动效果,下面的示例就足够了。

  • 是否可以混合事务程序化和基于注释的管理?默认情况下,@Transactional会在任何运行时进行回滚并重新抛出它。 我不想重播它,但返回可选。空()有可能吗?使用事务编程管理很容易实现:(我从Spring文档中获取了示例) 有可能以一种好的方式将它们结合起来吗?让我们说: 你认为,混合使用两种管理事务的方法是一种代码气味吗? 谢谢你。

  • PS Vita的系统软件会随着不断的升级而逐渐追加各种功能或强化安全性。请随时升级为最新版本。 身处有可使用接入点的场所时,轻触[系统升级]>[使用Wi-Fi进行升级],可通过Wi-Fi连接互联网,下载最新的升级文件。请遵循画面指示正确操作。 重要 请勿于升级时切断主机的电源或强制取出PS Vita专用存储卡。升级若遭到中断,可能会导致故障。 电池电量低时,可能无法开始升级。 升级中无法使用电源键

  • 当有镜像发布新版本,新版本服务上线时如何实现服务的滚动和平滑升级? 如果你使用ReplicationController创建的pod可以使用kubectl rollingupdate命令滚动升级,如果使用的是Deployment创建的Pod可以直接修改yaml文件后执行kubectl apply即可。 Deployment已经内置了RollingUpdate strategy,因此不用再调用kub