消费者线程模型

Dubbo 消费者线程池模型使用

2.7.5 版本对整个调用链路进行了全面的优化,根据压测结果,整体 QPS 性能提升近 30%,调用过程中的内存分配开销也降低了。值得一提的设计点是,2.7.5 引入了 Servicerepository 的概念,在服务注册阶段提前生成 ServiceDescriptor 和 MethodDescriptor,减少 RPC 调用阶段计算 Service 原信息带来的资源消耗。

消费者线程池模型优化

对于 2.7.5 版本之前的 Dubbo 应用,尤其是部分消费者端应用,在面对需要消费大量服务且并发量比较大的高流量场景(典型如网关场景),消费者端的线程数往往会过度分配,存在很多问题,具体讨论请参考 Need a limited Threadpool in consumer side #2013

改进后的消费者端线程池模型通过复用业务端的阻塞线程很好地解决了这个问题。

旧的线程池模型

Consumer thread pool.png

让我们关注 Consumer 部分

  1. 业务线程发送请求并获取 Future 实例。
  2. 然后业务线程调用 future.get 阻塞等待业务结果返回。
  3. 当业务数据返回时,将由独立的消费者端线程池进行反序列化,并调用 future.set 返回反序列化的业务结果。
  4. 业务线程在获取结果后直接返回

2.7.5 版本引入的线程池模型

Consumer thread pool new.png

  1. 业务线程发送请求并获取 Future 实例。
  2. 在调用 future.get() 之前,先调用 ThreadlessExecutor.wait(),wait 会让业务线程阻塞在阻塞队列上,直到队列中添加元素。
  3. 当业务数据返回时,生成一个 Runnable Task 并将其放入 ThreadlessExecutor 队列
  4. 业务线程取出 Task 并在这个线程中执行:反序列化业务数据并将其设置到 Future。
  5. 业务线程在获取结果后直接返回

这样,与旧的线程池模型相比,业务线程本身负责监控和解析返回的结果,省去了额外的消费端线程池开销。

关于性能优化,将在下一个版本中继续推进,主要从以下两个方面入手

  1. RPC 调用链路。目前可以看到的点包括:进一步减少执行链路的内存分配,在保证协议兼容性的前提下提高协议传输效率,提高 Filter 和 Router 的计算效率。
  2. 服务治理链路。进一步减少地址推送和服务治理规则推送带来的内存和 cpu 资源消耗。

上次修改时间:2023 年 1 月 2 日:Enhance en docs (#1798) (95a9f4f6c1c)