• 用nginx做grpc反向代理,nginx到后端server不能维持长连接问题


    问题描述

    公司内部容器平台,接入层用nginx做LB,用户有grpc协议需求,所以在lb层支持grcp反向代理,nginx从1.13开始支持grpc反向代理,将公司使用的nginx包从1.12升级到1.14.0后,增加grpc反向代理配置。配置完成后,打压力测试时,发现接入层机器端口占满而导致服务异常,开始追查问题。

    追查方向

    深入了解grpc协议

    • gRPC是一个高性能、通用的开源 RPC 框架,其由 Google 主要面向移动应用开发并基于HTTP/2协议标准而设计,基于ProtoBuf(Protocol Buffers) 序列化协议开发,且支持众多开发语言。gRPC 提供了一种简单的方法来精确地定义服务和为 iOS、Android 和后台支持服务自动生成可靠性很强的客户端功能库。客户端充分利用高级流和链接功能,从而有助于节省带宽、降低的 TCP 链接次数、节省 CPU 使用、和电池寿命。

    从上述描述可以看出grpc基于http2,client到server应该保持长连接,理论上不应该出现端口占满的问题

    抓包

    • client到接入层抓包看请求状态,发现client到接入层确实是长连接状态。接入层到后端server抓包发现,请求并没有保持长连接,一个请求处理完之后,链接就断开了。

    查nginx跟长连接相关配置

    • nginx长连接相关说明参考以下文档:nginx长连接
    • nginx跟grpc长连接相关配置,发现在1.15.6版本引入了"grpc_socket_keepalive"跟grpc直接相关长连接配置

      Configures the “TCP keepalive” behavior for outgoing connections to a gRPC server. By default, the operating system’s settings are in effect for the socket. If the directive is set to the value “on”, the SO_KEEPALIVE socket option is turned on for the socket.

    参考nginx长连接相关文档做了配置调整之后,发现nginx到server依然是短连接

    将nginx升级到nginx1.15.6(升级过程中由于线上的nginx用到了lua模块,碰到了lua模块不适配问题,解决方案见链接lua模块适配问题)配置grpc_socket_keepalive on,抓包发现,会有少量处理多个请求的长连接存在,但大部分依然是短连接。

    • 开启nginx debug模式

    从debug日志来看nginx确实尝试重用链接,但是从实际抓包看,nginx的链接重用的情况非常少,大部分都是请求处理完之后链接断开,怀疑nginx对grpc反向代理支持的不够理想。

    调整端口回收策略

    • 回到问题本身,要解决的问题是接入层端口占满,各种调整nginx的长连接配置并不能解决这个问题,就尝试从tcp链接端口回收方面解决,大部分的tcp链接都处于TIME_WAIT状态。

    • TIME_WAIT状态的时间是2倍的MSL(linux里一个MSL为30s,是不可配置的),在TIME_WAIT状态TCP连接实际上已经断掉,但是该端口又不能被新的连接实例使用。这种情况一般都是程序中建立了大量的短连接,而操作系统中对使用端口数量做了限制最大能支持65535个,TIME_WAIT过多非常容易出现连接数占满的异常。对TIME_WATI的优化有两个系统参数可配置:tcp_tw_reuse,tcp_tw_recycle 这两个参数在网上都有详细介绍,这是就不展开来讲

    • tcp_tw_reuse参考链接

    • tcp_tw_recycle(Enable fast recycling TIME-WAIT sockets)参考链接

    • 测试来看,开启tcp_tw_reuse并没有解决端口被占满的问题,所以开启了更激进的tcp_tw_recycle,至此端口占用显著降低,问题解决,由于我们接入层并不是用的NAT,所以这个配置不会影响服务。

    结论

    • 通过测试发现nginx对grpc的反向代理支持的不够理想,从nginx到后端server大部分请求不能保持长连接
    • 当用nginx做接入层反向代理时,对tcp参数调优可以避免端口占满等问题的发生

    作者:ylfforme
    链接:https://juejin.im/post/5c9db0155188252d9b377978
    来源:掘金
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • 相关阅读:
    SQL查询SP代码
    MS SQL Server:查询死锁进程(转载)
    批编译、重新编译和计划缓存
    sql like获取以逗号分割的字段内的数据
    SQL Server 2005—数据库管理10个最重要的特点(转载)
    SQL2005数据库镜像配置脚本
    转:SQL 语句优化
    转:SQL SERVER什么时候写日志
    MDX查询几个经典示例
    尾日志备份和时间点还原
  • 原文地址:https://www.cnblogs.com/gao88/p/12010917.html
Copyright © 2020-2023  润新知