今天来谈一谈心跳连接,本文不会给出具体的解决方案,只抛出问题。
使用心跳连接的初衷是检查目标主机是否可用,具体方式通常是通过独立的连接,以一定的频率pingpong,当然timeout也是必不可少的,毕竟丢包也是很正常的事情。
然而,在很多场景下,例如DC NET,心跳连接的方法往往无法生效,给出以下情况:
- IO连接可用,心跳连接不可用
- IO连接不可用,心跳连接可用
在场景1中,至多造成误切后端的问题,而场景2下,如果应用将心跳作为对端正常工作的依据,那么很可能会出现应用IO hang、RT突增的问题。
造成上述问题的主要原因是,在进行系统设计时,经常将endpoint之间的链路抽象为1条,所有的连接均经过该条链路,心跳也是如此,此时可以认为心跳代表对端的健康状况,若心跳不通,则对端出现网络隔离的情况。
然而,实际场景则是不同的5元组几乎拥有不同的网络路径,而独立的心跳连接仅表示其中的一条,这种场景下,心跳连接的意义就退化了,它仅能代表该条链路出现问题,简而言之,当心跳存在时,能够表示对端没有出现网络隔离,而心跳不存在则无法说明任何问题。
(这一代的)网络是不那么可靠的,无论我们用何种方式组织网络架构,failover的能力有多强,始终没法摆脱设备侧的bug以及配置出错等问题,其中不免导致交换机port无法正常工作,而failover能力无法将其收敛的情况,通常将这种问题称为黑洞。发生黑洞的网络设备距离endpoint越近,连接出现问题的概率越大,另外不要寄希望于endpoint的bonding能帮你完成故障收敛,没用的。
针对上述场景,在应用设计时应该如何处理?
首先,对于心跳机制,这里可以直接否掉独立的应用层心跳连接,改为检查连接的健康度,可用的机制至少有如下几点,前者对于应用是透明的,而后者则需要花费较大精力调整应用的IO模型了。
- 开启per connection的tcp keepalive
- 使用per connection的应用层心跳
其次,出现心跳超时后,如何恢复连接?
这里的难点是如何在SLA承诺的时间内恢复连接水位,对于2port组bonging,且endpoint到边缘交换机的上行黑洞的场景,那么此时建连的成功率是50%,在标准方案下,根本无法知道报文从哪个网卡port出去,因此建连是盲目的。只要连接数量够多,可能重试20次建连都无法成功,这个问题可以简称为建连长尾。
如果你的服务端能够承受连接数量成倍增加的副作用,可以考虑使用连接池,而且连接到同一后端的连接数量要足够多。至于非标方案是有很多的,包括改协议栈、改驱动、改交换机hash算法等,但这一切都不是说改就能改的,要考虑一下部署周期及相关风险,所以非标方案的代价还是很大的。
最后,建议将endpoint的心跳信息汇聚到一起,及时隔离链路存在问题的后端,这里需要考虑时效性。