Python中如何利用nginx原生支持gRPC

在 NGINX 的 v1.13.10 原生支持 gRPC 通信,比如
可以使用 nginx 转发各个服务
location /helloworld.Greeter {
grpc_pass grpc://127.0.0.1:50051;
}
location /helloworld.Dispatcher {
grpc_pass grpc://127.0.0.1:50052;
}
相较与服务注册发现,有了另一种实现方式。

实现及压测示例代码: https://github.com/Xiaoshuai/nginx-grpc

对比与 consul、etcd 或 kafka 这种服务注册及服务发现的微服务组织方式,大家有什么想法哈~
Python中如何利用nginx原生支持gRPC


21 回复

小项目初期阶段是不是直接用 nignx 去组织各个 gRPC 服务,类似于一个 gateway 的作用。这样不用花太多时间在服务的治理上了。


在Python里用nginx原生支持gRPC,核心是配置nginx作为gRPC服务的反向代理。nginx从1.13.10版本开始就内置了对gRPC的代理支持。

你需要一个基本的nginx配置文件,比如叫 grpc_nginx.conf。关键是用 listen 指令的 http2 参数来启用HTTP/2(gRPC的基础),然后在 location 块里用 grpc_pass 指向你的Python gRPC服务器地址。

这里是一个最简配置示例:

events {
    worker_connections 1024;
}

http {
    server {
        listen 50051 http2; # 监听50051端口,启用http2

        location / {
            grpc_pass grpc://localhost:50052; # 代理到本机50052端口的gRPC服务
        }
    }
}

假设你的Python gRPC服务跑在 localhost:50052。用这个命令启动nginx:

nginx -c /path/to/your/grpc_nginx.conf

Python这边,你需要用 grpc 包。下面是一个简单的服务端例子,实现一个 SayHello 方法:

from concurrent import futures
import grpc
import hello_pb2
import hello_pb2_grpc

class Greeter(hello_pb2_grpc.GreeterServicer):
    def SayHello(self, request, context):
        return hello_pb2.HelloReply(message=f'Hello, {request.name}!')

def serve():
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
    hello_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server)
    server.add_insecure_port('[::]:50052') # 服务监听50052端口
    server.start()
    server.wait_for_termination()

if __name__ == '__main__':
    serve()

对应的 hello.proto 文件内容:

syntax = "proto3";

package hello;

service Greeter {
  rpc SayHello (HelloRequest) returns (HelloReply) {}
}

message HelloRequest {
  string name = 1;
}

message HelloReply {
  string message = 1;
}

grpc_tools.protoc 生成 hello_pb2.pyhello_pb2_grpc.py 文件:

python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. hello.proto

客户端调用时需要指定nginx代理的地址(localhost:50051):

import grpc
import hello_pb2
import hello_pb2_grpc

def run():
    with grpc.insecure_channel('localhost:50051') as channel: # 连接到nginx
        stub = hello_pb2_grpc.GreeterStub(channel)
        response = stub.SayHello(hello_pb2.HelloRequest(name='World'))
        print(f"Greeter client received: {response.message}")

if __name__ == '__main__':
    run()

这样,客户端请求 localhost:50051,nginx收到后转发给 localhost:50052 的真实服务,再把响应返回给客户端。这种架构的好处是nginx可以帮你做负载均衡、TLS终止、访问日志等,而你的Python服务只需专注业务逻辑。

总结:配好nginx的grpc_pass,让流量走代理就行。

示例代码 greeter_cient_timeit.py 中,提供了对比测试,HTTP/2.0 的多路复用大约能节省一半的时间。

我一直在想 nginx 有一天会不会也像 apache 一样臃肿

会成为变形金刚,这 nginx 真正的强大的地方,而不是单纯的一个 http 服务器

和 tcp_pass 好像没啥区别。。。

就我一个看成了 gRGB 吗?
我还在想这是什么灯光效果,
nginx 怎么玩的光污染。

对比?楼主你醒醒…根本不是一回事。

#6 区别比较大,tcp_pass 没法做负载均衡

现在有人用上这个版本的 nginx 了嘛?版本太新了,真的不敢更新,后面跟着 openresty 升吧

负载均衡,按请求内容分发节点,这些都是 tcp_pass 做不到的。
原来这类框架不及 http 的就是在这些方面,现在支持 gRPC 以后,估计原来 REST 的一些东西,http 类的 api 接口,微服务都会慢慢的往这边转。

针对多个 gRPC 的服务,可以在 nginx 配置不同端口,类似 url 地址不同。

同意,针对 gRPC,目前 nginx 可以通过 upstream 实现负载均衡。

同意,感觉这东西会接下来会很有用途的

嗯嗯,请帮对比下区别。
想抛出来,让大家讨论下,有哪些是 nginx 的新模块不能实现的,而且这些是否在项目演进各个阶段是否重要 开发维护工作量如何 有什么替代方案。

出 grpc 支持能更好的驱动 ngmesh,这是我个人比较看好的。因为之前基本上就 envoy 可以选择。

另外的就是做 GRPC API Gateway 也多了个选择

#16 caddy 了解一下?

了解 但是 license 不讨好

楼主这个怎么跑 能说明下么?直接 docker-compose?怎么验证呢

我是在 mac 下跑的 nginx 和 python3,可以分别看下这俩目录下的 readme.md 文件

小项目 没那么多服务治理能力刚需

给我在 nginx 里写死,貌似可以一战

回到顶部