23

nginx grpc streaming负载均衡的排坑和思考 – 峰云就她了

 4 years ago
source link: http://xiaorui.cc/2019/07/27/nginx-grpc-streaming%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%E7%9A%84%E6%8E%92%E5%9D%91%E5%92%8C%E6%80%9D%E8%80%83/?
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

nginx grpc streaming负载均衡的排坑和思考 – 峰云就她了

专注于Golang、Python、DB、cluster

nginx grpc streaming负载均衡的排坑和思考

我们知道nginx在1.13版本之后就可以支持grpc的负载均衡了。官方给出的使用也很简单,类似proxy_pass的语法。但在使用的过程中遇到短连接的问题。

该文章后续仍在不断的更新修改中, 请移步到原文地址 http://xiaorui.cc/?p=5970

大量的timewait短连接:

我们知道grpc是基于http2的,http2的设计就是长连接的设计,在连接上可以跑多个stream来规避http 1.1 中的队头阻塞(Head of line blocking),简单说http1协议导致单个连接不能多路复用。

pic_proxy_meitu_1.jpg

以前在cdn公司的基础架构组干过,所以对nginx算是熟悉了。我知道在使用nginx proxy_pass upstream的时候,需要配置keepalive,不然nginx做负载均衡转发一律会按照短连接处理。 没想到grpc upstream也要配置keepalive。

😅 没有在nginx upstream keepalive连接池配置的时候,timewait的连接会到4w左右。需要注意的是 keepalive是单个worker的连接池,毕竟nginx是多进程的,在nginx的架构模型下是不能连接共享的。

EA8CACB2-8421-4167-A416-20DF31517DE9_meitu_2.jpg
nginx grpc timewait
// xiaorui.cc
server {
    listen       6666 http2;
    server_name  localhost;

    #charset koi8-r;
    access_log  /var/log/nginx/host.access.log  main;

    location / {
        grpc_pass grpc://grpcservers;
    }
}

upstream grpcservers {
    server 10.161.11.181:8090;
    server 10.161.11.180:8090;
    server 10.161.11.179:8090;
    server 10.161.11.178:8090;
    server 10.161.11.177:8090;
    keepalive 2000;
}

有朋友问,使用nginx做grpc的负载均衡是否存在异常? 我使用client -> nginx -> 5个grpc server实例来测试,负载均衡没问题。

grpc unaryRpc可以负载均衡,这个好理解,一个请求一个返回,最后单个连接client的请求会均衡到nginx upstream下游的主机上。经过我的测试,server/client streaming和bidi streaming模式,nginx grpc也完美支持。

只要client跟nginx后面的服务建立了streaming的请求,那么就一直占用这个连接了,同一时间nginx到服务下游的连接不能复用。就是说如果有10000个client streaming长请求,那么nginx就要创建10000个连接对接下游服务。而unary rpc请求是可以复用连接池的。

2.pic_hd_meitu_1.jpg
nginx grpc streaming

grpc的streaming请求可以理解为有状态的请求,nginx是怎么区分的请求?看了下nginx 1.13关于grpc的代码,没怎么看明白 😅。通过tcpdump抓包来分析grpc streaming bidi/unary,没有发现标明grpc请求类型的标识。

我先前开发过一个grpc网关,是通过protobuf描述符、动态注册、各种反射来实现的。通过fullMethod和protobuf描述符里的descriptor可以分析该请求是否有streaming。有兴趣的可以看看我封装的库。 https://github.com/rfyiamcool/grpcall

grpc的负载均衡除了借助外部的gateway之外,还可以使用内置的grpc balancer接口实现。

我司的k8s ingress网关采用envoy做负载均衡,个人觉得envoy的强大值得拥有。这里不是说envoy比nginx强大,我可以负责的说envoy性能比nginx差不少。envoy的优势在微服务体系下有更灵活的配置和适配,比如对接istio,自定义xds接口,rest api -> grpc转换。


大家觉得文章对你有些作用! 如果想赏钱,可以用微信扫描下面的二维码,感谢!
另外再次标注博客原地址  xiaorui.cc
weixin_new.jpg

Golang nginx envoy, nginx grpc, nginx grpc golang, nginx grpc 性能 Bookmark


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK