容灾级别
从同步方式上分类:
定期备份(冷备) -> 主从副本(主从同步,从库只读)-> 多主数据库(热备)
从主从副本的容灾级别分级:
机器级 -> 机架级 -> 机房级
机房级容灾的实现方式:
-
- 冷备(只是把数据做了一个备份) -> 同城热备(备用机房不使用) -> 同城双活(所有机房都提供服务)-> 两地三中心(机房间距离1000公里以上)-> 伪异地双活 -> 真异地双活(就近读写,实现双主数据库互相同步)
- 灾备分为冷备和热备。冷备:没有服务,只是一份备份的数据。热备: 从机房服务和数据都具备,必要时随时可以启用,但平时没有启用。
- 多活:不同于灾备的一点是从机房也提供服务,一般作为只读的服务。
常见容灾级别
同城双活
两地三中心:
两地是指 2 个城市,三中心是指有 3 个机房,其中 2 个机房在同一个城市,并且同时提供服务,第 3 个机房部署在异地,只做数据冷备。
伪异地双活:
伪异地双活的问题在于两个机房距离较远,受到物理距离的限制,现在,两地之间的网络延迟就变成了「不可忽视」的因素了。
光速约为300k公里/s,北京到上海的距离大约 1300 公里,即使架设一条高速的「网络专线」,光纤以光速传输,一个来回也需要近 10ms 的延迟。况且,网络线路之间还会经历各种路由器、交换机等网络设备,实际延迟可能会达到 30ms ~ 100ms,如果网络发生抖动,延迟甚至会达到 1 秒。不止是延迟,远距离的网络专线质量,是远远达不到机房内网络质量的,专线网络经常会发生延迟、丢包、甚至中断的情况。总之,不能过度信任和依赖「跨城专线」。
因此,异地部署的话就不能再分主从数据库并做读写分离了,否则就是伪异地双活,是不切实际的。
真异地双活:
双主同步:
需要解决双主之间如何同步的问题,常见的存储组件,只有MySQL原生提供了双主架构,支持双向复制数据,Redis、MongoDB 等数据库并没有提供这个功能,RabbitMQ、Kafka这些也不支持。业界也开源出了很多数据同步中间件,例如阿里的 Canal、RedisShake、MongoShake,可分别在两个机房同步 MySQL、Redis、MongoDB 数据。
双主同步存在的问题在于:两个机房同时写同一条数据时,冲突如何解决?如果数据因此出错,后果不堪设想。
解决思路:
1. 自动合并冲突,比如根据写入的时间戳 —— 成本高,不可靠。
2. 从源头上避免冲突,严格分片,避免两个机房写同一条数据。
- 就近接入
- 一致性哈希
当然,最上层的路由层把用户分片后,理论来说同一个用户只会落在同一个机房内,但不排除程序 Bug 导致用户会在两个机房「漂移」。安全起见,每个机房在写存储时,还需要有一套机制,能够检测「数据归属」,应用层操作存储时,需要通过中间件来做「兜底」,避免不该写本机房的情况发生。
这里还有一种情况,是无法做数据分片的:全局数据。例如系统配置、商品库存这类需要强一致的数据,这类服务依旧只能采用写主机房,读从机房的方案,不做双活。双活的重点,是要优先保证「核心」业务先实现双活,并不是「全部」业务实现双活。
星状同步
随着扩展的机房越来越多,当一个机房写入数据后,需要同步的机房也越来越多,这个实现复杂度会比较高。所以业界又把这一架构又做了进一步优化,把「网状」架构升级为「星状」:
这种方案必须设立一个「中心机房」,任意机房写入数据后,都只同步到中心机房,再由中心机房同步至其它机房。
这样做的好处是,一个机房写入数据,只需要同步数据到中心机房即可,不需要再关心一共部署了多少个机房,实现复杂度大大「简化」。
但与此同时,这个中心机房的「稳定性」要求会比较高。不过也还好,即使中心机房发生故障,我们也可以把任意一个机房,提升为中心机房,继续按照之前的架构提供服务。