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

Java ZeroMQ多线程:按需创建套接字还是使用套接字对象池?,java,multithreading,sockets,connection-pooling,zeromq,Java,Multithreading,Sockets,Connection Pooling,Zeromq,我正在构建一个利用ZeroMQ N-to-N发布/订阅模型的POC。在我们的应用服务器上,当http请求得到服务时,如果线程从数据库中提取数据,它会用该数据更新本地memcache实例。要同步app server群集中的其他memcache实例,请求线程使用ZMQ发布器发送包含数据的消息……因此问题是:当应用程序有许多线程依赖套接字发送消息时,在最小化套接字创建/破坏开销方面,什么策略最有效?我们是否共享一个套接字池,是否为每个线程创建/销毁套接字,等等 策略1-线程管理的发布服务器套接字 在这

我正在构建一个利用ZeroMQ N-to-N发布/订阅模型的POC。在我们的应用服务器上,当http请求得到服务时,如果线程从数据库中提取数据,它会用该数据更新本地memcache实例。要同步app server群集中的其他memcache实例,请求线程使用ZMQ发布器发送包含数据的消息……因此问题是:当应用程序有许多线程依赖套接字发送消息时,在最小化套接字创建/破坏开销方面,什么策略最有效?我们是否共享一个套接字池,是否为每个线程创建/销毁套接字,等等

策略1-线程管理的发布服务器套接字
在这种方法中,每个线程,
T1
T2
T3
,通过创建套接字对象(发布者)、建立连接、发送消息并最终关闭套接字来管理其生命周期。基于此,这当然是最安全的方法,但我们担心重复创建、连接和销毁套接字时的开销;如果开销对性能有负面影响,我们希望避免它

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

我们没有分析这两种方法,因为我们想先做一个关于SO测试的试金石。就数量而言,我们的应用程序不会发布“重”,但可能会有100-150个线程(每个应用服务器)同时需要发布消息


因此,重申一下:当应用程序有许多线程依赖发布者发送消息时,在最小化开销的同时强调性能方面,哪种策略最有效?如果不提供估计吞吐量的真实数字,就无法真正问到性能问题。我们说的是每秒10个请求,100100010K吗

如果HTTP服务器真的在为每个请求创建和销毁线程,那么重复创建0MQ套接字将给操作系统带来压力,并且取决于请求量和进程限制,它会工作,或者会耗尽句柄。您可以简单地测试这一点,这是第一步

然后,共享一个套接字池(你所说的“zmqpublisher”)是令人讨厌的。人们会这样做,但套接字不是线程安全的,所以在将套接字切换到另一个线程时要非常小心

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


一般来说,最好是做出最简单的设计并打破它,而不是过多地考虑设计过程(尤其是在开始时)。

对我来说,这听起来也像是过早的优化,如果可能的话,你应该坚持第一种策略,避免让自己头疼

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

编辑:

最简单的方法是使用ThreadLocal套接字创建执行器,并为其提供可运行的作业。(请参阅)线程将只创建一次,并从那时起重新使用,直到执行器关闭

当在作业的
run()
方法中引发异常时,这会变得有点棘手。我怀疑您会发现您需要对执行器线程的生命周期进行更多的控制。如果是,您可以复制
newFixedThreadPool
的源代码:

return new ThreadPoolExecutor(nThreads, nThreads,
                              0L, TimeUnit.MILLISECONDS,
                              new LinkedBlockingQueue<Runnable>());
返回新的ThreadPoolExecutor(nThreads,nThreads,
0L,时间单位为毫秒,
新建LinkedBlockingQueue());
并将实例化的
ThreadPoolExecutor
子类化以对其进行自定义。例如,通过这种方式,您可以覆盖以检测和清理断开的套接字


发送作业通过阻塞队列传输到工作线程。我意识到这不是ZeroMQ将消息传递给工作线程的方式,这将是inproc消息传递。这将ZeroMQ从HTTP工作线程移开,后者的生命周期超出您的控制,因此很难在其中维护套接字,更接近应用程序的边缘。您必须简单地测试两者中哪一个更有效,并且必须判断您希望应用程序采用ZeroMQ消息传递范例进行线程间通信的严格程度。

线程不能重用自己的私有套接字吗?不,这些是HTTP处理程序线程,由应用服务器管理;我将更新这个问题,thx。什么是编程语言/app server?Java,在Tomcat或jettypeter上,哪个示例最能说明在永久转发器线程中使用
inproc
?(感谢您提供的信息!)您建议使用
clientThread.connect(inproc://...)
clientThread.connect相反(tcp:///...)
是由于
inproc的开销较小