起因
今天排查的一个故障,和tcp keepalive有些相关,不过以前阅读UNP时太过随意,因此一直不太了解其机制,这个故障虽然也不是由 tcp keepalive引起的,不过正好也可以总结一下这方面的知识。
tcp keepalive 是 what
根据 linux-doc,tcp keepalive,顾名思义,keep tcp alive,是内核的一种检测tcp链接状态的机制。通俗的说,内核通过一系列的定时器,用来检测tcp链路的对端是否还在线,如果离线并达到一定的条件,内核就会认为链路失效,从而通知应用进行相应的处理
爱与恨
既然是这么一个好东西,那岂不是不要白不要?是的,tcp keepalive是无侵入式的,只需要在创建socket之后,用setsocketopt
设置 SO_KEEPALIVE
标志位即可享受内核级别的健康检查
不过,任何招式都不能走遍天下,tcp keep alive虽然能够有效的解决断链的问题,不过如果有大量的tcp链路开启了keepalive,网络上将可能充斥着大量的心跳包,这是一个不小的负担,因此,具体问题具体分析,还是需要根据应用场景来选择是否开启这个选项。
keepalive的几个参数
在sysctl中,keepalive还有几个参数可以配置,分别是:
tcp_keepalive_time
the interval between the last data packet sent (simple ACKs are not considered data) and the first keepalive probe; after the connection is marked to need keepalive, this counter is not used any further
tcp_keepalive_intvl
the interval between subsequential keepalive probes, regardless of what the connection has exchanged in the meantime
tcp_keepalive_probes
the number of unacknowledged probes to send before considering the connection dead and notifying the application layer
即,加入经过tcp_keepalive_time
,链路上还没有数据流动,则进入tcp keepalive probe阶段,每隔tcp_keepalive_intvl
秒,内核给对端发送一个keepalive probe包,如果连续发送了tcp_keepalive_probes
个仍然没有回应,则认为链路已经失效,从而通知应用程序。
PS:由于用于probe的包只是普通的ack包,因此tcp keepalive只需要本端支持即可,无需双方都有这个功能
nginx中的 keepalive和 proxy_timeout
nginx的stream模块中,listen指令可以配置一个 so_keepalive
的参数,用于开启tcp keepalive,同时也能配置上述的三个参数,另外一个和keepalive机制类似的,则是proxy_timeout
指令,这个指令在http和stream中都存在,意思是nginx和upstream之间,如果在proxy_timeout
秒还没有数据交互,则nginx会关闭链接。
本次遇到的故障,就是在nginx作为网关时,其后面的服务和客户端之间需要维持一个”长连接“,即双方很可能几个小时都不收发数据,但是nginx默认的proxy_timeout
为10分钟。
因此每隔十分钟,客户端发送的数据就会丢失一次,因为nginx关闭与后端的连接后,客户端下一次写会收到一个 RST包,只能重新三次握手建链后重新发送,当将proxy_timeout
设置为一个足够大的数之后,问题就得到了解决
网友评论