Python中如何扩展gRPC功能?
最近刚接触 grpc 有个不明白的地方: 官方例子中 grpc 服务端和客户端都是写死了 host 和 port,那么如果由于用户量的上升,grpc 服务端需要扩展到多台,那么这个时候如何处理? grpc 有现成的方案?
Python中如何扩展gRPC功能?
在Python中扩展gRPC功能,核心是围绕Protocol Buffers定义和gRPC服务实现。主要方式有:
- 定义新的.proto文件:在现有.proto文件中添加新的service、rpc方法、message类型,或者创建新的.proto文件。这是功能扩展的基础。
- 实现新的服务类:继承生成的gRPC服务基类,实现新增的rpc方法。
- 使用中间件/拦截器:通过
grpc.ServerInterceptor或grpc.UnaryUnaryClientInterceptor等实现认证、日志、监控等横切关注点。 - 集成异步支持:使用
grpc.aio模块实现异步服务端和客户端。
完整代码示例:
假设已有calculator.proto,要添加一个Multiply方法:
// calculator.proto
syntax = "proto3";
service Calculator {
rpc Add (AddRequest) returns (AddResponse) {}
rpc Multiply (MultiplyRequest) returns (MultiplyResponse) {} // 新增方法
}
message AddRequest {
int32 a = 1;
int32 b = 2;
}
message AddResponse {
int32 result = 1;
}
message MultiplyRequest { // 新增消息
int32 a = 1;
int32 b = 2;
}
message MultiplyResponse { // 新增消息
int32 result = 1;
}
重新生成代码后,实现服务:
# server.py
import grpc
from concurrent import futures
import calculator_pb2
import calculator_pb2_grpc
class CalculatorServicer(calculator_pb2_grpc.CalculatorServicer):
def Add(self, request, context):
result = request.a + request.b
return calculator_pb2.AddResponse(result=result)
def Multiply(self, request, context): # 实现新方法
result = request.a * request.b
return calculator_pb2.MultiplyResponse(result=result)
def serve():
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
calculator_pb2_grpc.add_CalculatorServicer_to_server(
CalculatorServicer(), server
)
server.add_insecure_port('[::]:50051')
server.start()
server.wait_for_termination()
if __name__ == '__main__':
serve()
客户端调用新方法:
# client.py
import grpc
import calculator_pb2
import calculator_pb2_grpc
def run():
with grpc.insecure_channel('localhost:50051') as channel:
stub = calculator_pb2_grpc.CalculatorStub(channel)
# 调用原有方法
add_response = stub.Add(calculator_pb2.AddRequest(a=10, b=20))
print(f"Add result: {add_response.result}")
# 调用新方法
multiply_response = stub.Multiply(
calculator_pb2.MultiplyRequest(a=10, b=20)
)
print(f"Multiply result: {multiply_response.result}")
if __name__ == '__main__':
run()
简单总结:改proto定义,重新生成代码,实现新方法,就这么简单。
了解一下什么叫 服务注册发现
简单方案就是服务端前面用 HAProxy,客户端连 HA
python 的 grpc 就放弃吧,虽然你可以写 C extension 扩展 resolver,但是要在最开头引入,因为 grpcio 的所有 class,init 都隐含调用 grpc_init(),这样你写的 resolver 就没有用了
c-core 原生支持 dns resolver,target 用 dns:// 开头,不过只支持 A 记录
c-core 的 client side lb 自带了,不需要你自己做,但是参数你要看 C 的代码。
完全没有 go client 那么方便。
最终你可能还是会考虑 说的 HAProxy 方案
go 的话很方便,etcd 的 v3 版本客户端已经提供 grpclb 的实现,几行代码就能使用,而且不仅仅可以简单的负载算法,还可以自己实现一些特定的算法来满足特定需求,比如一致性 hash
+1
Java 版本可以自己实现 Loadbalancer,不过略复杂
python 选择 HA 方案挺方便的
用的 aws loadblance 服务
这和 grpc 有半毛钱关系?
grpc 只负责 rpc,你这个需要的是服务发现与 client 负载均衡。
当然系统化的话就更多了。


