为什么主备切换需要业务重连?

wen IT资讯 235

本文目录导读:

为什么主备切换需要业务重连?

  1. 核心原因:连接状态的丢失
  2. 为什么TCP协议本身无法自动恢复?
  3. 一个形象的类比
  4. 是否所有主备切换都必然需要业务重连?

连接的本质是“状态”,而主备切换破坏了这种状态的一致性。

一个网络连接(比如TCP连接)不仅仅是两端IP和端口的组合,它包含了大量的运行时状态,主备切换发生时,这些状态在备机上是没有的。

下面我们来详细拆解这个过程:

核心原因:连接状态的丢失

一个典型的网络连接(以TCP为例)包含以下几个关键状态:

  1. IP地址和端口:这是连接的“身份证”,在切换前,业务端连接的是主机的IP和端口。
  2. TCP序列号和确认号:保证数据按序、不丢、不重,这是TCP协议可靠传输的核心。
  3. 窗口大小:流量控制,告诉对方自己还能接收多少数据。
  4. 未确认的数据包缓冲区:主机发送了但还没收到ACK的数据,如果主机崩了,这些数据就丢了。
  5. 应用层上下文:比如登录认证的Session、数据库连接池中的事务上下文、请求状态(正在处理哪个SQL语句)等。

当主备切换发生时:

  • 主节点故障:主机因故障(断电、硬件故障、OS崩溃、JVM OOM等)突然挂掉,主机内存中的所有连接状态(TCP控制块、应用层Session)瞬间消失。
  • 服务IP漂移:主备切换的机制是“IP漂移”(VIP,虚拟IP),备机启动后,将自己的网卡绑定上这个VIP,对外宣称“我接替了主机”,但对业务端来说,它看到的服务IP没有变。
  • 备机状态缺失:备机平时可能处于“冷备”或“热备”状态。
    • 冷备:备机上根本没有运行该服务进程,切换后才启动,连接状态自然是零。
    • 热备:备机运行着同样的服务进程,但通常不监听VIP对应的端口,或者不与客户端的连接建立任何同步,备机并不知道客户端发来的SYN包要对应哪个连接,因为它本地没有任何关于客户端连接的数据结构。

为什么TCP协议本身无法自动恢复?

你可能会想,TCP不是可靠协议吗?它应该能重传吧?

答案是:TCP协议的可靠性只保证在“同一个连接的生命周期内”,当连接本身被中断(主机挂掉,没有发出FIN或RST包),TCP无法在两端都不知道的情况下“修复”这个连接。

  1. 对方已死,无法通知:主机突然挂了,根本来不及发送FIN(优雅关闭)或RST(强制复位)包给客户端,客户端对主机的宕机一无所知。
  2. 中间设备视角:传输路径上的交换机、路由器、防火墙并不知道主机挂了,它们只会继续尝试转发数据给主机MAC地址,由于主机网卡已死,数据包被丢弃。
  3. 客户端卡死:客户端如果正在发送数据,发送缓冲区满,应用层会阻塞,客户端如果正在等待数据,会一直等待,直到TCP超时重传耗尽(通常需要几十秒到几分钟),或者应用层自己的心跳超时检测机制发现异常。
  4. 序列号错乱:即使备机以某种方式知道了客户端最后收到的序列号(这很难,因为主机内存丢了),备机也不可能凭空开始一个完整的TCP连接,因为它不知道主机侧已发送但未确认的数据是什么,以及接收缓冲区里已经接收但未处理的数据是什么,任何尝试都会导致TCP校验失败。

一个形象的类比

想象你和你的朋友A(主机)正在打视频电话。

  • 你们聊着天,你们之间的通话线路就是TCP连接
  • 突然,A的手机掉进水里瞬间报废(主机故障),手机里的通话状态、当前聊的话题(应用层上下文)、下一句要说的话(未发送数据)全没了。
  • 这时,B(备机)赶紧拿起了A的手机SIM卡(IP漂移),插进自己手机里,B的号码变成了A的号码(服务IP不变)。
  • 问题来了: 你正在对着电话说话,B能直接接起来继续和你聊吗?
    • 不能。 因为B根本不知道你们刚才聊到哪里了,你的那通电话是一个有状态的会话,在A手机崩溃的那一刻,这个会话就已经物理上终结了。
    • 你必须先挂断电话(识别到连接断开),然后重新拨打这个号码(发起新的TCP连接),B接起电话,他只能说:“喂,A的电话已经转给我了,请重新告诉我你的事。”(业务重连

是否所有主备切换都必然需要业务重连?

是的,几乎所有的“普通”主备切换都需要。

但有几种极端情况可以减少重连的影响实现近乎无感的切换,但它们要么付出巨大代价,要么有严格的限制:

  1. 会话保持/状态同步(热备 + 状态同步):备机不仅运行服务,还通过某种机制(如TCP状态同步技术、共享内存、数据库日志回放)实时同步主机的连接状态和上下文,切换时,备机能接管所有连接,代价:

    • 性能开销巨大:同步所有TCP连接状态和内存数据,会严重拖慢主机。
    • 复杂性极高:同步网络缓冲区、确认号、未ACK数据包等,非常容易出bug。
    • 存在同步窗口:总会有极短时间的数据丢失。
    • 例子:Pacemaker + DRBD(分布式块设备复制)、某些高性能专用的硬件负载均衡器(如F5的Active-Active)。
  2. 无状态服务:如果业务本身是完全无状态的(比如只做静态文件读写、DNS查询),那么连接中断后,客户端重连毫无影响,但绝大多数后端数据库、中间件、Web应用都是有状态的。

  3. 客户端自动重试机制(重连):这是最实际、最常用的方案,客户端集成一个连接池重试策略

    • 当一次请求失败(网络超时、连接被重置、返回错误码),客户端立即尝试从连接池中获取一个新的连接。
    • 连接池发现旧连接无效,自动关闭它。
    • 连接池创建新连接,发起三次握手,连接到已经切换好的备机。
    • 核心库重试:如果是数据库操作,客户端驱动(如JDBC、mongosh)通常内置了自动重连和负载均衡机制(比如spring.datasource.hikarifailover)。
原因 说明
连接状态丢失 主节点故障时,内存中TCP控制块、应用Session、未确认数据全部丢失。
备机无此状态 备机(即使是热备)通常不会同步每个TCP连接的微观状态。
TCP协议限制 TCP本身无法在一个中断的连接上“续传”,需要SYN重新建立握手。
应用层上下文 登录会话、事务ID、HTTP Session等应用层信息在主节点上,备机不知道。

主备切换导致业务重连,本质上是连接的有状态性(Stateful)与状态同步的巨大成本之间的矛盾。 为了可靠性和简单性,业界普遍选择了“切换后废弃旧连接,让业务方通过重连来建立新连接”的策略,优秀的客户端连接池和重试机制可以把这个过程变得非常快(毫秒级),对用户来说几乎无感。

抱歉,评论功能暂时关闭!