Python中如何扩展gRPC功能?

最近刚接触 grpc 有个不明白的地方: 官方例子中 grpc 服务端和客户端都是写死了 host 和 port,那么如果由于用户量的上升,grpc 服务端需要扩展到多台,那么这个时候如何处理? grpc 有现成的方案?


Python中如何扩展gRPC功能?
12 回复

实现个 DNS 轮询服务
或者试试 grpc + consul


在Python中扩展gRPC功能,核心是围绕Protocol Buffers定义和gRPC服务实现。主要方式有:

  1. 定义新的.proto文件:在现有.proto文件中添加新的service、rpc方法、message类型,或者创建新的.proto文件。这是功能扩展的基础。
  2. 实现新的服务类:继承生成的gRPC服务基类,实现新增的rpc方法。
  3. 使用中间件/拦截器:通过grpc.ServerInterceptorgrpc.UnaryUnaryClientInterceptor等实现认证、日志、监控等横切关注点。
  4. 集成异步支持:使用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 负载均衡。

当然系统化的话就更多了。

回到顶部