开发者社区> 技术小美> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

一种在网络层清理机器假死时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,如需转载请自行联系原作者

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
《TCP IP 详解卷1:协议》阅读笔记 - 第十章
阅读须知:笔记为阅读《TCP IP 详解卷1:协议》后摘抄的一些知识点,其间也有加入一些根据英文原版的自己翻译和结合网上知识后的理解,所以有些段落之间并不能够串联上或者知识点与书上略有差别(基本差别不大,参考的资料属RFC官方文档)。
1292 0
《TCP IP 详解卷1:协议》阅读笔记 - 第十三章
阅读须知:笔记为阅读《TCP IP 详解卷1:协议》后摘抄的一些知识点,其间也有加入一些根据英文原版的自己翻译和结合网上知识后的理解,所以有些段落之间并不能够串联上或者知识点与书上略有差别(基本差别不大,参考的资料属RFC官方文档)。
1398 0
《TCP IP 详解卷1:协议》阅读笔记 - 第五章
阅读须知:笔记为阅读《TCP IP 详解卷1:协议》后摘抄的一些知识点,其间也有加入一些根据英文原版的自己翻译和结合网上知识后的理解,所以有些段落之间并不能够串联上或者知识点与书上略有差别(基本差别不大,参考的资料属RFC官方文档)。
1324 0
《TCP IP 详解卷1:协议》阅读笔记 - 第二章
阅读须知:笔记为阅读《TCP IP 详解卷1:协议》后摘抄的一些知识点,其间也有加入一些根据英文原版的自己翻译和结合网上知识后的理解,所以有些段落之间并不能够串联上或者知识点与书上略有差别(基本差别不大,参考的资料属RFC官方文档)。
1266 0
《TCP IP 详解卷1:协议》阅读笔记 - 第十四章
阅读须知:笔记为阅读《TCP IP 详解卷1:协议》后摘抄的一些知识点,其间也有加入一些根据英文原版的自己翻译和结合网上知识后的理解,所以有些段落之间并不能够串联上或者知识点与书上略有差别(基本差别不大,参考的资料属RFC官方文档)。
1533 0
《TCP IP 详解卷1:协议》阅读笔记 - 第十五章
阅读须知:笔记为阅读《TCP IP 详解卷1:协议》后摘抄的一些知识点,其间也有加入一些根据英文原版的自己翻译和结合网上知识后的理解,所以有些段落之间并不能够串联上或者知识点与书上略有差别(基本差别不大,参考的资料属RFC官方文档)。
1574 0
《TCP IP 详解卷1:协议》阅读笔记 - 第十六章
阅读须知:笔记为阅读《TCP IP 详解卷1:协议》后摘抄的一些知识点,其间也有加入一些根据英文原版的自己翻译和结合网上知识后的理解,所以有些段落之间并不能够串联上或者知识点与书上略有差别(基本差别不大,参考的资料属RFC官方文档)。
1858 0
《TCP IP 详解卷1:协议》阅读笔记 - 第十七章
阅读须知:笔记为阅读《TCP IP 详解卷1:协议》后摘抄的一些知识点,其间也有加入一些根据英文原版的自己翻译和结合网上知识后的理解,所以有些段落之间并不能够串联上或者知识点与书上略有差别(基本差别不大,参考的资料属RFC官方文档)。
1330 0
《TCP IP 详解卷1:协议》阅读笔记 - 第七章
阅读须知:笔记为阅读《TCP IP 详解卷1:协议》后摘抄的一些知识点,其间也有加入一些根据英文原版的自己翻译和结合网上知识后的理解,所以有些段落之间并不能够串联上或者知识点与书上略有差别(基本差别不大,参考的资料属RFC官方文档)。
1488 0
+关注
6819
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载
冬季实战营第三期:MySQL数据库进阶实战
立即下载