三、多活架构的核心概念:流量分发、数据一致性、会话保持

多活架构,说白了就是让多个数据中心同时在线干活。但要让它们真正协同工作,有三个坎儿必须迈过去:流量怎么分、数据怎么对齐、用户怎么不掉线。我每次给团队做设计评审时,都会先问这三个问题,这基本决定了整个多活系统的成败。

3.1 流量分发——用户该去哪?

流量分发是多活的最外层。用户访问进来,第一个接触的就是这个系统。我习惯把它分成三层来看:

  • 第一层:DNS 入口分发 —— 基于地理位置或健康状态,把用户指向最近的可用站点
  • 第二层:负载均衡层 —— Nginx、HAProxy 这类组件,在站点内部做流量引导
  • 第三层:业务路由层 —— 根据用户 ID、请求特征,决定具体由哪个单元处理

我在项目里遇到过这么个坑:光靠 DNS 做全局分发,结果某个站点挂了,DNS 缓存还没刷新,用户愣是打了三分钟才切过去。所以我现在建议,DNS 只做粗粒度分流,精细控制得交给负载均衡器配合健康检查来做。

我的习惯做法: 对延迟敏感的业务,用 Anycast DNS 把用户引导到最近节点;对一致性要求高的写操作,用一致性哈希做单元化路由,减少跨站写扩散。

3.1.1 几种常见的分流策略

策略 特点 适用场景
轮询 请求均匀分摊,简单粗暴 无状态服务,各站点对等
加权分发 按站点容量分配权重 站点配置不完全对等时
哈希路由 相同的 Key 永远去相同站点 有状态服务、单元化架构
Geo 感知 基于地理位置的最近站点 全球部署,降低延迟

你想想看,如果选错了分流策略,后果有多严重。我记得有个案例,团队用了简单轮询,用户的写请求从北京发到上海,读请求又落到深圳,数据一致性直接崩了。

3.2 数据一致性——站点间数据怎么对齐?

数据一致性是多活里最头疼的问题,没有之一。我经常跟团队说,多活的核心不是“活”,而是“一致”。

核心矛盾: 可用性和一致性永远在拔河。你选择强一致,就得接受响应变慢甚至不可用;你追求高可用,就得容忍数据暂时不一致。

3.2.1 一致性模型的抉择

大致分三种:

  • 强一致 —— 写入后立刻全局可见。代价是延迟高,跨站写入需要分布式事务。
  • 最终一致 —— 写入后不保证立即读取到,但最终会一致。大多数互联网业务都选这个。
  • 因果一致 —— 有因果关系的操作保证顺序。折中方案,介于前两者之间。

我在一个金融项目里,遭遇过 CP 和 AP 的艰难抉择。最后因为监管要求必须强一致,我们牺牲了一点可用性,用了 Paxos 协议做跨站复制。嗯,那段时间线上值班压力不小。

3.2.2 常见数据同步模式

模式 实现方式 风险
同步复制 写入主站,同步到从站后才应答 延迟增加,主站故障影响全局
异步复制 写入主站,后台异步同步 主站崩溃可能丢数据
双向同步 各站可写,互相增量同步 冲突解决机制必须可靠
避坑提醒: 我曾经被二次冲突坑过。两条一模一样的记录在不同站点同时修改,结果同步过去覆盖了对方的变更,数据对不上。建议一定引入版本向量或 CRDT 数据结构,或者至少明确的 LWW 策略。

3.3 会话保持——用户怎么不掉线?

会话保持,也叫 Sticky Session。你想想看,用户登录后,他的会话信息存在 A 站内存里。下一次请求被分到 B 站,B 站根本不认识他,直接要求重新登录。这体验能好吗?

3.3.1 三种主流会话方案

  • Sticky Session —— 让同一个用户始终落在同一个站点。实现简单,但站点挂了,会话也跟着丢。
  • 集中式会话存储 —— 用 Redis、Memcached 做共享会话。用户可以无感切换站点,但存储层成了单点。
  • JWT 无状态会话 —— 所有信息编码在 里,站点无需存储。灵活且可扩展,但 泄露风险大。

我个人特别推荐混合方案:用 JWT 做身份认证,把会话状态沉降到分布式缓存里,再辅以 Cookie 做站点亲和性。这样既保留了一定的站点亲和性,又支持了故障切换。

一个小 trick: 我会在 Nginx 层植入一个 sticky route cookie,比如 route=site-a。当站点 A 挂了,负载均衡器主动清除这个 cookie,请求就能马上漂到 B 站,同时 B 站去共享会话存储里拉数据。这样切换时间能从分钟级降到秒级。

3.3.2 代码示例:基于 Cookie 的简单会话保持配置

下面是 Nginx 里最简单的 sticky 配置片段,帮你直观感受下:

upstream backend {
    hash $cookie_route consistent;
    server site-a.example.com;
    server site-b.example.com;
}

server {
    listen 80;
    location / {
        proxy_pass http://backend;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

这段配置通过 hash $cookie_route 确保带有相同 route 值的请求始终落到同一个上游,同时 consistent 参数让新增或减少节点时尽量不扰动已有映射。

三者如何协同?一张图讲清楚

流量分发、数据一致性、会话保持,不是三个孤立的东西。它们之间有天然的依赖关系。下面这张图展示了三者在多活架构中的位置和协作路径:

多活架构三大核心概念协同图 多活架构三大核心概念协同关系 用户请求进入 流量分发层 DNS + 负载均衡 + 业务路由 站点 A 上海数据中心 站点 B 北京数据中心 站点 C 深圳数据中心 会话保持层 Sticky / 共享存储 / JWT 数据一致性层 同步复制 / 最终一致 / CRDT 说明:用户经过流量分发定向到站点;会话保持确保站点内状态可用;数据一致性层通过复制把状态在站点间对齐

从上图可以清晰看到:流量分发是第一关,把请求分到对应站点;站点收到请求后,会话保持确保用户状态不丢;而站与站之间,则靠数据一致性层来同步。三者环环相扣,缺一不可。

总结一下

流量分发、数据一致性、会话保持,这三个概念是设计多活架构的底层逻辑。我衡量一个多活方案靠不靠谱,就看它在三者之间是否能做到合理权衡。别再纠结于“多活”这个词,你真正要解决的是流量怎么分、数据怎么对齐、用户怎么不掉线。把这三点想透了,多活架构的骨架就立住了。