使用 Wildfly 的集群单例?

Posted

技术标签:

【中文标题】使用 Wildfly 的集群单例?【英文标题】:Clustered Singleton using Wildfly? 【发布时间】:2015-03-13 05:12:10 【问题描述】:

我正在尝试在 Wildfly 8.2 上创建一个简单的集群 Singleton。我配置了 2 个 Wildfly 实例,在独立集群配置中运行。我的应用已部署到两者,我可以毫无问题地访问它。

我的集群 EJB 如下所示:

@Named
@Clustered
@Singleton
public class PeekPokeEJB implements PeekPoke 

    /**
     * Logger for this class
     */
    private static final Logger logger = Logger
            .getLogger(PeekPokeEJB.class);

    private static final long serialVersionUID = 2332663907180293111L;

    private int value = -1;

    @Override
    public void poke() 
        if (logger.isDebugEnabled()) 
            logger.debug("poke() - start"); //$NON-NLS-1$
        

        Random rand = new SecureRandom();
        int newValue = rand.nextInt();
        if (logger.isDebugEnabled()) 
            logger.debug("poke() - int newValue=" + newValue); //$NON-NLS-1$
        

        this.value = newValue;

        if (logger.isDebugEnabled()) 
            logger.debug("poke() - end"); //$NON-NLS-1$
        
    

    @Override
    public void peek() 
        if (logger.isDebugEnabled()) 
            logger.debug("peek() - start"); //$NON-NLS-1$
        

        if (logger.isDebugEnabled()) 
            logger.debug("peek() - value=" + value); //$NON-NLS-1$
        

        if (logger.isDebugEnabled()) 
            logger.debug("peek() - end"); //$NON-NLS-1$
        
    

...我已经编写了一个非常简单的 RESTful 服务,让我可以通过浏览器调用这些方法...

@Path("/test")
@Named
public class TestRS extends AbstractRestService 
    /**
     * Logger for this class
     */
    private static final Logger logger = Logger.getLogger(TestRS.class);

    @Inject
    private PeekPoke ejb = null;

    @GET
    @Path("/poke")
    public void poke() 
        if (logger.isDebugEnabled()) 
            logger.debug("poke() - start"); //$NON-NLS-1$
        

        this.ejb.poke();

        if (logger.isDebugEnabled()) 
            logger.debug("poke() - end"); //$NON-NLS-1$
        
    

    @GET
    @Path("/peek")
    public void peek() 
        if (logger.isDebugEnabled()) 
            logger.debug("peek() - start"); //$NON-NLS-1$
        

        this.ejb.peek();

        if (logger.isDebugEnabled()) 
            logger.debug("peek() - end"); //$NON-NLS-1$
        
    

我能够从单个 Wildfly 实例调用 peekpoke 方法并获得预期值。但是,如果我尝试从一个实例调用 poke,然后从另一个实例中窥视,我会发现这些值没有在 EJB 之间复制。

我的印象是集群单例会在两个应用程序服务器之间复制“value”的值,无论我从哪个主机发出peek 调用,都提供相同的值。这不正确吗?有什么我遗漏的东西仍然需要添加到此代码中吗?

如果您能给我任何帮助,我将不胜感激!谢谢!

【问题讨论】:

【参考方案1】:

单例会话 bean 提供了一种正式的编程结构,保证会话 bean 将在特定的 Java 虚拟机 (JVM)每个应用程序被实例化一次。

JSR 318:Enterprise JavaBeans TM 3.1 版说:

单例会话 bean 是一个会话 bean 组件,它是 每个应用程序实例化一次。如果容器是 分布在许多虚拟机上,每个应用程序将有一个 每个 JVM 的 Singleton 的 bean 实例

因此,在集群应用程序中,每个集群成员都有自己的单例会话 bean 实例,并且数据不会在 JVM 实例之间共享(在 Wildfly 实现中)。

在 Wildfly 中,如果您在集群范围内只需要一个单例实例,您可以使用 SingletonService 实现。使用SingletonService,目标服务安装在集群中的每个节点上,但在任何给定时间仅在一个节点上启动。

见:

Implement an HA Singleton cluster-ha-singleton: A SingletonService deployed in a JAR started by SingletonStartup and accessed by an EJB

更新:

WildFly 10 增加了将给定应用程序部署为 “单例部署”。这是一项功能的新实现, 存在于 AS 6.0 及更早版本中。部署到一组集群时 服务器,单例部署将仅部署在单个节点上 任何给定的时间。如果部署处于活动状态的节点停止或 失败,部署将自动在另一个节点上启动。

见:WildFly 10 Final is now available!

【讨论】:

嗨,federico,正如您和文档中所说的 wildfly 10,“如果部署处于活动状态的节点停止或失败,部署将自动在另一个节点上启动。”我想知道,当一个节点停止或失败而另一个节点启动时,新节点是否将数据保留在旧节点中? @xxlali 根据文档:cache-container 和单例策略的缓存属性必须引用来自 Infinispan 子系统的有效缓存。如果没有定义特定的缓存,则假定缓存容器的默认缓存。此缓存用作哪些节点可以提供给定服务的注册表,并且通常会使用 replicated-cache 配置。

以上是关于使用 Wildfly 的集群单例?的主要内容,如果未能解决你的问题,请参考以下文章

Wildfly 集群设置问题

在 Wildfly 10.1 中禁用 Infinispan 集群

集群 Wildfly 抛出 java.lang.IllegalAccessError

如何禁用 Wildfly 9.0.2 尝试序列化集群应用程序中的某些类

Wildfly 8,远程调试应用

在 Wildfly/Jboss 中部署 ear 期间如何防止 HTTP 404