消息通信机的心跳机制测试浅析

2018-08-13   出处:大商所行业测试中心  作/译者: 大连飞创  

摘要:本文结合某消息通信机的测试实践,介绍了心跳机制的必要性和主要功能。并从发送与检测机制、发送时机、超时时间、发送内容以及超时处理等方面简要介绍了自定义心跳机制的设计思路。在此基础上,结合测试实践,进一步介绍了心跳机制的测试思路和难点,供读者参考。


一、 心跳机制简介
在《期货交易数据交换协议》(JR/T0016-2014)中介绍了心跳机制-“在连接已经建立的情况下,如果任何一侧在相当长的时间内,没有需要向另一侧发送任何报文,那么应该定期发送心跳报文...心跳间隔时间的长度将由交易所决定,或者利用登录报文中的字段进行协商决定。任何一侧,在更长的一段时间内,没有收到任何有意义的报文和心跳报文时,将可以直接断开连接。”从上述介绍中可以了解到,所谓的心跳机制,就像是人靠心跳来泵送血液维持生理机能一样,交易所和会员的主机之间也依靠着心跳报文来告诉对方,我方还活着,请维持彼此间的长连接。换句话说,在众多的连接中,可以利用心跳机制很快侦测出已经断开连接的对端,便于采取后续的措施。因此,简要来说,心跳机制主要由如下两个功能:
1)宣告己方在线,防止连接被对端错误的断开。
2)快速发现已“死亡”的对端,便于采取后续措施。
不仅仅是FTD这样的金融行业协议,凡是涉及到对端间数据通信的应用,心跳机制几乎是一个必备的功能。通用的如Redis和各种MQ,其余行业如网络游戏等,均有自行开发的心跳功能。熟悉TCP通信的读者可能要问了,TCP自身是带心跳功能的,为什么大家还会选择自行开发,而不是使用TCP的KeepAlive心跳功能呢?笔者理解可能有如下的三个考虑:
1)TCP的默认设置不利于及时发现问题。默认的KeepAlive超时需要2小时,期间的探测次数为5次。对于很多服务端应用程序来说,2小时的空闲时间太长。
2)TCP的KeepAlive是全局设置。如果为了能更及时的检测出断开的连接,把tcp_keepalive_time和tcp_keepalive_intvl的设置改小,该服务器上所有TCP应用的KeepAlive检测间隔都会变小。如果该服务器上有多个应用,这种一刀切的方案显然是不能接受的,因为不同应用程序的需求极有可能是不一样的。
3)KeepAlive会消耗额外的带宽和流量。这也是TCP协议层默认并不开启KeepAlive功能的一个原因。在按流量计费的环境下可能会增加费用,另外也可能带来额外的带宽损失,特别是在低带宽的环境下。
所以,考虑到心跳功能的重要性和个性需求,各类型的应用倾向于在各自的底层自行实现心跳功能。



二、心跳机制的设计思路
    笔者参与的某通信机开发项目,其架构如下:

 该项目依靠通信网关与外部机构通过基于TCP的私有消息协议进行双向消息通信,并且在内部采用了MQ消息中间件与所内业务系统进行消息传递。所选用的消息中间件默认每10秒双向发送心跳,如果30秒内未收到对方的心跳消息,则认为对方已经掉线,对端会触发重连/切换等动作。为了保证通信网关和通信客户端连接的可靠性,有必要也设计心跳功能。经过了解,以客户端为例,典型的心跳机制为:
    1 )客户端每隔一个时间间隔发生一个心跳包给通信网关;
    2 )客户端发包时启动一个超时定时器;
    3 )通信网关接收到检测包,应该回应一个心跳包;
    4 )如果客户机收到通信网关的应答包,则说明服务器正常,超时定时器刷新;
    5 )如果客户端的超时定时器超时,依然没有收到应答包,则主动断开连接通信网关,启动后续处理程序;
    6)通信网关采用与客户端相同的心跳机制。
    从上述描述中,可以了解到在自行开发心跳功能时,需考虑以下的问题:
    1)心跳包的发送方;
    2)心跳包的发送时机,超时计算与协商;
    3)心跳包的发送内容;
    4)心跳包与业务包的关系;
    5)心跳超时以后的处理;
1. 心跳包的发送方与检测机制
首先来谈一下心跳的发送方的考虑。在JR/T0016-2014协议以及FTD协议中,使用了双向心跳,即交易所端和会员端,均需要向对方发送心跳包。而在某些C/S应用中,则只需要服务器端向客户端发送心跳包,如果客户端没有返回的话,直接断开该客户端即可。另外,在行情转发等特殊业务场景中,由于采用了UDP组播的技术,也考虑服务端在没有行情的时候,发送心跳包来维持连接,即采用单向心跳。
2. 心跳包的发送时机,超时计算与协商
关于心跳包的发送时机,一般有两个选择,一钟是在双方建立TCP连接之后,立即开始心跳机制。另外一种是,只有当客户端完成登录、鉴权之后,才启动心跳机制,根据约定开始双向或者单向发送心跳。一般认为只有登陆之后,双方的业务往来才正式开展,所以通信层有维持心跳的需要。因此,一般采用后种方式。
心跳的发送时机设计,还存在一个间隔协商的机制。协商内容一般包括两项,心跳超时(Timeout)时间和发送时间间隔(Interval)。为了简化设计,一般由交易所端,或者协议的实现者规定发送间隔,如以Timeout/2,或者Timeout/3的时间间隔发送心跳包。一般心跳包发送的计算公式是:
(系统时间-最近一次收到消息的时间)>=时间间隔(Interval)
公式的左侧是一个滑动计算的时间窗口。而计算这个时间窗口时,也存在两种考虑,即业务包是否作为心跳包来计算。如果将业务包视为心跳包,遇到网络繁忙的时候,就可以不发送心跳包,减少网络开销。
而心跳超时(Timeout)超时时间,则可以考虑是否允许各个客户端和交易所进行协商,或者由交易所端统一规定。当然,一般可以约定一个最低的超时时间,避免过于频繁的心跳报文,对服务器端造成负担。
3. 心跳包的发送内容
至于心跳包的内容,出于降低网络开销的考虑,一般来说都是在逻辑层发送空的echo包来实现。如JR/T0016-2014中约定的心跳报文是报文类型为FTDTypeNone,不含FTDC的FTD报文,而且在扩充报头内有FTDTagKeepAlive项。
4. 心跳包与业务包的关系
至于心跳包和业务包的关系,之前讨论超时时间时,已经提到过了业务包刷新时间窗口的问题。另外一个是需要考虑的是,心跳包是否占用序列号。在FTD协议中,考虑心跳包属于链路管理层报文,不承载业务信息,也不占用序列号,与FIX协议不同。
5. 心跳超时以后的处理
而心跳超时以后的处理,则属于协议可靠性的设计。服务端如果侦测到心跳超时,则除了简单地断开连接,向后端服务进行宣告之外,还需要做好在途消息的缓存、重传等工作。而客户端在侦测到心跳超时后,则需要启动自动重连,重新登录,并维护好消息序列。


三、心跳机制的测试设计
在测试心跳机制时,可能需要考虑到如下的一些问题
    1)心跳超时场景的触发
    2)心跳包各项功能的单测和功能交互测试
    3)心跳的自动化测试
1. 心跳超时场景的触发
心跳超时与普通的业务应用的测试相比更为底层,不能简单的通过页面点击或者接口调用来完成。测试工作中较为基础的部分,是制造心跳超时的场景。笔者在测试内部的一款通信机的过程中,至少采用了如下的几个场景
1)进程挂起
在红帽Linux中,通过kill -19/18 PID来挂起/恢复进程,制造心跳超时的场景。实际的测试,是结合了该通信机的可靠性测试进行的,除了挂起进行,还包括了杀死进程、断网等场景。在测试中,也发现了虽然应用被挂起,但底层的通讯连接仍然存在,只是业务报文无法发送/接收等问题。而这种场景是TCP KeepAlive所无法侦测到的,也证明了自有心跳机制的价值。
2)网络延迟
网络延迟是制造心跳超时的另外一种有效方法。利用Linux提供的网络模拟功能模块netem和traffic control(简称tc)的系统工具,可以模拟出复杂的互联网传输性能,诸如低带宽、传输延迟、丢包等等情况。如下的一条命令就可以模拟出eth0上所有传输都延迟10秒,
tc qdisc add dev eth0 root netem delay 10000ms
这样,就很容易触发应用的心跳超时,进行测试了。
3)客户端消息处理线程处理超时
在通信过程中,为了提升效率,消息的收发一般会采用不同的线程,由专门的消息接收线程来接收来自对端的消息,并以回调函数(callback)的方式接收来自底层的消息。

而这个回调函数通知调用者的过程往往是一个阻塞的过程。因此,当某个OnMessage的方法中强制让线程休眠,来模拟消息接收端处理消息超时,看是否会触发心跳超时。
4)空闲等待
这是最基本的空闲超时了,模拟客户端和服务端无业务往来的场景。当然,也可以来验证诸如只有登录后才有心跳等设计。
2. 心跳功能测试
采用一般测试设计的思路,可以将心跳测试划分为功能单测与功能交互两大类场景。功能单测,就是按照本文第二部分所介绍的心跳机制的设计思路,从发送方、检测机制等内容开始,逐一展开测试,验证心跳机制是否按照设计正常进行工作。譬如笔者在设计中,就发现了被测的通信机缺少了服务端强制向客户端推送心跳超时时间的功能。
在功能单测之外,就是与其余功能交互的场景了,如业务包与心跳包夹杂、业务序列号维持等协议层内容。特别是客户端在心跳超时后重连服务器的功能。
服务器列表: A,B,C,D
一般来说,客户端可以获得一个服务器列表,然后按照顺序依次尝试连接,与第一个可用的服务器建立并维持连接。结合心跳超时中网络延迟等场景,可以制造出循环队列等复杂的场景,测试心跳机制和通信协议的健壮性。
3. 心跳测试的自动化
从超时场景的触发、功能测试的场景等内容,可以看出,心跳测试的自动化是一项比较复杂的工作。主要的挑战来自以下的几点,
1)用例的执行比较复杂。如果从客户端发起测试的话,涉及到客户端接口的调用、心跳响应的获取、网络、进程的操作等内容。
2)结果的验证不是很友好。心跳机制作为应用的底层功能,一般并不向外提供接口,由应用自身进行管理。外部只能通过解析日志等方式来观察和获取相关的信息进行断言。对于手工测试来说,这是比较方便的,但对于自动化来说,就需要做许多额外的工作了。
由此,笔者在通信机的测试中,也仅仅是辅助性地通过程序、脚本来实现客户端的启停、消息发送接收等重复性共工作,结果的验证则主要通过人来判断,并没有实现完全的自动化。


四、参考文献
1、《期货交易数据交换协议》(JR/T0016-2014):http://www.csisc.cn/editorfile/20150211170845302.pdf
2、TCP Keepalive HOWTO:http://www.tldp.org/HOWTO/TCP-Keepalive-HOWTO/overview.html



欢迎给测试窝投稿或参与内容翻译工作,请邮件至editors@testwo.com。也欢迎大家通过新浪微博(@测试窝)或微信公众号(测试窝)关注我们,并与我们的编辑和其他窝友交流。
147°|1474 人阅读|0 条评论

登录 后发表评论
最新文章