一种在网络层清理机器假死时TCP连接的方案介绍

简介:

一、背景

  假如应用服务器A上有若干模块连接某数据库服务机器B,当B异常假死,需要将B的请求切换到备份系统,这样已经建立的连接就遗留了下来。如果A上hang住的连接占用的服务线程较多,就可能造成业务系统受到影响,因此需要即时清理掉hang住的连接。

二、问题分析

  出现问题时需要快速释放hang住的连接,我们可能用那些方式来解决呢?

  1,重启假死的机器:受限于响应速度、需要承担重启机器的风险

  2,重启程序:能快速中断hang住的连接,但是

  多类模块(php、java、C、script等)连接数据库,重启方式各异;

  部分模块需要加载数据,启动时间长;

  如果模块同时重启,服务可能会受影响;

  部分模块重启后cache失效,对性能有影响;

 

  3,网络层清理

  根据netstat命令或/proc/net/tcp找到所有与B有关的连接,通过iptables封禁。由于iptables需要包驱动,B假死时iptables不能正常工作,同时A--->B除了TCP重传和心跳检测外,应用层一般为同步读写模式,不保证有包交互;同时长短连接并存,以短连接为主,tcp_keeplive心跳检测特性不能利用。

  4,总结

  hang住的连接主要处于连接建立和ESTABLISHED阶段,建立连接时程序可以配置连接超时,处于连接建立阶段B--->A的包如果没有收到A会重传,这样主要解决机器A上处于阻塞读的连接即可。除了重启程序还有以下方案:

  a,配置读写超时,libmysqlclient默认为1年,应用上有业务需要执行几秒到几百秒,由于系统性能波动,偶尔会有sql执行时间较长,应用不好配置这个值,时间配置太大没有意义。

  b,外部构造RST包关闭连接,由于安全原因RST包需要携带正确的seq,因此需要先记录包序。

  c,使用iptables等工具需要有A ---> B的包驱动

  d,内核API

  问题抽象为:在机器B假死时,如何产生一个A ---> B的数据包

 

三、实现方案

  1,如果是SYN_SEND状态

  tcp本身有重传,线上重传参数有优化;复用重传数据包中的seq 构造一个 [R.] seq=0 ack=seq+1的包就可以关闭连接;其它方式(配置较小的连接超时,handoff对新连接会自动转向)

 

 

  2,如果是ESTABLISHED状态,大部分连接处在这种状态

  在 RFC793(TCP/IP协议)里找到这么一段:

If an incoming segment is not acceptable,an acknowledgment should be sent in reply (unless the RST bit is set, if so drop the segment and return).

内核代码net/ipv4/tcp_input.c中,有具体实现:

static int tcp_validate_incoming(struct sock *sk, struct sk_buff *skb,

struct tcphdr *th, int syn_inerr)

{ …

省略…

/* Step 1: check sequence number */

if (!tcp_sequence(tp, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq)) {

/* RFC793, page 37: "In all states except SYN-SENT, all reset

* (RST) segments are validated by checking their SEQ-fields."

* And page 69: "If an incoming segment is not acceptable,

* an acknowledgment should be sent in reply (unless the RST

* bit is set, if so drop the segment and return)".

*/

if (!th->rst)

tcp_send_dupack(sk, skb);

goto discard;

}

…省略…

}

  因此,可以在A机器上模拟B给A发送一个不带RST标识、seq错误的数据包, A在接收到数据包后会回复一个用于ACK包,此时可以用iptables或其它方式捕获包上正确的seq,发送RST关闭连接,示例图如下:

 

  3,其它状态暂未处理(强制关闭连接的影响、非syn_send,established状态的处理)

 

 

 

四、具体实现

  环境机器A:192.168.1.4;

  环境机器B:192.168.1.13 ;

  端口3306

  方案1:使用iptables回复reset

  1,通过/proc/net/tcp(或netstat –nat|grep ESTABLISHED)获取所有A ---> B的连接

  2,添加iptables规则iptables -A OUTPUT -p tcp -d 192.168.2.13 --dport 3306 -j REJECT --reject-with tcp-reset

  3,对每一个连接,伪造B ---> A数据包hping3 --numeric --spoof 192.168.2.13 --destport <lport> --baseport 3306 --fin 192.168.2.4 #sendip -p ipv4 -is 192.168.2.13 -p tcp -ts 3306 -td <lport> -tff 1 -tfs 0 -tn 0 192.168.2.4

  4,删除iptables规则iptables -D OUTPUT -p tcp -d 192.168.2.13 --dport 3306 -j REJECT --reject-with tcp-reset

  方案2:

  1,通过/proc/net/tcp获取所有A ---> B的SYN_SENT或ESTABLISHED连接

  2,通过libpcap获取B交互的数据包副本,对匹配A ---> B包,回复RST,关闭连接;发送A--->B的fake FIN包,如果B协议栈还能工作,会回复ack;由于A的端口已被关闭,A上的协议栈会回复RST,关闭B--->A的半连接,包示例

10:08:06.338131 IP 192.168.2.10.43376 > 192.168.2.1.80: Flags [S], seq 1586426180, win 14600, options [mss 1460,sackOK,TS val 51262745 ecr 0,nop,wscale 5], length 0

10:08:06.338500 IP 192.168.2.1.80 > 192.168.2.10.43376: Flags [S.], seq 1103847096, ack 1586426181, win 8192, options [mss 1460,nop,wscale 8,sackOK,TS val 31578197 ecr 51262745], length 0

10:08:06.338614 IP 192.168.2.10.43376 > 192.168.2.1.80: Flags [.], ack 1, win 457, options [nop,nop,TS val 51262745 ecr 31578197], length 0

10:08:13.450742 IP 192.168.2.1.80 > 192.168.2.10.43376: Flags [F], seq 0, win 512, length 0

10:08:13.450766 IP 192.168.2.10.43376 > 192.168.2.1.80: Flags [.], ack 1, win 457, options [nop,nop,TS val 51264523 ecr 31578197,nop,nop,sack 1 {3191120200:3191120201}], length 0

10:08:13.452394 IP 192.168.2.1.80 > 192.168.2.10.43376: Flags [R], seq 1103847097, win 512, length 0 10:08:13.453823 IP 192.168.2.10.43376 > 192.168.2.1.80: Flags [F], seq 0, win 512, length 0

10:08:13.454021 IP 192.168.2.1.80 > 192.168.2.10.43376: Flags [.], ack 1, win 260, options [nop,nop,TS val 31578908 ecr 51264523], length 0

10:08:13.454039 IP 192.168.2.10.43376 > 192.168.2.1.80: Flags [R], seq 1586426181, win 0, length 0

  对1的每一个连接,模拟B给A发送数据包,驱动2执行。

 















本文转自百度技术51CTO博客,原文链接:http://blog.51cto.com/baidutech/748596,如需转载请自行联系原作者

相关文章
|
23天前
|
安全 虚拟化
在数字化时代,网络项目的重要性日益凸显。本文从前期准备、方案内容和注意事项三个方面,详细解析了如何撰写一个优质高效的网络项目实施方案,帮助企业和用户实现更好的体验和竞争力
在数字化时代,网络项目的重要性日益凸显。本文从前期准备、方案内容和注意事项三个方面,详细解析了如何撰写一个优质高效的网络项目实施方案,帮助企业和用户实现更好的体验和竞争力。通过具体案例,展示了方案的制定和实施过程,强调了目标明确、技术先进、计划周密、风险可控和预算合理的重要性。
41 5
|
2月前
|
安全 网络架构
MPLS线路构建稳定、高效网络的优选方案
【10月更文挑战第17天】MPLS线路构建稳定、高效网络的优选方案
59 5
|
1月前
|
网络协议 算法 网络性能优化
计算机网络常见面试题(一):TCP/IP五层模型、TCP三次握手、四次挥手,TCP传输可靠性保障、ARQ协议
计算机网络常见面试题(一):TCP/IP五层模型、应用层常见的协议、TCP与UDP的区别,TCP三次握手、四次挥手,TCP传输可靠性保障、ARQ协议、ARP协议
|
2月前
|
Web App开发 缓存 网络协议
不为人知的网络编程(十八):UDP比TCP高效?还真不一定!
熟悉网络编程的(尤其搞实时音视频聊天技术的)同学们都有个约定俗成的主观论调,一提起UDP和TCP,马上想到的是UDP没有TCP可靠,但UDP肯定比TCP高效。说到UDP比TCP高效,理由是什么呢?事实真是这样吗?跟着本文咱们一探究竟!
59 10
|
1月前
|
物联网 5G 数据中心
|
2月前
|
Docker 容器
docker swarm启动服务并连接到网络
【10月更文挑战第16天】
36 5
|
2月前
|
安全 网络架构
无线网络:连接未来的无形纽带
【10月更文挑战第13天】
75 8
|
2月前
|
运维 监控 安全
连锁药店网络优化策略:一站式融合方案提升竞争力
在数字化浪潮下,线上药店通过技术创新和线上线下融合,正重塑购药体验,提供24小时服务和医保结算便利。面对激烈竞争,连锁药店和中小药店纷纷通过优化网络架构、提升服务质量和加强合规管理来增强竞争力,实现高效、安全的数字化转型。
|
2月前
|
网络协议 Java API
【网络】TCP回显服务器和客户端的构造,以及相关bug解决方法
【网络】TCP回显服务器和客户端的构造,以及相关bug解决方法
65 2