【问题标题】:singleton pattern in storm topology风暴拓扑中的单例模式
【发布时间】:2016-02-26 23:58:47
【问题描述】:

我写了一个风暴拓扑,并将它的工人数设置为 1。 所以,我认为它的所有组件都应该在同一个进程中运行。而且我想在拓扑中的多个组件之间共享一个公共对象,所以我使用单例模式: 1,我在打开唯一的 spout 时初始化单例对象。 2、然后,我通过调用getInstance()函数在其他组件中使用单例对象。

但是,我发现我会在不同的组件之间得到不同的对象。

感谢您的回复。问题的关键代码如下: 单例类代码:

public class TraceApplicationContext {
   private volatile static TraceApplicationContext instance = new TraceApplicationContext();
   private TraceApplicationContext() {

   }
   public static TraceApplicationContext getInstance() {
        return instance;
   }
}

SpoutA 类代码:

public class SpoutA extends BaseRichSpout {
    public void open(Map map, TopologyContext topologyContext, SpoutOutputCollector spoutOutputCollector) {
        TraceApplicationContext.getInstance().init();
    }
}

BoltA 代码:

public class BoltA extends BaseRichBolt {
   private static JedisCluster jedisCluster   = TraceApplicationContext.getInstance().getJedisCluster();
}

BoltB 代码:

public class BoltB extends BaseRichBolt {
   private static JedisCluster jedisCluster   = TraceApplicationContext.getInstance().getJedisCluster();
}

在SpoutA中初始化TraceApplicationContext单例对象后,查看TraceApplicationContext.getInstance().getJedisCluster()返回的对象,不为null。但是我在BoltA和BoltB中查看,TraceApplicationContext.getInstance().getJedisCluster()返回的对象为null。

有没有人遇到过同样的问题或知道这样的问题有什么问题?

请帮忙! 谢谢!

【问题讨论】:

  • 请出示一些代码,否则我们将无法提供帮助。
  • 我已经添加了我的密钥代码,请帮助。谢谢!
  • 要仔细检查的是TraceApplicationContext.class.getClassLoader() 是否在所有上下文中返回相同的类加载器实例。任何单例都只限于其类加载器,而不是整个 JVM。
  • 在storm中使用单例可能会很棘手。认为在大多数情况下,每个类加载器(每个 JVM 工作程序)都有一个单例,而不是所有集群的单例。此外,不鼓励在风暴集群中的螺栓/喷口之间共享对象(锁、线程安全、可变性......),如果可能的话,我认为最好在风暴中删除任何单例的使用。

标签: java singleton apache-storm


【解决方案1】:

如果你不能像@Jorge_B 所说的那样使用枚举,你可以在getInstance() 方法中使用同步块

public class MySingleton {
    private static volatile MySingleton instance;
    private MySingleton() { ... }
    public static MySingleton getInstance() {
        if (instance == null) {
            synchronized(MySingleton.class) {
                if (instance == null) {
                    instance = new MySingleton();
                }
            }
        }
        return instance;
    }
}

http://en.wikipedia.org/wiki/Singleton_pattern


编辑

但这可能不是单例问题

getJedisCluster() 返回不同值的事实并不意味着它不是同一个单例,而是单例的状态发生了变化

尝试在单例中设置jedisCluster final(最终属性无法更改,但必须在构造函数中初始化)

private final JedisCluster jedisCluster;

如果您无法尝试跟踪 jedisCluster 何时更改:使用 setter...

【讨论】:

    【解决方案2】:

    如果您确保所有进程都在同一个 JVM 中运行,请尝试将您的 Singleton 实现为单个元素的 Enumeration。这应该解决对象初始化的所有可能并发问题。

    例如:

    类似的实现

    public class MySingleton {
       private static MySingleton instance;
       private MySingleton() { ... }
       public static MySingleton getInstance() {
          if (instance == null) { instance = new MySingleton() }
          return instance;
       }
    }
    

    容易出现并发问题。但是,像这样的一个

    public enum MySingleton {
       INSTANCE;
    
       private MySingleton() {...}
    }
    

    应该在任何地方都可以工作。

    【讨论】:

    • +1,OPs 代码的问题是他试图在他的 spout 中调用一个 init() 方法。创建实例应该在 Singleton 内部自动处理。
    【解决方案3】:

    根据我的经验,我在我的 Storm 拓扑中使用单例 cassandra 会话对象,以及单例作为应用程序属性。 由于这些单例对象没有任何变化的状态,即使我们有多个 WorkerProcess(WP)(即每个 WP 一个 JVM),每个 WP 都会有一个单例副本并且可以毫无问题地使用。

    就最佳实践而言,最好在提交拓扑时将静态单例设置为配置对象,并且准备方法会将其提供给各个任务。

    https://groups.google.com/forum/#!topic/storm-user/rWeQpGEnT9Q

    【讨论】:

      猜你喜欢
      • 2013-08-06
      • 1970-01-01
      • 2016-08-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多