1. grpc简介
-
1.1 概述
gRPC是搭建分布式应用接口和客户端的框架。在 gRPC 中,客户端应用程序可以直接调用不同机器上的服务器应用程序上的方法,就像它是本地对象一样,可以更容易创建分布式应用程序和服务。与许多 RPC 系统一样,gRPC 基于定义服务的思想,指定可以远程调用的方法及其参数和返回类型。在服务端,服务端实现这个接口并运行一个 gRPC 服务器来处理客户端调用。在客户端,客户端有一个存根(在某些语言中仅称为客户端),它提供与服务器相同的方法。
gRPC 客户端和服务器可以在各种环境中运行和相互通信——从 Google 内部的服务器到您自己的桌面——并且可以用任何 gRPC 支持的语言编写。例如,可以使用 Go、Python 或 Ruby 中的客户端轻松地调用在 Java 中创建 gRPC 服务器
-
1.2 grpc 优缺点
优点:- protobuf二进制消息,性能好/效率高
- proto文件通过命令自动生成目标代码,简单易用
- 序列化反序列化直接对应程序中的数据类,不需要解析后在进行映射
- 支持多种语言
缺点:
- 浏览器支持受限:部分浏览器不支持http2.0
- 人为读取困难,proto文件规定的格式在通讯中会序列化成二进制数据
-
1.3 grpc 使用场景
适用场景:- 微服务:gRPC 设计用于低延迟和高吞吐量通信。 gRPC 对于效率至关重要的轻量级微服务非常有用。
- 点对点实时通信:gRPC 对双向流式传输提供出色的支持。 gRPC 服务可以实时推送消息而无需轮询。
- 多语言环境:gRPC 工具支持所有常用的开发语言,因此,gRPC 是多语言环境的理想选择。
- 网络受限环境:gRPC 消息使用 Protobuf(一种轻量级消息格式)进行序列化。 gRPC 消息始终小于等效的 JSON 消息。
不适用场景:
- 浏览器可访问的API:gRPC 在浏览器中未受到完全支持。 gRPC-Web 可以提供浏览器支持,但它具有局限性并引入了服务器代理。
- 广播实时通信:gRPC 支持通过流式传输进行实时通信,但不存在将消息广播到注册连接的概念。 例如,在聊天室方案中,应将新的聊天消息发送到聊天室中的所有客户端,这要求每个 gRPC 调用将新的聊天消息单独流式传输到客户端。 SignalR 是适用于此方案的框架。 SignalR 具有持久性连接的概念,并内置对广播消息的支持。
- 进程间通信:进程必须托管 HTTP/2 服务器才能接受传入的 gRPC 调用。 对于 Windows,进程间通信管道是一种快速、轻便的通信方法。
2. grpc实现
- 2.1 依赖包安装
pip install grpcio
pip install grpcio-tools
pip protobuf
- 2.2 定义proto文件
以一个简单的健康检查接口为例,创建文件health.proto
syntax = "proto3";
// 定义grpc请求消息体
message HealthCheckRequest {
string service = 1;
}
// 定义grpc返回消息体
message HealthCheckResponse {
enum ServingStatus {
UNKNOWN = 0;
SERVING = 1;
NOT_SERVING = 2;
}
ServingStatus status = 1;
}
// 定义服务接口
service Health {
rpc check(HealthCheckRequest) returns (HealthCheckResponse);
}
创建proto文件后,使用命令生成相关文件
python -m grpc_tools.protoc -I . --python_out=. --grpc_python_out=. ./health.proto
- 2.3 服务端实现
class HealthServer(health_pb2_grpc.HealthServicer):
"""
定义类继承HealthServicer
"""
def __init__(self):
pass
def check(self, request, context):
"""
健康检查接口,实现proto文件中的服务接口
"""
return health_pb2.HealthCheckResponse(status=HealthCheckResponse.ServingStatus.SERVING)
def run(host, port):
"""
运行ocr服务
:param host:
:param port:
:return:
"""
server = grpc.server(futures.ThreadPoolExecutor(max_workers=5))
health_pb2_grpc.add_HealthServicer_to_server(HealthServer(), server)
server.add_insecure_port(f'{host}:{port}')
server.start()
print('Grpc server connect successful!')
# 启动服务,等待退出
try:
while True:
time.sleep(600)
except KeyboardInterrupt:
server.stop(0)
if __name__ == '__main__':
run(host='0.0.0.0', port='8001')
- 2.4 客户端实现
conn = grpc.insecure_channel('127.0.0.1:8001')
client = health_pb2_grpc.HealthStub(channel=conn)
request = health_pb2.HealthCheckRequest(service='test')
response = client.Check(request)
print('check grpc health status successful!')