16

高并发中负载均衡器临时端口耗尽问题

 3 years ago
source link: https://www.maideliang.com/index.php/archives/48/
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.

高并发中负载均衡器临时端口耗尽问题

2019.03.03原创文章 0 °C

最近有七层负载均衡器在大量流量的情况下出现异常,表现为time_wait数量过多,客户端请求失败,作为负载均衡器,对于RS来说,就是一个客户端,通常客户端会起一个随机端口一RS的server连接,这时就不得不考虑负载均衡器端口数量受限问题,为了能尽量缕清这个端口数量和qps的问题,有了以下的测试。
1.png

测试场景:

  • 系统环境参数:
    2.png

net.ipv4.tcp_timestamps = 0
net.ipv4.tcp_fin_timeout = 15
net.ipv4.tcp_tw_recycle = 0
net.ipv4.ip_local_port_range = 35535 65535
net.ipv4.ip_local_reserved_ports = 2090,3060,3080,8060,8080-8082,9000,9080,9090,10029,22223-22323
net.ipv4.tcp_tw_reuse = 1

  • ab模拟客户端发起请求qps约1000上下(有超过1000的):
    3.png
  • ab测试结果,有部分失败:
    4.png
  • nginx日志告警端口耗尽:
    5.png

nginx报警端口耗尽时间出现在:2019/03/03 15:42:33

  • tcp端口状态:
    通过每秒输出ss -s查看,nginx报错时的端口数量,基本在15:42:33时端口数量到达系统设置的上限30000:

6.png

  • 但是系统日志message并没有记录端口耗尽告警相关日志:
    7.png
  • 调整ab请求qps为900(低于1000):
    8.png
  • 查看nginx无报错:
    9.png
  • 调整快速回收参数
    net.ipv4.tcp_tw_recycle = 1

同样的端口数范围以及1000qps上下的qps请求条件,测试无异常结果:
10.png

11.png

但是,开启tcp_tw_recycle的话,会有一个时间戳的检验,这时会有一个副作用,就是当客户端的时间不一致时,会有数据包丢弃的风险(开启后会缓存连接的时间戳,60秒内,同一源IP的后续请求的时间戳小于缓存中的时间戳,内核就会丢弃该请求。)

  • 增加一个RS测试:
  • 大于2000qps时:
    12.png

出现临时端口耗尽报错:
13.png
14.png
15.png

  • 低于2000qps时,结果正常:
    16.png

17.png

以上测试示例的结果可以大致得出,作为负载均衡反向代理,没开启net.ipv4.tcp_tw_recycle = 1参数,单个负载均衡器的处理的短连接的qps上限约为net.ipv4.ip_local_port_range/(net.ipv4.tcp_fin_timeout*2)*RS,如上述实例
:单个proxy和rs时:qps=(65535-35535)/(15*2)=1000,单个proxy和两个rs时:qps=(65535-35535)/(15*2)=2000,单个负载均衡器处理超过这个qps时会有端口耗尽从而导致服务异常的风险,但是开启了快速回收,会有时间戳的副作用,应更加实际情况平衡好。

根据上面的测试结论,在一个四元组(五元组)作为一个唯一表示套接字中,在反代的场景下,作为负载均衡器,目的IP地址:目的端口已经固定,所以在源IP和源端口上进行:

  • 增加负载均衡器数量或者在负载均衡器上增加网卡ip,以此来增加四元组的个数
  • 增加端口使用范围
  • 增加后端服务器数量
  • 缩短MSL的Time_Wait回收时间
  • 开启快速回收参数
  • 使用长连接

上面测试讨论的负载均衡器作为客户端反代流量到后端RS时,一般出现在常用的nginx、haproxy等作用在用户空间的反代程序上,但是理论上lvs并不会出现这个问题,因为lvs只是纯粹的流量转发,处理在内核链表上完成,不管是DR和是TUN模式,最终到RS拆解接收的请求报文中,sourceip:port都是真实的客户端ip端口,而不是lvs的ip和端口,所以lvs并不会受到临时端口耗尽的问题,这也是为什么多数情况下,出入口都是先lvs再到后面的nginx或haproxy再调度,但是lvs作为4层反代不能根据实际的业务需求处理七层的URL个性转发。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK