想不开系列 —— C++折腾gRPC小记

by on
分类: grpc | 阅读量

本文为本人原创,欢迎分享,转载请注明【本文链接】

前言

本文记录了19下半年,因为项目需要开发一个监控采集数据的Agent程序,我使用C++折腾gRPC的经历。

Thumper

1、gRPC简介

服务(Service) ,正是作为业务服务器的最根本职能,而下面是我认为的一些常见服务架构:

Thumper

都2020年了,应该没有人不知道rpc是啥了吧?而说到常用的rpc框架如下:

Thumper

我选择了gRPC作为与用户方通信的方式,gRPC是在HTTP/2之上实现的RPC框架, 它运行在TCP协议之上,相比于传统的REST/JSON机制有诸多的优点: (1)基于HTTP/2之上的二进制协议(Protobuf序列化机制) (2)一个连接上可以多路复用,并发处理多个请求和响应 (3)支持多种语言的类库实现(然而我选择了困难度最高的c++) (4)服务定义文件和自动代码生成(.proto文件和Protobuf编译工具) (5)pb作为通信数据交换格式,好处不用多说(感兴趣请详见文章《浅谈protobuf》

gRPC的通信模型架构如下: Thumper Thumper

而gRPC使用了Http2.0作为协议层,大大加强了通信的性能与安全性: Thumper

我从自己通信的请求中抓了下请求的包,长这个样子: Thumper

简而言之,gGRPC把元数据放到HTTP/2 Headers里,请求参数序列化之后放到DATA Frame里。

2、安装C++ gRPC编译/执行环境

好了,谈架构和原理,大家也许都头头是道,实际上手才发现,除了google本身的golang儿子,其他语言使用起来其实都有些麻烦。。。

环境/内核要求: tlinux 2.2以上版本,gcc编译器4.8.0以上版本,我是Cent7.0+的环境安装的。

(1)安装相关依赖

yum install build-essential autoconf libtool pkg-config
yum install libgflags-dev libgtest-dev
yum install clang libc++-dev

我们可以执行/usr/bin/gcc --version查看c库版本:

gcc (GCC) 4.8.5

(2)clone代码到机器

git clone -b $(curl -L https://grpc.io/release) https://github.com/grpc/grpc

(3)解压、初始化submodule

cd grpc
git submodule update --init

(4) 编译

export LD_LIBRARY_PATH=LDLIBRARYPATH:/usr/local/libexport:LDLIBRARYPATH=/{target-path}/grpc/thirdparty/protobuf/src/.libs/:LD_LIBRARY_PATH

make -j32
make install

完成编译后,我们可以看到,目录大致如下:

[root@host:/usr/local/grpc]$ ls
AUTHORS             examples                OWNERS
bazel               Gemfile                 package.xml
bins                gens                    PYTHON-MANIFEST.in
BUILD               grpc.bzl                Rakefile
build_config.rb     gRPC-Core.podspec       README.md
BUILD.gn            gRPC-C++.podspec        requirements.bazel.txt
BUILDING.md         grpc.def                requirements.txt
build.yaml          grpc.gemspec            setup.cfg
cache.mk            grpc.gyp                setup.py
cmake               gRPC.podspec            src
CMakeLists.txt      gRPC-ProtoRPC.podspec   summerofcode
CODE-OF-CONDUCT.md  gRPC-RxLibrary.podspec  templates
composer.json       include                 test
CONCEPTS.md         libs                    third_party
config.m4           LICENSE                 tools
config.w32          Makefile                TROUBLESHOOTING.md
CONTRIBUTING.md     MANIFEST.md             WORKSPACE
doc                 NOTICE.txt
etc                 objs

其中不同gRPC版本,依赖的protobuf版本也不同,执行install后,gRPC相关库默认被安装到/usr/local/lib/目录下(

libaddress_sorting.a               libgrpc++_reflection.a
libaddress_sorting.so              libgrpc++_reflection.so
libaddress_sorting.so.7            libgrpc++_reflection.so.1
libaddress_sorting.so.7.0.0        libgrpc++_reflection.so.1.20.0
libgpr.a                           libgrpc.so
libgpr.so                          libgrpc++.so
libgpr.so.7                        libgrpc++.so.1
libgpr.so.7.0.0                    libgrpc++.so.1.20.0
libgrpc.a                          libgrpc.so.7
libgrpc++.a                        libgrpc.so.7.0.0
libgrpc_cronet.a                   libgrpc_unsecure.a
libgrpc++_cronet.a                 libgrpc++_unsecure.a
libgrpc_cronet.so                  libgrpc_unsecure.so
libgrpc++_cronet.so                libgrpc++_unsecure.so
libgrpc++_cronet.so.1              libgrpc++_unsecure.so.1
libgrpc++_cronet.so.1.20.0         libgrpc++_unsecure.so.1.20.0
libgrpc_cronet.so.7                libgrpc_unsecure.so.7
libgrpc_cronet.so.7.0.0            libgrpc_unsecure.so.7.0.0
libgrpc++_error_details.a          libprotobuf.a
libgrpc++_error_details.so         libprotobuf.la
libgrpc++_error_details.so.1       libprotobuf-lite.a
libgrpc++_error_details.so.1.20.0  libprotobuf-lite.la
libgrpcpp_channelz.a               libprotoc.a
libgrpcpp_channelz.so              libprotoc.la
libgrpcpp_channelz.so.1            pkgconfig
libgrpcpp_channelz.so.1.20.0

(5)基本环境变量配置

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib
export LD_LIBRARY_PATH=/usr/local/grpc/third_party/protobuf/src/.libs/:$LD_LIBRARY_PATH

export PATH=/usr/local/grpc/bins/opt/:$PATH
export PATH=/usr/local/grpc/bins/opt/protobuf:$PATH
export PKG_CONFIG_PATH=/usr/local/grpc/libs/opt/pkgconfig
export PKG_CONFIG_PATH=/usr/local/grpc/third_party/protobuf/:$PKG_CONFIG_PATH
export CPLUS_INCLUDE_PATH=/usr/local/grpc/third_party/protobuf/src/
export CPLUS_INCLUDE_PATH=$CPLUS_INCLUDE_PATH:/usr/local/grpc/third_party/protobuf/conformance/third_party/jsoncpp/

可以通过执行protobuf --version,看看配置有没有生效,并且看下pb版本。我用的是3.7.0

[root@host:/data/home/wind/grpc/src/cpp]$ protoc --version
libprotoc 3.7.0

(6)demo编译测试 ./grpc/examples/cpp/helloworld目录下可以进行demo测试:

[root@host:/usr/local/grpc/examples/cpp/helloworld]$ make clean
rm -f *.o *.pb.cc *.pb.h greeter_client greeter_server greeter_async_client greeter_async_client2 greeter_async_server

[root@host:/usr/local/grpc/examples/cpp/helloworld]$ make -j8
protoc -I ../../protos --cpp_out=. ../../protos/helloworld.proto
protoc -I ../../protos --grpc_out=. --plugin=protoc-gen-grpc=`which grpc_cpp_plugin` ../../protos/helloworld.proto
g++ -std=c++11 `pkg-config --cflags protobuf grpc`  -c -o greeter_client.o greeter_client.cc
g++ -std=c++11 `pkg-config --cflags protobuf grpc`  -c -o greeter_server.o greeter_server.cc
g++ -std=c++11 `pkg-config --cflags protobuf grpc`  -c -o greeter_async_client.o greeter_async_client.cc
g++ -std=c++11 `pkg-config --cflags protobuf grpc`  -c -o greeter_async_client2.o greeter_async_client2.cc
g++ -std=c++11 `pkg-config --cflags protobuf grpc`  -c -o greeter_async_server.o greeter_async_server.cc
g++ -std=c++11 `pkg-config --cflags protobuf grpc`  -c -o helloworld.pb.o helloworld.pb.cc
g++ -std=c++11 `pkg-config --cflags protobuf grpc`  -c -o helloworld.grpc.pb.o helloworld.grpc.pb.cc
g++ helloworld.pb.o helloworld.grpc.pb.o greeter_client.o -L/usr/local/lib `pkg-config --libs protobuf grpc++ grpc` -Wl,--no-as-needed -lgrpc++_reflection -Wl,--as-needed -ldl -o greeter_client
g++ helloworld.pb.o helloworld.grpc.pb.o greeter_server.o -L/usr/local/lib `pkg-config --libs protobuf grpc++ grpc` -Wl,--no-as-needed -lgrpc++_reflection -Wl,--as-needed -ldl -o greeter_server
g++ helloworld.pb.o helloworld.grpc.pb.o greeter_async_client.o -L/usr/local/lib `pkg-config --libs protobuf grpc++ grpc` -Wl,--no-as-needed -lgrpc++_reflection -Wl,--as-needed -ldl -o greeter_async_client
g++ helloworld.pb.o helloworld.grpc.pb.o greeter_async_client2.o -L/usr/local/lib `pkg-config --libs protobuf grpc++ grpc` -Wl,--no-as-needed -lgrpc++_reflection -Wl,--as-needed -ldl -o greeter_async_client2
g++ helloworld.pb.o helloworld.grpc.pb.o greeter_async_server.o -L/usr/local/lib `pkg-config --libs protobuf grpc++ grpc` -Wl,--no-as-needed -lgrpc++_reflection -Wl,--as-needed -ldl -o greeter_async_server

(7) 运行测试

[root@host:/usr/local/grpc/examples/cpp/helloworld]$ ./greeter_server 
Server listening on 0.0.0.0:50051

[root@host:/usr/local/grpc/examples/cpp/helloworld]$ ./greeter_client 
Greeter received: Hello world

有以上回显,表示编译和环境已经standby!

protobuf, grpc, c++