断网场景实验


发布于 2024-06-20 / 23 阅读 / 0 评论 /
断网是常见的混沌测试场景,在C/S架构中,断网对服务端和客户端都有什么样的影响呢?

1.断网场景描述

我之前写过一个nio demo,当服务端通过blade工具进行100%丢包测试时,发现原先的tcp连接在断网后,客户端通过netstat工具查看到的tcp连接还是处于ESTABLISHED状态,没有断开。

等待一段时间后,tcp连接才断开。

1.1.客户端报错

客户端在tcp端开后,有如下报错信息:

Exception in thread "main" java.io.IOException: Connection reset by peer
        at sun.nio.ch.FileDispatcherImpl.read0(Native Method)
        at sun.nio.ch.SocketDispatcher.read(SocketDispatcher.java:39)
        at sun.nio.ch.IOUtil.readIntoNativeBuffer(IOUtil.java:223)
        at sun.nio.ch.IOUtil.read(IOUtil.java:197)
        at sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:379)
        at SocketChannelClientTest.main(SocketChannelClientTest.java:23)

1.2.服务端报错

服务端报错信息如下所示:

Exception in thread "main" java.io.IOException: No route to host
        at java.base/sun.nio.ch.SocketDispatcher.read0(Native Method)
        at java.base/sun.nio.ch.SocketDispatcher.read(SocketDispatcher.java:47)
        at java.base/sun.nio.ch.IOUtil.readIntoNativeBuffer(IOUtil.java:330)
        at java.base/sun.nio.ch.IOUtil.read(IOUtil.java:296)
        at java.base/sun.nio.ch.IOUtil.read(IOUtil.java:259)
        at java.base/sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:417)
        at SelectorServer.main(SelectorServer.java:47)

下面,我们从这个场景入手,分析断网场景中服务端和客户端的表现。

2.影响tcp连接的因素

tcp连接有以下机制保证。

2.1.tcp keepalive机制

tcp自身有个keepalive机制,用于保证连接双方能够保持一定的心跳,保证网络链路的通畅。

keepalive机制的控制由以下三个操作系统级别参数决定。

2.1.1.tcp_keepalive_time

表示发送一次keepalive的报文的间隔时间,单位是秒。

该参数对应Socket的TCP_KEEPIDLE选项,通过setsocketopt进行设置。

可通过以下方式查看该参数的配置值:

[root@ ~]# cat /proc/sys/net/ipv4/tcp_keepalive_time
7200
[root@ ~]#

上述案例表示每隔7200秒发送一次keepalive的报文。

2.1.2.tcp_keepalive_intvl

在发送keepalive报文没有响应的情况下,需要重试,tcp_keepalive_intvl表示重试的时间间隔,单位为秒。

该参数对应Socket的TCP_KEEPINTL选项,通过setsocketopt进行设置。

可通过以下方式查看该参数的配置值

[root@ ~]# cat /proc/sys/net/ipv4/tcp_keepalive_intvl
75
[root@ ~]#

上述案例表示如果没有回应,则75秒后重试。

2.1.3.tcp_keepalive_probes

在发送keepalive报文没有响应的情况下,需要重试,tcp_keepalive_probes表示最多重试次数。

该参数对应Socket的TCP_KEEPCNT选项,通过setsocketopt进行设置。

可通过以下方式查看该参数的配置值。

[root@ ~]# cat /proc/sys/net/ipv4/tcp_keepalive_probes
9
[root@ ~]#

上述案例表示如果没有回应,最多重试9次即认为连接关闭。

2.1.4.tcp keepalive机制存在的问题

正常情况下,连接的一方主动调用close关闭连接时,另一方会收到通知。但是如果tcp连接的另一端突然掉线,或者重启断电,这个时候我们并不知道网络已经关闭。此时如果发送数据失败,tcp会自动进行重传。重传包的优先级高于keepalive,那就意味着,我们的keepalive总是不能发送出去,而此时,我们也不知道该连接已经出错而中断。在较长时间的重传失败之后,我们才会知道。

2.2.tcp重传机制

如果通信双方出现网络错误,比如丢包,则会触发tcp连接的重传机制,重传未得到响应的报文。

如果在重传报文的过程中,网络恢复,由于丢包100%并不会改变TCP连接状态,并且还是处于ESTABLISHED状态,如果一方接收到新的报文,则会回ACK响应报文。

tcp重传机制与以下三个系统级参数相关。

2.2.1.tcp_retries2

表示重传最多次数。

可通过以下方式查看和设置tcp_retries2

[root@ ~]# cat /proc/sys/net/ipv4/tcp_retries2 
15
[root@ ~]# 

net.ipv4.tcp_retries2

2.2.2.tcp_rto_max

表示相邻两次重传之间最大时间间隔,单位秒。

可通过以下方式查看和设置tcp_rto_max

[root@ ~]# cat /proc/sys/net/ipv4/tcp_rto_max
120
[root@ ~]# 

net.ipv4.tcp_rto_max

2.2.3.tcp_rto_min

表示相邻两次重传之间最小时间间隔,单位毫秒。

可通过以下方式查看和设置tcp_rto_min

[root@ ~]# cat /proc/sys/net/ipv4/tcp_rto_min
200
[root@ ~]#

net.ipv4.tcp_rto_min

2.2.4.重传机制中等待时间

每次重传于开始重传的时间起点不是线性关系的。下面以tcp_retries2=15,tcp_rto_min=200,tcp_rto_max=120为例,解析每次重传的等待时间,如下表所示:

tcp_retries2

重传次序

与上一次重传间隔(毫秒)

与重传起点间隔

0

1

200

200ms

1

2

400

600ms

2

3

800

1.4s

3

4

1600

3s

4

5

3200

6.2s

5

6

6400

12.6s

6

7

12800

25.4s

7

8

25600

51s

8

9

51200

102.2s

9

10

102400

204.6s

10

11

120000

324.6s

11

12

120000

444.6s

12

13

120000

564.6s

13

14

120000

684.6s

14

15

120000

804.8s

15

16

120000

924.8s

当tcp_retries2为15时,如果重传15次(或者说15分钟24.8秒)后还无法成功,就断开连接。