ZeroMQ多线程:按需创建套接字还是使用套接字对象池?

时间:2013-05-20 22:49:02

标签: java multithreading sockets connection-pooling zeromq

我正在构建一个利用ZeroMQ N-to-N发布/订阅模型的POC。从我们的应用服务器,当服务http请求时,如果线程从数据库中提取数据,它将使用该数据更新本地memcache实例。为了同步应用服务器集群中的其他memcache实例,请求线程使用ZMQ发布者发送带有数据的消息...所以问题是:关于最小化套接字的最有效的策略当应用程序有许多依赖于套接字发送消息的线程时,创建/目标开销?我们是否共享一个套接字池,我们是否为每个线程创建/销毁套接字等?

策略1 - 线程管理的Publisher套接字
在这种方法中,每个线程T1T2T3通过创建它,建立连接,发送消息,最后管理套接字对象(发布者)的生命周期。关闭套接字。基于this,它肯定是最安全的方法,但我们担心在重复创建,连接和销毁套接字时的开销;如果开销对性能产生负面影响,我们希望避免它。

enter image description here

策略2 - 发布者套接字对象池
在此方法中,父进程(app server)在启动时初始化ZMQ发布者池。当一个线程需要一个发布者时,它从对象池中获取一个,发送它的消息,然后将发布者返回到池中;对于使用发布者的线程,消除了创建,连接和销毁套接字的过程,但访问池是同步,以避免任何两个线程同时使用相同的发布者对象,并且这就是可能出现死锁和并发问题的地方。

我们没有描述任何一种方法,因为我想先在SO测试上做一个石蕊。关于卷,我们的应用程序不发布“重”,但可能有100-150个线程(每个应用服务器)同时需要发布消息。

ZMQ Publisher Object Pool

所以,重申一下:最有效的策略是什么策略最小化开销,同时在应用程序有很多依赖于发布者发送消息的线程时强调性能?

2 个答案:

答案 0 :(得分:3)

如果没有提供估算吞吐量的实际数据,您无法真正询问有关性能的问题。我们是在谈论每秒10个请求,100,1,000,10K?

如果HTTP服务器实际上正在为每个请求创建和销毁线程,那么重复创建0MQ套接字会对操作系统造成压力,并且取决于请求量和进程限制,它会起作用,或者它将耗尽处理。你可以轻松地测试这个,这是第一步。

然后,共享一个套接字池(你的意思是“ZMQ发布者”)是令人讨厌的。人们这样做,但套接字线程安全,所以当你将套接字切换到另一个线程时,这意味着非常小心。

如果有一种方法可以保持线程的持久性,那么每个线程都可以在需要时创建它的PUB套接字,只要它存在就保持它。如果没有,那么我的第一个设计无论如何都会创建/销毁套接字,但是使用inproc://将消息发送到单个永久转发器线程(SUB-PUB代理)。我会对此进行测试,然后如果它破裂,请选择更具异国情调的设计。

一般来说,制作最简单的设计并打破它,比过度思考设计过程(特别是在开始时)更好。

答案 1 :(得分:1)

这听起来对我来说也是过早的优化,如果可能的话,你应该坚持第一个策略并避免头痛。

但作为第二个选项的替代方法,您可以在应用程序中维护一个Executor线程池来执行实际的zmq发送。这样每个执行程序线程都可以保留自己的套接字。您可以监听应用程序/ servlet生命周期事件,以了解何时关闭池并清理套接字。

编辑:

执行此操作的最简单方法是使用Executors.newFixedThreadPool()创建Executor,并为其提供使用ThreadLocal套接字的Runnable作业。 (参见Java Executors and per-thread (not per-work unit) objects?)线程将只创建一次,然后重复使用,直到Executor关闭。

当作业的run()方法抛出异常时,这会有点棘手。我怀疑你会发现你需要对执行程序线程的生命周期有更多的控制。如果是这样,您可以复制newFixedThreadPool的来源:

return new ThreadPoolExecutor(nThreads, nThreads,
                              0L, TimeUnit.MILLISECONDS,
                              new LinkedBlockingQueue<Runnable>());

并将实例化的ThreadPoolExecutor子类化为自定义它。这样您就可以覆盖afterExecute以检测并清理损坏的套接字。

发送作业通过阻塞队列传输到工作线程。我意识到这不是将消息传递给工作线程的ZeroMQ方法,这将是inproc消息传递。这使ZeroMQ远离HTTP工作线程,这些线程的生命周期超出了您的控制范围,因此难以维护套接字,更多地是朝向应用程序的边缘。您必须简单地测试两者中哪一个更有效,并且必须判断您希望应用程序如何严格地采用ZeroMQ消息传递范例进行线程间通信。