《碟中谍》系列电影中,汤姆克鲁斯主演的亨特特工,无论什么情况,什么环境下都能够有惊无险的完成那些看似不可能的任务。
对于技术人员来说,如果也能像汤姆克鲁斯那样,不管什么mission impossible最后都能解决,那迎娶白富美,当上CTO,走向人生巅峰都不是问题!
“异地多活”看起来就是这样一个万能的大杀器,很多人理想中认为只要实现了“异地多活”,不管是新奥尔良水灾,美加大停电,蓝翔挖掘机。。。。。。等等都不再是问题。
不过,事实上,作为一个解决方案,异地多活是否最终有效,既取决于实施方如何去使用方案如何去设计(千万不要以为捡到倚天剑就是武林盟主),也取决于工具方案本身还有哪些不如意之处固有的约束和限制。要知道,即便是淘宝这样能够做到“异地多活”的公司而言,实际上也仍然有不够完美的地方。如果不意识到这些impossible mission,那么对于异地多活的理解就是错误的。
异地多活本质上是通过异地的数据冗余,来保证在极端异常的情况下业务也能够正常提供给用户,因此数据同步是异地多活设计方案的核心。
通过网络将数据从A地同步到B地,会受限于一个普遍的物理规则,即:光速真空传播是每秒30万公里,在光纤中传输的速度大约是每秒20万公里,再加上传输中的各种网络设备的处理,实际还远远达不到光速的速度。
除了距离上的限制外,中间传输各种不可控的因素也非常多,例如挖掘机把光纤挖断,中美海底电缆被拖船扯断、骨干网故障等,这些故障是第三方维护,业务方根本无能为力也无法预知。
例如广州机房到北京机房,正常情况下RTT大约是50ms左右,遇到网络波动之类的情况,RTT可能飙升到500ms甚至1s,更不用说经常发生的线路丢包问题,那延迟可能就是几秒几十秒了。
因此“实时异地多活”是不可能实现的,因为不管是购买优质的运营商网络,还是采用云方案,甚至是自己拉光纤,都不可能突破物理上的限制,也不可能预防所有的意外情况。在设计异地多活方案的时候,业务上必须考虑这种时延或者中断的情况,不能认为底层传输是绝对可靠的。
不能实现“实时异地多活”就意味着某些极端情况下,肯定会有部分用户的数据无法及时同步到异地机房,这部分用户的业务在切换到异地机房后短时间内会异常。比如说小明在A机房成功发布了一条#某某明星出轨#相关的微博,此时A机房故障,数据还没有同步到B机房,我们将业务切换到B机房,此时小明登录到B机房就看不到自己刚才发的微博了!
这种情况下,运气好一些的话(比如说只是网络设备坏了)需要等到A机房业务恢复,数据重新同步到B机房;运气不好的话(比如说机器坏了,硬盘没坏)需要人工来修复数据,可能耗时几十分钟,也可能耗时几个小时;运气最差的情况下(比如说机房起火,硬盘被烧掉了)可能这些未同步的数据就永久丢失了。
站在用户的角度这样肯定很不爽(甚至直接打电话投诉开骂之类的),但这种现象也是无法完全避免的,异地多活不能保证每一个用户的业务无论在什么场景下都不受损,只要能保证绝大部分用户的业务在异常的场景下继续可用,就是很好的异地多活方案了。
虽然我们无法做到100%可用性,但并不意味着我们什么都不能做,除了抓紧时间恢复业务恢复数据外,为了让用户心里更好受一些,我们可以采取一些措施进行安抚或者补偿,例如:安抚、挂公告(“技术哥哥正在紧急处理”)、事后补偿(代金券、小礼包)等。
异地多活效果看起来很诱人,但如果不假思索贪大求全的要求所有业务都实现异地多活的话,就会把自己带到坑里去。
第一个原因是异地多活是有成本的,包括开发成本和维护成本。需要实现异地多活的业务越多,方案越复杂,投入的设计开发时间越多;同时维护成本也会越高,需要更多的机器,需要更多的带宽。
第二个原因是有的业务理论上就无法实现异地多活。典型的有“余额”和“库存”这两个业务。
以余额为例,假设我们实现了余额的异地多活业务,用户小明有10000块钱,在A机房给女友转账了5000块,还剩余5000块;如果此时A机房异常且数据还没同步到B机房,小明登录到B机房发现自己又有10000块了,小明感觉中彩票了,赶紧又转了10000块给女友,最后出现了小明只有10000块却转账了15000块的问题,对于和资金相关的业务,这样的问题是绝对无法容忍的,哪怕一个用户有问题都不行。
所以,异地多活也不能保证所有业务都异地多活,在设计异地多活方案的时候,需要从业务和用户的角度出发,识别出核心和关键业务,明确哪些业务是必须实现异地多活,哪些是可以不实现异地多活,哪些是不能实现异地多活的。比如“登录”必须实现异地多活、“注册”和“修改用户信息”不一定要实现异地多活。
异地多活方案设计的关键是数据同步,提到数据同步我们自然而然的就想到了底层存储的同步功能,例如Oracle的数据复制、MySQL的数据同步、Redis的数据集群、云数据库跨机房复制等。如果使用这些底层存储方案的同步功能就能实现异地多活,那异地多活方案实现就很轻松了。
但现实显然没有这么美好,原因就在于这些底层存储的同步方案是通用的解决方案,无法基于业务的特点来有针对性的处理,而且这些底层同步方案一样会有bug,一样会延迟。以MySQL为例,MySQL5.1版本的复制是单线程的复制,在网络抖动或者大量数据同步的时候,经常发生延迟较长的问题,短则延迟十几秒,长则可能达到十几分钟。而且即使我们通过监控的手段知道了MySQL同步时延较长,也难以采取什么措施,只能干等。
所以只通过底层存储的同步方案来实现异地多活是不可能的,我们不能把鸡蛋都放到一个篮子里面,需要结合多种手段来实现业务数据同步或者读取,例如:重新生成数据、消息队列异步同步数据、多个机房间通过API直接访问数据等。
综合前面的分析,异地多活设计的理念可以总结为一句话:“采用多种手段,保证绝大部分用户的核心业务异地多活!”
不要被那些号称用一个工具或者方案解决所有问题的说法给骗了,工程领域不存在“银弹”。
=============================================================================================
本文首发云头条,同步CSDN和云栖社区,转发请注明出处。