2. 系统架构冗余:从单点到多活
聊到高可用,第一个要干掉的就是单点故障。
我见过太多团队,一开始图省事,一台机器扛所有交易。平时没事,一遇到行情剧烈波动,机器挂了,整个交易系统直接瘫痪。那损失,可不是一台服务器的钱能补回来的。
所以,冗余是必须的。但怎么冗余?这里头门道不少。
2.1 单点架构:为什么它最脆弱?
说白了,单点架构就是所有鸡蛋放一个篮子里。
你的行情网关、订单管理、风控、交易引擎,全跑在一台物理机或一个进程里。一旦这台机器宕机、网络中断、甚至只是内存条故障,整个系统就停了。
我早年在一个期货公司做项目,他们的核心交易节点就是单点。有一次机房空调故障,温度过高导致服务器自动关机。结果呢?整整40分钟无法交易。客户投诉电话打爆了。从那以后,我对单点架构就特别敏感。
- 硬件故障:CPU、内存、磁盘、电源,任何一个坏了都可能宕机
- 网络故障:网卡、交换机、光纤,断了就失联
- 软件故障:操作系统崩溃、JVM OOM、进程死锁
- 人为误操作:配置改错、误删文件、重启顺序搞反
单点架构的恢复时间,通常以分钟甚至小时计。对于低延迟交易来说,这完全不可接受。
2.2 Active-Standby:主备模式,最经典的冗余方案
Active-Standby,也叫主备模式。一台主节点干活,一台备节点等着。
主节点正常时,备节点不处理业务流量,只同步数据。主节点挂了,备节点顶上。
我习惯把这种模式分成两种:
- 冷备(Cold Standby): 备节点平时不启动,甚至不装软件。主节点挂了,人工启动备机,加载数据,切换IP。恢复时间通常在分钟级。
- 温备(Warm Standby): 备节点已启动,软件已部署,数据在同步。主节点挂了,备节点直接接管。恢复时间在秒级。
- 热备(Hot Standby): 备节点和主节点几乎实时同步,甚至共享存储。切换时间可以做到毫秒级。但成本高,复杂度也高。
2.3 Active-Active:双活模式,更高阶的冗余
Active-Active,两个节点同时处理业务。没有主备之分,谁都能干活。
这种架构的好处很明显:
- 利用率高: 两台机器都在处理交易,不像主备模式,备机闲着浪费。
- 故障切换快: 一台挂了,另一台继续处理,流量自动分配,用户几乎无感知。
- 水平扩展: 理论上可以加更多节点,线性提升处理能力。
但双活也有代价。最大的问题是——数据一致性。
两个节点同时处理订单,如果共享同一个数据库或内存状态,就必须解决并发冲突。比如,两个节点同时修改同一个账户的余额,怎么办?
我曾在做股票交易系统时用过双活架构。当时我们用了分布式锁 + 乐观锁来解决冲突。但代价是延迟增加了。嗯,这里要注意,双活不是银弹,它适合无状态或弱状态的服务,比如行情转发、查询服务。对于强一致性的交易核心,要非常谨慎。
2.4 核心对比:Active-Active vs Active-Standby
| 对比维度 | Active-Standby | Active-Active |
|---|---|---|
| 资源利用率 | 低(备机闲置) | 高(所有节点工作) |
| 故障切换时间 | 秒级到分钟级 | 毫秒级 |
| 数据一致性 | 容易保证(单点写入) | 困难(需分布式协调) |
| 实现复杂度 | 低 | 高 |
| 适用场景 | 核心交易、强一致性 | 行情分发、查询、非核心 |
| 成本 | 较低 | 较高(网络、中间件) |
你想想看,如果你的交易系统对延迟极其敏感,比如纳秒级,那Active-Active的分布式协调开销可能就受不了。这时候,Active-Standby反而是更务实的选择。
2.5 脑裂问题:双活架构的头号杀手
脑裂,英文叫Split-Brain。这是分布式系统里最头疼的问题之一。
什么叫脑裂?简单说,就是两个节点之间的心跳网络断了,但节点本身都还活着。它们互相认为对方挂了,于是都开始接管服务,都认为自己才是主节点。
结果呢?两个节点同时写入数据,数据就乱套了。账户余额可能被覆盖,订单状态可能不一致。在交易系统里,这会导致严重的资金差错。
我曾经在一个项目中遇到过脑裂。 当时我们用了双活架构,两个机房之间有一条专线做心跳。结果专线被施工队挖断了。两个机房的节点都检测不到对方,于是都切换成了主模式。等专线恢复,数据已经冲突了。我们花了整整两天才把数据对账清楚。那两天,整个团队都在加班,压力巨大。
2.6 脑裂的解决方案
解决脑裂,核心思路就一个:引入第三方仲裁机制。
常见的方案有几种:
- 仲裁节点(Quorum): 使用一个独立的仲裁节点,或者一组节点(如ZooKeeper、etcd)。节点之间通过仲裁节点确认谁是主。仲裁节点挂了,整个系统不可用,但不会脑裂。
- 隔离(Fencing): 当节点怀疑对方挂了,先尝试把对方隔离掉。比如通过STONITH(Shoot The Other Node In The Head)机制,直接给对方的电源发指令关机。确保对方真的死了,自己再接管。
- 冗余心跳: 不要只用一条心跳线路。用两条甚至三条,比如一条专线、一条带外管理网络、一条IPMI。多条心跳同时断的概率极低。
- 磁盘锁(SCSI Reservation): 在共享存储上,节点通过SCSI预留锁来争抢写入权。谁抢到锁,谁就是主。这个方案在传统存储架构里很常见。
2.7 架构图:双活与脑裂防护
下面这张图,展示了一个典型的双活架构,以及如何通过仲裁节点和冗余心跳来防止脑裂。
这张图里,两个机房各有一个交易节点,都是Active状态。它们之间通过两条独立的心跳链路互相监控。同时,两个节点都向仲裁节点etcd注册并定期续约。
如果心跳全断了,节点不会立刻接管。它会先尝试联系仲裁节点。仲裁节点会告诉它:对方是否还活着。如果仲裁也联系不上,节点会执行STONITH,尝试强制关闭对方电源,确保自己成为唯一的主节点。
2.8 总结一下
架构冗余,不是简单加一台机器就完事了。
- 单点架构最脆弱,必须干掉。
- Active-Standby适合核心交易,简单可靠。
- Active-Active适合高吞吐、弱一致性场景,但要注意脑裂。
- 脑裂的解决方案:仲裁 + 冗余心跳 + 隔离机制,三者缺一不可。
我个人习惯,在交易核心链路用Active-Standby,在行情分发和查询服务用Active-Active。这样既保证了核心交易的数据一致性,又充分利用了资源。
下一节,我们会聊到数据同步的细节。嗯,那是另一个容易踩坑的地方。
公众号:蓝海资料掘金营,微信deep3321