一种在网络层清理机器假死时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执行。
转载于:https://blog.51cto.com/baidutech/748596
一种在网络层清理机器假死时TCP连接的方案介绍相关推荐
- tomcat假死排查-数据连接池耗尽
问题背景:测试环境最近隔几周就会出现请求服务没有响应,查看服务进程正产,查看后台日志没有任何报错的日志,查看tomcat下的localhost_access_log.log日志中也没有请求记录. 排查 ...
- 混沌系列 | 其实制造“假死”很容易
点击上方"朱小厮的博客",选择"设为星标" 回复"1024"获取独家整理的学习资料 欢迎跳转到本文的原文链接:https://honeypp ...
- [Linux] 假死分析
所谓假死,就是能ping通,但是ssh不上去:任何其他操作也都没反应,包括上面部署的apache也打不开页面. 作为一个多任务操作系统,要把系统忙死,忙到ssh都连不上去,也不是那么容易的.尤其是现在 ...
- qt开启线程界面假死问题解决
一.前言 在 使用qt高速读取传感器数据时,如果想要将数据实时刷新在界面,就需要开启一个线程单独去跑读取数据函数,并反馈给主程序,否则在主程序中读取和刷新界面会很卡很卡,但是在开启多线程,无外接鼠标键 ...
- Tomcat假死的原因及解决方案
假死:Linux服务器没有崩,浏览器访问页面,出现无法访问的情况但是并没有报4xx或5xx错误,重启tomcat后,恢复正常. 原因:tomcat默认最大连接数(线程数)200个,默认每一个连接的生命 ...
- win10记事本编写html没反应,Win10记事本编辑时无响应假死怎么办
不管是哪一个系统,记事本都是Windows中自带的一个小工具,我们可以进行简单的文字编辑,而很多人升级到win10系统之后,反映说打开记事本编辑的时候遇到无响应假死的情况,如果有编辑了很多文字的话,要 ...
- win10记事本编写html没反应,Win10记事本编辑时无响应假死解决方法(图)
原标题:"Win10记事本编辑时无响应假死怎么办"相关电脑问题教程分享. - 来源:191路由网. 不管是哪一个系统,记事本都是Windows中自带的一个小工具,我们可以进行简单的 ...
- mysql假死_win7系统假死的5种情况和处理方法
情景一:开机假死 开机就假死一般情况是在进入桌面之后,鼠标就变成圆圈状,一直在忙碌状态,会持续很长一段时间,要结束的话只有强制关机. 出现这一类问题的原因比较多,可以从几个方面来看.首先,最好不要安装 ...
- 五种Windows 7假死的情景与处理方法
自己的笔记本经常假死,但又舍不得重装,当然,这种想法也是不对的,我们应该学会解决问题,而不是逃避,这里记录一下解决问题的方法. ------------------------我是分割线------- ...
最新文章
- 如何在ToolBar中显示文字和图标,自定义图标大小,并和MenuItem关联
- sqlite php 函数大全,SQLite 表达式
- Linux:nice函数
- python时间序列动图_python中如何用matlibplot画时间序列图?
- Kettle使用_21 分组与分析窗口函数
- Unity-Animator深入系列---控制IK
- FastReport4.6程序员手册_翻译
- python手绘效果图_2020高校邦《马克笔手绘效果图》判断题答案2020高校邦《网络数据采集与Python爬虫(山东大学定制班级)》见面课测试答案...
- Java将一个对象的属性值copy给另一个相同的对象
- [Database] 不知道表名和字段查找值=1234的数据.
- Atitit 提现功能安全条例 目录 1. 防余额篡改	1 2. 大额 频繁交易预警系统	1 3. 增加审核 流程	1 4. 增加审计	1 5. 财务出款核对	1 6. Other	2 6.1. 数
- 针对我国——国产数据库进行分析
- Ovito教程:高清大图渲染方法
- acer软件保护卡怎么解除_Acer软件保护卡使用说明全解.doc
- 时间片,从多任务系统说起
- 云计算服务包括哪三种服务?怎么定义?
- Scary Movie 4
- android+特殊符号过滤,android 特殊符号过滤
- 痞子衡嵌入式:深扒i.MXRTxxx系列ROM中集成的串行NOR Flash启动SW Reset功能及其应用场合...
- chatgpt+机器人控制器融合(一)