在Java GCP PubSub消费者中有两个重要的字段用于控制并发级别:
- 平行拉数
- 执行线程数
来自官方示例:
setParallelPullCount
决定订阅者将打开多少StreamingPull流来接收消息。默认为1。setExecutorProvider
为订阅者配置一个执行器来处理消息。这里,订阅者被配置为打开2个流来接收消息,每个流创建一个带有4个线程的新执行器来帮助处理消息回调。总共有2x4=8个线程用于消息处理。
所以并行拉计数,如果我没弄错的话,直接指的是Java执行器的数量(=线程池),而执行器线程的数量设置了每个线程池的线程数量。
通常我认为单独的线程池有不同的用例或职责,所以我们可能有一个无界的缓存线程池用于IO,一个固定的线程池用于cpu绑定的操作,一个单一的(或低数量的)线程池用于异步IO通知,等等。
但是,使用两个或多个具有相同属性的线程池来消费和处理pubsub消息,与简单地使用单个线程池并拥有所需的最大线程数相比,有什么好处呢?例如,如果我可以在订阅者上总共预留8个线程,那么使用1x8 vs 2x4组合的具体原因是什么?(8线程的单个池,与拉计数=2使用每个4线程)?setParallelPullCount
选项不只是指JavaExecutor
s的数量,它指创建的从服务器请求消息的流的数量。由于各种因素,不同的流可能返回不同数量的消息。为了在单个客户端中处理比在单个流(10MB/s)上传输更多的消息,可能需要增加并行拉取计数。这与是否共享执行器/线程池无关。
setExecutorProvider
来处理。如果您设置一个ExecutorProvider
,在每次调用getExecutor
时返回相同的Executor
,那么流将共享它。如果您让它为每个调用返回一个新的Executor
,那么它们每个都有自己专用的Executor
。默认的ExecutorProvider
执行后者。
如果调用setParallelPullCount(X)
,则setExecutor
被调用X
次以获得每个流的Executor
。在大多数情况下,是所有人共享一个还是每个人单独使用一个可能不会有太大的变化。如果您试图保持总体线程数相对较低,那么共享单个Executor
可能会有所帮助。
Executor
s和带有X*Y个线程的一个Executor
之间的选择实际上归结为共享这些资源的能力,如果来自每个流的数据量有很大的不同,这可能不是大多数情况下的情况。如果是,那么共享的Executor
意味着一个特别饱和的流可以"借用"。不饱和的线。另一方面,使用单独的Executor
可能意味着在这种情况下,消息较少的流上的消息与饱和流上的消息一样能够通过。