【原创】心跳包对状态机的影响

本文以 rabbitmq-c 使用的 AMQP 协议为例说明 heartbeat 对协议状态机的影响。而实际上该问题具有一定普适性。

背景:基于rabbitmq-c源码改造了基于libevent实现的版本,增加了部分功能(一些属性的支持),也省略了部分功能(原代码中的心跳处理)。
问题:在后续需要使用 AMQP 心跳协议进行保活时,发生了状态机遗漏和错乱的情况。

图例

没有考虑 heartbeat 情况下,rabbitmq Producer 的最简状态转换

rabbitmq Consumer 的最简状态转换

简单观察上面的状态切换是发现不了问题的,下给出结合代码状态机实现+实际网络情况的图示。

没有考虑 heartbeat 情况下,给出 rabbitmq Producer 状态转换时 FSM 的稳态以及可能出现网络卡顿的地方。

rabbitmq Consumer 状态转换时 FSM 的稳态以及可能出现网络卡顿的地方。

上面图中的稳态是指 FSM 实现中的某个稳定状态(一般来说,无限循环的状态机都至少应该有一个稳态);而网络卡顿是指由于网络原因或服务器原因导致的协议包延迟到达的现象。

      在事件驱动+FSM的实现模型下,遇到网络卡顿时,可以对超时情况进行记录,并重新触发新一轮的状态处理。就上面的 consumer 而言,当处于 basic.deliver 状态下,在指定时间内没有收到对应协议帧时,只需要重新进入该状态再次等待接收该协议帧即可。

当添加了 heartbeat 处理后,状态机变化如下:

rabbitmq Producer 状态转换时 FSM 的稳定态以及可能出现网络卡顿的地方。

rabbitmq Consumer 状态转换时 FSM 的稳定态以及可能出现网络卡顿的地方。

可以看到,情况变的稍微复杂了点。这种情况下,需要程序能够处理

  • 针对 heartbeat 超时次数进行统计
  • 需要统一发送态下 heartbeat 超时时间和接收态下 heartbeat 超时时间(Producer中的情况),否者会出现判定错误
  • 需要在处理 heartbeat 协议帧前,正确记录当前的状态,以便后续重新恢复到该状态

另外值得说一句的是,FSM 中的稳态其实是和代码实现强相关的,就像上面图中 Producer 的稳态就实现在了 idle 中,而 Consumer 的稳态却安排在了 basic.deliver 。而会出现网络卡顿的点也需要仔细考量。

时间: 2024-10-25 10:38:21

【原创】心跳包对状态机的影响的相关文章

tcp连接探测Keepalive和心跳包

采用TCP连接的C/S模式软件,连接的双方在连接空闲状态时,如果任意一方意外崩溃.当机.网线断开或路由器故障,另一方无法得知TCP连接已经失效,除非继续在此连接上发送数据导致错误返回.很多时候,这不是我们需要的.我们希望服务器端和客户端都能及时有效地检测到连接失效,然后优雅地完成一些清理工作并把错误报告给用户. 如何及时有效地检测到一方的非正常断开,一直有两种技术可以运用.一种是由TCP协议层实现的Keepalive,另一种是由应用层自己实现的心跳包. TCP默认并不开启Keepalive功能,

TCP连接探测中的Keepalive 和心跳包

采用TCP连接的C/S模式软件,连接的双方在连接空闲状态时,如果任意一方意外崩溃.当机.网线断开或路由器故障,另一方无法得知TCP连接已经失效,除非继续在此连接上发送数据导致错误返回.很多时候,这不是我们需要的.我们希望服务器端和客户端都能及时有效地检测到连接失效,然后优雅地完成一些清理工作并把错误报告给用户. 如何及时有效地检测到一方的非正常断开,一直有两种技术可以运用.一种是由TCP协议层实现的Keepalive,另一种是由应用层自己实现的心跳包. TCP默认并不开启Keepalive功能,

为什么基于TCP的应用需要心跳包(TCP keep-alive原理分析)

TCP keep-alive的三个参数 用man命令,可以查看linux的tcp的参数: man 7 tcp 其中keep-alive相关的参数有三个: tcp_keepalive_intvl (integer; default: 75; since Linux 2.4) The number of seconds between TCP keep-alive probes. tcp_keepalive_probes (integer; default: 9; since Linux 2.2)

Delphi2010中DataSnap高级技术(5)—建立稳定服务程序之TCP心跳包的使用

为了能让我们的服务程序更加稳定,有些细节问题必须解决.就如上一讲中提到的客户端拔掉网线,造成服务器上TCP变成死连接,如果死连接数量过多,对服务器能长期稳定运行是一个巨大的威胁. 另外,经过测试,如果服务器上有TCP死连接,那么服务程序连接数据库,也会产生那个一个死连接.这样的话,给数据库服务器也造成威胁.所以,服务器程序编写的好坏,直接影响系统的稳定性! 如何解决TCP死连接的问题,有多种方法,其中最有效的就是心跳包技术. 我们在DSServer的OnConnect事件中加入心跳包代码 use

心跳包机制

心跳包之所以叫心跳包是因为:它像心跳一样每隔固定时间发一次,以此来告诉服务器,这个客户端还活着.事实上这是为了保持长连接,至于这个包的内容,是没有什么特别规定的,不过一般都是很小的包,或者只包含包头的一个空包. 在TCP的机制里面,本身是存在有心跳包的机制的,也就是TCP的选项:SO_KEEPALIVE.系统默认是设置的2小时的心跳频率.但是它检查不到机器断电.网线拔出.防火墙这些断线.而且逻辑层处理断线可能也不是那么好处理.一般,如果只是用于保活还是可以的. 心跳包一般来说都是在逻辑层发送空的

ios后台运行-iOS中,微信在退出后,是否会一直给服务器发送心跳包?

问题描述 iOS中,微信在退出后,是否会一直给服务器发送心跳包? 我在iphone手机的设置中心关掉了微信的通知.但是微信实际上还是可以收到消息.只是手机上没有声音,横幅提醒.所以我猜测:1)微信的消息接受不是推送机制实现的:2)微信在退出后,实际上会一直给服务器发送心跳包.要不然,微信不可能立刻收到消息.不知道我的理解对不对?

java 路由器心跳包-java中怎么接收服务器传过来的json呢?谢谢大家

问题描述 java中怎么接收服务器传过来的json呢?谢谢大家 最近最到了一个关于路由器心跳包,需要用java实现,在取值方面,路由器传过来的是一串json { "gwmac":"c8:3a:35:29:bc:80","gwaddr":"192.168.1.10","gwport":"8080","usrnum":"0", "versio

TCP连接探测中的Keepalive和心跳包. 关键字: tcp keepalive, 心跳, 保活

1. TCP保活的必要性 1) 很多防火墙等对于空闲socket自动关闭 2) 对于非正常断开, 服务器并不能检测到. 为了回收资源, 必须提供一种检测机制.   2. 导致TCP断连的因素 如果网络正常, socket也通过close操作来进行优雅的关闭, 那么一切完美. 可是有很多情况, 比如网线故障, 客户端一侧突然断电或者崩溃等等, 这些情况server并不能正常检测到连接的断开.    3. 保活的两种方式: 1) 应用层面的心跳机制 自定义心跳消息头. 一般客户端主动发送, 服务器接

心跳包中怎样加测试代码?

问题描述 我做的是客户机向主机发送心跳包,想在心跳包中加个特殊校验位,当主机接收到包后分析校验位判断客户端的情况.