当前在我们的推荐配置下,Pegasus Replica Server 一共会有 174 线程在工作,所有的线程都是长线程。 这些线程到底是用来做什么的,我们在这篇文章进行梳理。


线程总览

多数线程会通过 wait 的方式沉睡,实际对 CPU 的竞争影响较小,典型的 pstack 情况是

  • pthread_cond_wait: 49
  • epoll_wait: 36
  • sem_wait: 81

这样算下来会发现实际运转的线程数是 174-49-36-81=8,而我们的机器通常配置的核心数是 24 核,平时的计算资源存在一定冗余。

THREAD_POOL_COMPACT
worker_count = 8

THREAD_POOL_FDS_SERVICE
worker_count = 8

THREAD_POOL_REPLICATION_LONG
worker_count = 8

THREAD_POOL_LOCAL_APP
worker_count = 24

THREAD_POOL_FD
worker_count = 2

THREAD_POOL_DLOCK
worker_count = 1

THREAD_POOL_META_STATE
worker_count = 1

THREAD_POOL_REPLICATION
worker_count = 24

THREAD_POOL_DEFAULT
worker_count = 8

抛开 meta_server 的线程池(THREAD_POOL_DLOCKTHREAD_POOL_META_STATE),由 rDSN 托管的线程数算下来应该是 82 个,多出来的 92 线程如何分配?

30 个线程负责定时任务的处理

30 个线程负责 timer_service,即定时任务的处理。

rDSN 默认为每个线程池分配一个 timer 线程,理论上有 7 个线程池,就是 7 线程。但是因为 THREAD_POOL_REPLICATION 是各个线程 share nothing 的,所以它的每个 worker 线程会单独配一个 timer 线程。因此总 timer 线程数是 24 + 6 = 30。

40 个线程负责网络报文处理

20 个线程负责 tcp 的处理(asio_net_provider),20 个线程执行 udp 的处理(asio_udp_provider)

目前每个 rpc_channel (udp/tcp) 对每个 network_header_format 都会配置 4 个 worker 线程。

我们目前有四种 format:RAW,THRIFT,HTTP,DSN,(目前不清楚第 5 种的类型)

相关配置:

[network]
io_service_worker_count = 4

2 个线程负责上报监控到 falcon

2 个线程负责上报监控到 falcon,这里的线程数是写死的。

参考: pegasus_counter_reporter

1 个线程负责 aio 读写磁盘

1 个线程执行 aio 读写磁盘的任务,即 libaio 的 get_event 操作。

16 个线程执行 rocksdb 后台操作

其中 12 个线程执行 rocskdb background compaction。

4 个线程执行 rocksdb background flush。

参考: pegasus_server_impl

相关配置:

[pegasus.server]
rocksdb_max_background_flushes=4
rocksdb_max_background_compactions=12

2 个线程执行 shared_io_service

2 个线程执行 shared_io_service,给 percentile 类型的 perf-counter 用

相关配置:

[core]
timer_service_worker_count=2