本文中介绍了如何配置gRPC和brpc。
gRPC的配置真的是蛋疼。主要原因是官方的推荐方式是从源码编译。于是我首先花了一个下午用小水管clone了下gRPC和它的十来个三方库。
安装和配置protobuf
gRPC依赖于protobuf,但不能盲目安装protobuf,例如Ubuntu默认的protobuf是2.6.1,而Google给的helloworld示例需要protobuf 3才能编译,所以不能用apt安装。此外即使从源码编译装,也没必要去protobuf的官方仓库。注意gRPC不会自动帮你make install protobuf
,所以需要到gRPC的third_party目录下找到protobuf的源码编译安装。更新gRPC中的子模块的命令如下
1 | git submodule update --init --recursive |
进入protobuf目录
1 | ./autogen |
注意点
./autogen
里面会下载gmock,可能会失败,这里可以直接进去注释掉相关语句。- 需要安装libtool,否则会出现
undefined macro: AC_PROG_LIBTOOL
- 需要安装autoconf,否则会出现
autoreconf: command not found
- 由于protobuf的安装版本不带调试信息,有时候会出现
Can't parse message of type
的情况,不能assert然后调试dump,可参考https://github.com/protocolbuffers/protobuf/issues/1102编译调试版本。
gRPC项目的编译
编译gRPC应当遵循BUILDING.md
1 | apt-get install build-essential autoconf libtool pkg-config |
在编译gRPC项目时,对于客户端会生成**.pb.h和.pb.cc两个文件;但是服务端则需要.grpc.pb.h和.grpc.pb.cc两个文件。这四个文件是由protoc通过不同的指令生成的,如下所示,这里grpc_out
即表示生成服务端需要使用的带.grpc.pb系文件,plugin
字段需要我们指明grpc_cpp_plugin这个插件所在的位置。如果我们从源码编译安装的话,这个插件一般会在/usr/local/lib**里面,我们一般需要将这个路径export出来
1 | export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH |
当然也可以运行这个脚本来一劳永逸地解决问题。
注意点
- 注意使用
git clone -b $(curl -L https://grpc.io/release) https://github.com/grpc/grpc
来下载grpc的release版本对应的repo。 - unused-variable的错误,可见https://github.com/grpc/grpc/issues/16739,不过解决不了问题,我是替换掉所有-Werror`解决的
Makefile
如果直接使用Makefile来编译,我们需要先按照下面的规则生成四个文件,此外我们还需要将程序链接到protobuf、grpc++、grpc这三个库上。gRPC的官方Git仓库中提供了Makefile的demo。
1 | $ protoc -I ../../protos --grpc_out=. --plugin=protoc-gen-grpc=`which grpc_cpp_plugin` ../../protos/route_guide.proto |
CMake
gRPC的官方Git仓库也提供了CMakeLists的Demo,不过我并没有能够成功进行编译,它提示缺少gRPCConfig.cmake或grpc-config.cmake文件,于是我放弃了来自官方的CMakeLists。在我先前的protobuf试用中,我了解了cmake中的PROTOBUF_GENERATE_CPP
宏可以编译出**.pb.h和.pb.cc**两个文件,现在我们需要依葫芦画瓢搞出一个PROTOBUF_GENERATE_GRPC_CPP
宏就行了。在爆栈网的一篇回答中我找到了一个实用的实现,借助于它我实现了自己的CMakeLists。注意目前gRPC的编译需要C++11标准的支持,所以这里我使用了SET(CMAKE_CXX_COMPILER /usr/bin/g++-7 CACHE PATH "" FORCE)
来强制设置了编译器。
可以在https://github.com/CalvinNeo/ARPC/blob/master/test/grpc/中找到我的一个完整的配置
gRPC使用的坑
14 Connection Refused
Linux下的Connection Refused这是由于我们配置了http_proxy
的缘故
Server::Shutdown
根据https://github.com/grpc/grpc/issues/10324,这个函数也会阻塞
gRPC服务类型
gRPC支持Unary RPC、Server streaming RPC、Client streaming RPC和Bidirectional streaming RPC。
常用类
服务端
一般服务器端的类包含ServiceImpl类(一般派生自Service
类)、grpc::ServerBuilder
类、Server
类。我们一般可以用下面的类进行封装
1 | struct Context{ |
Service
::package_name::ServiceName::Service
(简称为Service
)类是由Protobuf根据我们proto文件自动生成的类,实际上是用C++描述了ServiceName
这个service。我们一般会从Service
中派生出一个类ServiceImpl: Service
类来实现这些方法。
1 | struct ServiceImpl: public ::package_name::ServiceName::Service{ |
Status
grpc::Status
类一般用来维护RPC调用的状态
Server
Server类
gRPC线程模型
gRPC提供了异步和同步的API。
https://github.com/grpc/grpc/pull/10919/files
brpc的编译安装
brpc依赖gflags、protobuf、openssl和leveldb。其中gflags按照以下方式安装
1 | git clone https://github.com/gflags/gflags.git |
openssl通过以下命令安装
1 | apt install libssl-dev openssl |
接下来make,注意一定要加上--with-glog
不然例如braft里面的test的用到glog的都有问题
1 | sh config_brpc.sh --headers="/usr/local/include /usr/include" --libs=/usr/local/lib --cxx=g++ --cc=gcc --nodebugsymbols --with-glog |
在gRPC 3.7版本后,GoogleOnceInit
被用std::call_once
取代了,这时候编译brpc就会出现问题。这里推荐使用3.6的版本,特别注意,在换版本之后一定要先make clean掉已经生成的pd文件。
这里注意一下,我们可以同时从源码和从apt安装protobuf的,这时候我们就要指定我们要用哪个版本的protobuf。一般apt安装在不带local的文件夹下。
特别地,gflags可能和glog产生冲突,这时候可以先apt purge掉gflags再编译glog。或者可以采用./configure CPPFLAGS="-I/usr/local/include" LDFLAGS="-L/usr/local/lib"
命令编译。