MEMCACHE TIME_WAIT过多的解决方法

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

环境:

web: LNMP

mc: memcache

2台机器,相对于memcache服务,web为客户端,mc为服务端

现象:

客户端上11211端口有4W多个TIME_WAIT

服务端正常

我们先查看一下我们现在的tcp连接情况

显示套接字使用摘要(优化后)

ss -s

Total: 1231 (kernel 1447)
TCP:   1910 (estab 1020, closed 796, orphaned 83, synrecv 0, timewait 796/0), ports 1065

Transport Total     IP        IPv6
*         1447      -         -        
RAW       0         0         0        
UDP       2         2         0        
TCP       1114      1114      0        
INET      1116      1116      0        
FRAG      0         0         0 

或 

watch -n1 'cat /proc/net/sockstat'

Every 1.0s: cat /proc/net/sockstat                                                                                                                                                    Sun Apr  8 11:07:44 2018

sockets: used 1232
TCP: inuse 1097 orphan 69 tw 1017 alloc 1098 mem 182
UDP: inuse 2 mem 0
UDPLITE: inuse 0
RAW: inuse 0
FRAG: inuse 0 memory 0

再看tcp连接情况(优化后)

netstat -n | awk '/^tcp/ {++y[$NF]} END {for(w in y) print w, y[w]}'

TIME_WAIT 1378
FIN_WAIT1 33
FIN_WAIT2 237
ESTABLISHED 962
SYN_RECV 1
CLOSING 1
LAST_ACK 14

查看TIME-WAIT状态连接的内存占用,内存占用还是蛮小的

slabtop -o | grep -E '(^  OBJS|tw_sock_TCP|tcp_bind_bucket)'

  OBJS ACTIVE  USE OBJ SIZE  SLABS OBJ/SLAB CACHE SIZE NAME                   
  6018   1262  20%    0.06K    102       59       408K tcp_bind_bucket        
  3870   1860  48%    0.25K    258       15      1032K tw_sock_TCP 

开始分析

TIME_WAIT是通信双方建立TCP连接后,主动关闭连接的一方就会进入TIME_WAIT状态,此时TCP连接还没释放的,需要一个2MSL(2个最长报文生存时间),在高并发情况下(短连接),就会堆积很多TIME_WAIT,(客户端TCP端口数量由net.ipv4.ip_local_port_range取值,假设有42000个TIME_WAIT,那么每秒有700个连接),当TIME_WAIT产生的速度比不上销毁的速度,那势必造成端口不够用(TCP关闭后才不会占用端口),客户端端口不够用了,就无法建立连接!服务端端口不够用了,就会拒绝连接!也无法提供更高的并发。在我们的环境下,WEB是客户端,MC是服务端,大多数服务器端一般执行被动关闭,服务器不会进入TIME_WAIT状态,这也就说明为什么服务端没有大量的time-wait。

在linux中,MSL写死了

 /usr/src/kernels/2.6.32-696.16.1.el6.x86_64/include/net/tcp.h

#define TCP_TIMEWAIT_LEN (60*HZ) /* how long to wait to destroy TIME-WAIT
                                  * state, about 60 seconds     */

既然知道怎么产生TIME_WAIT了,那就好解决了。

1.web使用长连接

nginx使用upstream,指明http1.1协议(默认长连接),并且设置header Connnction=""

       proxy_http_version 1.1;
       proxy_set_header Connection "";

如何提高更高的并发?

1.提供多个IP

2.减少2MSL时间,也就是启用time-wait的重用和快速回收!

客户端(web)

net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_timestamps = 1

MC作为服务端关闭tw_reuse,tw_recycle,开启timestamps(网上并没有写到这个参数是因为默认是开启的)

net.ipv4.tcp_tw_reuse = 0
net.ipv4.tcp_tw_recycle = 0
net.ipv4.tcp_timestamps = 1

来看看几个TCP参数的解释

通过cat /proc/sys/net/ipv4/**  查看

TCP连接的回收:

net.ipv4.tcp_timestamps = 1
#开启TCP时间戳
#以一种比重发超时更精确的方法(请参阅 RFC 1323)来启用对 RTT 的计算;为了实现更好的性能应该启用这个选项。默认1

net.ipv4.tcp_tw_reuse = 1
#表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭;

net.ipv4.tcp_tw_recycle = 1
#表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭。
#在NAT(Network Address Translation)网络下,这个选项不推荐启用,会导致大量的TCP连接建立错误。

net.ipv4.tcp_fin_timeout = 60
#表示如果套接字由本端要求关闭,这个参数决定了它保持在FIN-WAIT-2状态的时间。默认60,网上大部分写30

net.ipv4.tcp_max_tw_buckets = 180000
#表示系统同时保持TIME_WAIT套接字的最大数量,默认值(262144|5000)
#每个TIME_WAIT连接占用内存很少,无需修改

---------以下参数为其他TCP优化建议,建议,建议-----------

TCP连接的保持:
net.ipv4.tcp_keepalive_time = 60
#TCP发送keepalive探测消息的间隔时间(秒),用于确认TCP连接是否有效。缺省是2小时。

net.ipv4.ip_local_port_range = 1024  65535
#表示用于向外连接的端口范围。缺省情况下很小:32768到61000 
#注意!在高并发端口较小的情况下,可能导致在这区间的服务启动不起来,可使用缺省值。

net.ipv4.tcp_keepalive_probes = 9
#TCP发送keepalive探测以确定该连接已经断开的次数。(注意:保持连接仅在SO_KEEPALIVE套接字选项被打开是才发送.次数默认不需要修改,当然根据情形也可以适当地缩短此值.设置为5比较合适)

net.ipv4.tcp_keepalive_intvl = 75
#探测消息发送的频率,乘以tcp_keepalive_probes就得到对于从开始探测以来没有响应的连接杀除的时间。默认值为75秒,也就是没有活动的连接将在大约11分钟以后将被丢弃。(对于普通应用来说,这个值有一些偏大,可以根据需要改小.特别是web类服务器需要改小该值,15是个比较合适的值)

TCP的连接管理:

net.ipv4.tcp_syncookies = 0
#表示是否打开TCP同步标签(syncookie),内核必须打开了CONFIG_SYN_COOKIES项进行编译,同步标签可以防止一个套接字在有过多试图连接到达时引起过载。可防范少量的syn攻击,默认为0,表示关闭。

net.ipv4.tcp_synack_retries = 2
#tcp_synack_retries 显示或设定 Linux 核心在回应 SYN 要求时会尝试多少次重新发送初始 SYN,ACK 封包后才决定放弃。这是所谓的三段交握 (threeway handshake) 的第二个步骤。即是说系统会尝试多少次去建立由远端启始的 TCP 连线。tcp_synack_retries 的值必须为正整数,并不能超过 255。因为每一次重新发送封包都会耗费约 30 至 40 秒去等待才决定尝试下一次重新发送或决定放弃。tcp_synack_retries 的缺省值为 5|6,即每一个连线要在约 180 秒 (3 分钟) 后才确定逾时。

net.ipv4.tcp_retries1 = 3
#该变量设置放弃回应一个tcp连接请求前,需要进行多少次重试。缺省值是3。

net.ipv4.tcp_retries2 = 15
#控制内核向已经建立连接的远程主机重新发送数据的次数,低值可以更早的检测到与远程主机失效的连接,因此服务器可以更快的释放该连接,可以修改为5

net.ipv4.tcp_max_syn_backlog = 819200
#每一个连接请求(SYN报文)都需要排队,直至本地服务器接收,该变量就是控制每个端口的 TCP SYN队列长度的。如果连接请求多余该值,则请求会被丢弃,可修改为819200,容纳更多等待连接的网络连接数,缺省值为2048|1024

总结:

1. tw_reuse,tw_recycle 必须在客户端服务端开启timestamps才管用(timestamps 默认开启)

2. tw_reuse,tw_recycle 在服务端上不需要开启。

3. tw_reuse,tw_recycle 必须在客户端上开启

4. 为何net.ipv4.tcp_tw_recycle = 1 在NAT下不建议开启?

比如你的负载层lvs是使用nat模式

当多个客户端通过NAT方式联网并与服务端交互时,服务端看到的是同一个IP,由于这些客户端的时间戳可能存在差异,所以从服务端的视角看,便可能出现时间戳错乱的现象,进而直接导致时间戳小的数据包被丢弃。

 

参考资料:

记一次TIME_WAIT网络故障   

https://huoding.com/2012/01/19/142

Coping with the TCP TIME-WAIT state on busy Linux servers

https://vincent.bernat.im/en/blog/2014-tcp-time-wait-state-linux

不要在linux上启用net.ipv4.tcp_tw_recycle参数 

http://www.cnxct.com/coping-with-the-tcp-time_wait-state-on-busy-linux-servers-in-chinese-and-dont-enable-tcp_tw_recycle/?utm_source=tuicool&utm_medium=referral

转载于:https://my.oschina.net/longquan/blog/1607414

你可能感兴趣的:(MEMCACHE TIME_WAIT过多的解决方法)