grpc-go中controlbuf是否是性能瓶颈

之前一直在关注grpc-go性能问题,之所以说是问题,高并发I/O的情况下,read和write都会有ms级别的耗时波动。

被http2协议的流控是否干扰性能这个问题困扰很久,因为grpc-go是我唯一阅读的rpc框架,没有参考,所以对于rpc框架该怎么设计合理,心中没有标准,也没办法衡量。我们之前使用的brpc,性能表现相当好,cpu吃的也不紧,而且github上的文档干活比较多,当然干活多不代表文档全,brpc这方面还是要优化下。所以反复读了brpc在io部分的设计,总结下框架处理高并发I/O要做些什么:

  • 流水线:不同类工作分开处理,防止干扰,针对不同req处理耗时波动大或者不可预估的环节一定要加入并发能力(例如执行用户逻辑的部分,这块通常没有框架会犯低级错误,让用户的业务逻辑互相干扰)
  • lock-free和wait-free:涉及到连接r和w,如果是http2还涉及到frame的顺序保证,所以在框架层内部一定要做到其中一种,最好是wait-free,就是线程之间完全不干扰,brpc从读取并解析完header后就直接并发了,基本算是wait-free

反过来看grpc-go,grpc-go以frame形式read所有req,frame需要积累直到遇到带有end标识的dataFrame,grpc-go在event dispatcher这块采用单goroutine读取并预处理的模式,问题出在预处理,frame的种类有几种,可以简单分为:

  • 请求相关:headerFrame & dataFrame
  • 控制相关:settingsFrame & rstFrame & pingFrame & windowUpdateFrame(这个frame和bdp计算以及keepalive相关)

上面的所有frame grpc-go无差别单goroutine处理,当然每种frame处理时间固定,也不算设计有缺陷,而这里的frame大多与controlbuf相关,这个buf是有lock的,buf给配了一个单独的goroutine loopyWriter负责处理其中的内容,get/put肯定是要过lock的,get的操作包含很多种:内部控制(sender来的窗口frame)、req相关、外部控制(receiver给外部的),这种干扰是没必要的,应该尽量让框架的各环节流水线工作,这块也是我后续调研的方向,希望能增加grpc-go在高并发下的稳定性,我希望看到的情况是,随着服务器的cpu负载上升,所有stream的请求延时稳定上升,而不是波动。

grpc-go中controlbuf是否是性能瓶颈
Share this