首页
解决方案
数据库专业技术服务全栈式PostgreSQL解决方案Oracle分布式存储化数据库云PolarDB一体化解决方案
产品
CLup:PostgreSQL高可用集群平台 CMiner: PostgreSQL中的CDC CData高性能数据库云一体机 CBackup数据库备份恢复云平台 CPDA高性能双子星数据库机 CSYun超融合虚拟机产品 ZQPool数据库连接池 ConshGuard数据保护产品
文档
文章
客户及伙伴
中启开源
关于我们
公司简介 联系我们
中启开源

1. 背景说明

我们在日常运维中,经常需要杀掉一个TCP连接,但情况是不一样的,有些是需要杀掉已经死了的TCP连接,有些是需要终止某个IP过来的连接。

对于死的TCP连接,这个TCP连接上已经没有数据包在传输了,这种连接用tcpkill是无法杀掉的,因为tcpkill杀连接时需要这个连接上有包传输才可以杀掉。

对于一直有包传输的TCP连接,我们可以使用tcpkill杀掉。

2. kill死连接或空闲连接

对于kill死连接或空闲连接,比较好用的工具为hping3。

网上很多文章介绍使用ss命令杀tcp连接,但是ss命令要求内核版本要>=4.9,而且打开了CONFIG_INET_DIAG_DESTROY选项,在Centos7.X下的内核都没有打开这个选项,所有在这些Linux平台下ss命令是无法杀连接的。所以还是建议使用hping3

要求操作系统已经安装了hping3工具,安装方法 :

  1. yum install hping3

下面我们测试一下hping3杀连接的过程:

我们用psql与数据库建立一条连接:

  1. psql -h 127.0.0.1 -p 5432 -Upostgres

然后看连接:

  1. [root@csu06 ~]# netstat -an |grep 5432
  2. tcp 0 0 127.0.0.1:5432 0.0.0.0:* LISTEN
  3. tcp 0 0 127.0.0.1:34724 127.0.0.1:5432 ESTABLISHED
  4. tcp 0 0 127.0.0.1:5432 127.0.0.1:34724 ESTABLISHED
  5. tcp6 0 0 ::1:5432 :::* LISTEN
  6. unix 2 [ ACC ] STREAM LISTENING 58718 /var/run/postgresql/.s.PGSQL.5432
  7. unix 2 [ ACC ] STREAM LISTENING 14877 /tmp/.s.PGSQL.5432

连接为127.0.0.1:34724 -> 127.0.0.1:5432

先用hping3给此socket发一个SYN包,然后此socket会返回一个ACK,从而获得此socket的正确seq序列号,然后再用此seq序列号发一个RST包,就把此连接给关闭了。

发SYN包:

  1. hping3 127.0.0.1 -a 127.0.0.1 -s 37472 -p 5432 --syn -V -c 1

上面命令中的第一个参数127.0.0.1是目标IP,-a 127.0.0.1是源IP,-s 是源端口,-p 5412是目标端口, —syn是发送SYN包,-V显示详细信息(从详细信息中可以获得seq序列号), -c 1发送包1次。

  1. [root@pgdev ~]# hping3 127.0.0.1 -a 127.0.0.1 -s 37472 -p 5432 --syn -V -c 1
  2. using lo, addr: 127.0.0.1, MTU: 65536
  3. HPING 127.0.0.1 (lo 127.0.0.1): S set, 40 headers + 0 data bytes
  4. len=40 ip=127.0.0.1 ttl=64 DF id=4347 tos=0 iplen=40
  5. sport=5432 flags=RA seq=0 win=0 rtt=0.1 ms
  6. seq=0 ack=42230941 sum=14a3 urp=0
  7. --- 127.0.0.1 hping statistic ---
  8. 1 packets transmitted, 1 packets received, 0% packet loss
  9. round-trip min/avg/max = 0.1/0.1/0.1 ms

从上面可以获得ack=42230941,
发SYN包:

  1. hping3 127.0.0.1 -a 127.0.0.1 -s 34724 -p 5432 --rst --win 0 --setseq 42230941 -c 1
  1. [root@csu06 ~]# hping3 127.0.0.1 -a 127.0.0.1 -s 34724 -p 5432 --rst --win 0 --setseq 42230941 -c 1
  2. HPING 127.0.0.1 (lo 127.0.0.1): R set, 40 headers + 0 data bytes
  3. --- 127.0.0.1 hping statistic ---
  4. 1 packets transmitted, 0 packets received, 100% packet loss
  5. round-trip min/avg/max = 0.0/0.0/0.0 ms

再用netstat命令查看此连接,发现连接已经关闭,到psql中输入任何命令,发现连接被关闭了:

  1. postgres=# \d
  2. server closed the connection unexpectedly
  3. This probably means the server terminated abnormally
  4. before or while processing the request.
  5. The connection to the server was lost. Attempting reset: Succeeded.

如果可以支持“ss -K”的平台上,可以用下面命令kill tcp连接:

  1. ss -K sport == 36474

3. kill非空闲连接

非空闲连接是说此连接上一直有包在传送。使用ngrep或tcpkill命令可以完成此任务。ngrep或tcpkill当发现有包过来时,抓取了包中seq序列号,然后用此seq序列号给远端和目标端发送RST包来关闭tcp连接。

安装ngrep的方法:

  1. yum install ngrep

安装tcpkill的方法:

  1. yum install dsniff

查看连接:

  1. [root@csu06 ~]# netstat -anp |grep 5432
  2. tcp 0 0 127.0.0.1:5432 0.0.0.0:* LISTEN 6366/postgres
  3. tcp 0 0 127.0.0.1:36474 127.0.0.1:5432 ESTABLISHED 15212/psql
  4. tcp 0 0 127.0.0.1:5432 127.0.0.1:36474 ESTABLISHED 15213/postgres: pos
  5. tcp6 0 0 ::1:5432 :::* LISTEN 6366/postgres

psql的连接为“127.0.0.1:36474 -> 127.0.0.1:5432”,

运行命令ngrep -d any -K3 '' 'port 36474',发现ngrep命令会等待socket上有包发送:

  1. [root@csu06 ~]# ngrep -d any -K3 '' 'port 36474'
  2. interface: any
  3. filter: ( port 36474 ) and (ip || ip6)
  4. #

然后到psql中运行\d,然后再看ngrep的窗口,发现ngrep发现了发送的数据包,然后发送RST包,再切换回psql再运行\d才发现连接被终止了:

  1. postgres=# \d
  2. Did not find any relations.
  3. postgres=# \d
  4. server closed the connection unexpectedly
  5. This probably means the server terminated abnormally
  6. before or while processing the request.
  7. The connection to the server was lost. Attempting reset: Succeeded.

如果是tcpkill,则命令为:

  1. tcpkill -i any 'port 37018'