gRPC概述
gRPC是一款高性能、开源的 RPC 框架,产自 Google,基于 ProtoBuf 序列化协议进行开发,支持多种语言(Golang、Python、Java等)。gRPC对HTTP2.0协议的支持使其在 Android、IOS 等客户端后端服务的开发领域具有良好的前景。gRPC 提供了一种简单的方法来定义服务,同时客户端可以充分利用HTTP2.0 stream的特性,从而有助于节省带宽、降低 TCP 的连接次数、节省CPU的使用等。所谓RPC(remote procedure call 远程过程调用)框架实际是提供了一套机制,使得应用程序之间可以进行通信,而且也遵从server/client模型。使用的时候客户端调用server端提供的接口就像是调用本地的函数一样。
gRPC优势
gRPC和Restful API都提供了一套通信机制,用于server/client模型通信,而且它们都使用http作为底层的传输协议。不过gRPC有些特有的优势如下:
- gRPC可以通过protobuf来定义接口,从而可以有更加严格的接口约束条件。
- 通过protobuf可以将数据序列化为二进制编码,这会大幅减少需要传输的数据量,从而大幅提高性能。
- gRPC可以方便地支持流式通信。(理论上通过http2.0就可以使用streaming模式, 但是通常web服务的Restful API似乎很少这么用,通常的流式数据应用如视频流,一般都会使用专门的协议如HLS,RTMP等,这些就不是我们通常web服务了,而是有专门的服务器应用)
gRPC场景
- 需要对接口进行严格约束的情况。比如我们提供一个公共的服务,很多客户端可以访问这个服务,这时对于接口我们希望有更加严格的约束,我们不希望客户端给我们传递任意的数据,尤其是考虑到安全性的因素,我们通常需要对接口进行更加严格的约束。这时gRPC就可以通过protobuf来提供严格的接口约束。
- 对于性能有更高的要求的情况。有时我们的服务需要传递大量的数据,而又希望不影响我们的性能,这个时候也可以考虑gRPC服务,因为通过protobuf我们可以将数据压缩编码转化为二进制格式,通常传递的数据量要小得多,而且通过http2我们可以实现异步的请求,从而大大提高了通信效率。
gRPC安装
在线:
pip install grpcio
pip install protobuf
pip install grpcio_tools
离线
https://pypi.org/project/grpcio/#files
https://pypi.org/project/protobuf/#files
https://pypi.org/project/grpcio-tools/#files
gRPC示例
1、protobuf定义接口和数据类型
syntax = "proto3";
package firstmsg;
service FirstMsg {
rpc firstMsg(FirstMsgRequest) returns (FirstMsgResponse) {}
}
message FirstMsgRequest {
string body = 1;
}
message FirstMsgResponse {
string content = 1;
}
python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. first_msg.proto
-I 指定协议文件的查找目录 设置为当前目录./
--python_out 指定 xxxxxx_pb2.py的输出路径
--grpc_python_out 指定xxxxxx_pb2_grpc.py文件的输出路径
2、gRPC Server 端代码
# -*- coding:utf-8 -*-
import sys
import json
import time
from concurrent import futures
from mgrpc.proto.first_msg_pb2 import *
from mgrpc.proto.first_msg_pb2_grpc import *
default_encoding = "utf-8"
if sys.getdefaultencoding() != default_encoding:
reload(sys)
sys.setdefaultencoding(default_encoding)
class CFirstMsgServicer(FirstMsgServicer):
def firstMsg(self, request, context):
request_body = request.body
print 'receive client request : {}'.format(request_body)
if request_body:
data = json.loads(request_body)
print 'parse client request : {}'.format(data)
return FirstMsgResponse(content=json.dumps({"code": 200, "data": "success"}))
else:
return FirstMsgResponse(content=json.dumps({"code": 500, "data": "failure"}))
def startup():
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
add_FirstMsgServicer_to_server(CFirstMsgServicer(), server)
server.add_insecure_port('127.0.0.1:10080')
server.start()
try:
while True:
time.sleep(3600)
except KeyboardInterrupt:
server.stop(0)
if __name__ == '__main__':
startup()
3、gRPC Client 端代码
# -*- coding:utf-8 -*-
import sys
import json
from datetime import datetime
from mgrpc.proto.first_msg_pb2 import *
from mgrpc.proto.first_msg_pb2_grpc import *
default_encoding = 'utf-8'
if sys.getdefaultencoding() != default_encoding:
reload(sys)
sys.setdefaultencoding(default_encoding)
def invoke_first_msg_service():
channel = grpc.insecure_channel('127.0.0.1:10080')
first_msg_stub = FirstMsgStub(channel)
msg = {"from": 1, "to": 2, "op_time": datetime.now().strftime('%Y-%m-%d %H:%M:%S'), "msg": "hello"}
response = first_msg_stub.firstMsg(FirstMsgRequest(body=json.dumps(msg)))
print 'response content : {}'.format(response.content)
response = first_msg_stub.firstMsg(FirstMsgRequest(body=None))
print 'response content : {}'.format(response.content)
if __name__ == '__main__':
invoke_first_msg_service()