grpc c++使用以及踩坑
两个因素想做开源项目:
1 主导开发中间件系统的心愿已经达成,虽然中间磕磕碰碰的踩了很多坑。
但毕竟最终结果是好的。
唯一的遗憾就是没有开源了。
2 之前做了一些小网站,也累积了不少用户,但是对技术的磨练还是太少了。
特别是用户的增长出现瓶颈以后,架构和细节已经没有必要在优化了。这就让人产生了惰性。
认真做一个开源项目,会有bug issue和功能的issue。会有人去推动你不断探究。
我认为这会收获巨大。
具体项目没想好,可能是基础库(偏网络高并发?又一个轮子?),也可能是比较擅长的存储系统。
做存储系统的话,会比较慎重,毕竟会是以十年计的项目(参考fastdfs的余庆前辈)。
不管是参考着做一些开源库,还是做存储系统。
调研(研究透彻了有问题才自己轮)或者做存储系统使用一个开源rpc框架(总不能拿公司框架出来做开源项目吧)都是必须的。
本文就以探究grpc框架为主,基于1.12版本
安装使用
最简单的是使用vcpkg安装静态库,不推荐这么做。
实测grpc的静态库会有很大的性能损耗,比起后来自己编译的动态库有75%的性能损耗,暂时还不清楚原因。
1 | sudo apt-get install build-essential autoconf libtool libgflags-dev libgtest-dev clang libc++-dev pkg-config unzip |
以上安装过程是从别的博客复制过来的,centos的环境应该会有些差别。我自己的centos环境是全的,直接可以安装。
安装以后cmake写上如下
1 | target_link_libraries(${TARGET} protobuf) |
可以把grpc的example复制过来编译试试看。
也可以直接跑我这个项目的build脚本
里面有同步,异步,多线程异步客户端的demo。
使用
同步客户端没什么好说的,内部实现是一个线程池,性能上会有很大问题(线程争用)。
异步客户端必须严格按照以下流程(任何一阶段乱序都会core掉我试过啦)
1 | RegisterService |
如果想要调用不同的service(指proto),或者不同handler(指相同proto下的不同handler)
需要在CallData进行封装,每个CallData会是grpc事件循环的调度单位
测试
这是坑爹的部分
测试还是使用我上面提供的github项目,使用go客户端进行压测
动态编译的1.12性能比静态的好得多了,但还是不佳,主要体现在网络10%负荷的情况下,cpu只能跑一半。
以为是自己的问题,在ubuntu和centos上都装了好几次,依然没法。
这个时候只能怀疑是grpc的问题了。
我直觉上grpc可能是锁争用了,上gperf一测果然是这样,wait和signal是最高消耗。
去翻了一下issue果然是这样。
Poor c++ performance benchmark result
即使是官方自己的测试,c++的性能也只有java的一半,8核还能跑一大半,32核只能跑三分之一了
很明显的锁争用阿。
不太清楚grpc的团队是不是很忙,这个issue提出来2个月了,在10天前才被定为bug
于是我换版本,一直换到1.6,依然是这个问题。
issue说1.6是java性能两倍,我没感觉到有性能提升。也看不到官方图表关于以前版本的数据。
grpc的这一次探究暂时算是扑街
待续
grpc的go版本很棒,可能主要还是依赖了go良好的协程模型,一般写不出什么性能问题来。
c++版本更像一个玩具,可能还是研发人员的精力不够吧,毕竟不是全职。
等c++版本修复了这个问题再来跟进吧。
PS:每个网络库都自称自己很牛,实际的库用户更像是抽奖,赌对了起飞,错了血崩。
怪不得现在层出不穷的各种轮子,至少有问题自己能方便改啊。
看来再轮一个开源网络库也不是不可以。