数据操作带来的复杂度
序言
书接上文,我们谈到CAP设计理论的关键点是数据。那么我们这篇来分析下数据操作为系统设计带来的不同复杂度。(个人归纳和猜想,如有毒鸡汤,还请指出,万分感谢)
高可用,高性能
系统设计复杂度归根结底无不源于高可用,高性能这两点。其中,我个人认为:高性能(抗高并发,系统吞吐量,响应速度),这一块是我们初中高开发人员最常接触,最关注,面试最会问的东西。但受限于单机性能,网络情况(TCP不换,永远的拥塞,流量限制),以及现有技术体系的发展。高性能方面的套路着实有限,不论是微信的高并发抢红包还是jvm调优带来的吞吐量提高,更或者多级缓存带来的响应速度提高,都是有限的技术选择。所以,我认为高性能带来的复杂度问题不大,因为现有业务的复杂度需求都有现成的技术能够满足。而高可用则不然,面对高可用从来都没有最优解,仅仅是因地制宜,选择最合适的方案去规避部分风险,降低成本。所以这里,仅着重分析高可用场景,事实上高性能个人感觉跟CAP没啥关系,高可用则息息相关。高可用还可以分为两点:存储高可用和计算高可用。
存储高可用(数据的增删改)
存储高可用方案的本质都是通过将数据存储到多个存储设备,通过数据冗余的方式来实现高可用,其复杂性主要体现在如何存储(万恶的一致性算法,一致性算法这块会单独起一篇文章来总结)和如何同步(复制延迟,中断带来的数据不一致,分区现象)。
存储高可用的策略还可以按地理位置划分为:单机房,同城异区,跨城异地,跨国异地。
单机房
列举下:主备(意外有备机,其实个人觉得这种架构也就心里安慰。如果故障是业务场景导致的,一套线上环境运行的系统都扛不住,妄想没上过线的备机能抗住?),主从(读压力分摊),双机切换(会自动切换,热备用)。成本从左往右递增,感觉大家应该都懂,不多赘述。(业务量没压力的场景)
同城异区
关键在于搭建高速网络将两个机房连接起来,达到近似单机房的效果。仅仅是鸡蛋不装在一个篮子而已。架构设计上跟单机房雷同。不多赘述。(业务量压力大的场景)
跨城异地
重头戏来了,为什么要采用跨城异地的架构设计?第一:业务量极大,服务停止影响极大,达到等保三级的服务系统。第二:数据量极大,大到量变引发质变,原有架构体系根本撑不住。第三:规避地震、水灾等等极端情况导致服务系统整个不可用(这种如果中招,感觉即使数据全部能追回,马上从新跑一套系统也要好几个钟头。保守点说,出事故到系统能再次提供服务我觉得至少也要个把月。毕竟数据全打水漂,去捞磁盘修复?想想都蛋疼)
这块摊开讲内容太多,我就讲我个人理想的解决方案吧。跨城异地本质上还是做数据的冗余。但这个冗余很要命。物理的距离已经是量变导致质变了。例如,广州机房到北京机房,正常情况下RTT大约是50毫秒左右,遇到网络波动之类的情况,RTT 可能飙升到500毫秒甚至1秒,如果发生丢包,那延迟可能就是几秒几十秒了(而这种长距离传输,丢包还是很有可能的)。那么数据的一致性就面临了极大的挑战,几乎无时无刻不处于分区的情况。这里面临的问题其实就是根本无法保证CP,而我们的数据很可能就有必须要是CP的数据类型。因此这就面临一个无法彻底解决的矛盾:业务上要求数据快速同步,物理上做不到数据快速同步。
ES都知道吧。ES的分片副本我觉得应用在这里就很好。既将数据拆成多份数据(例如3份),每个节点持有其中几份数据(比如3个节点,每个节点持有2份数据),这样子就能保证部分节点异常时其他节点还能正常提供服务(比如以上情况就支持1个节点异常,剩余两个节点依旧持有全量数据,能正常运作)。
书接上文,对于必须要CP的数据,既然无法彻底解决矛盾,那就只能想办法尽量减少影响。引入ES的数据副本思路,将数据根据地区拆分成多份(这看公司财力和业务情况了)。这里要有一定调整,物理上距离过远的城市不适合存储相互的数据副本。例如,一样三个中心,广州,福建,杭州。广州存(广州和福建的数据副本),福建存(福建和杭州的数据副本),杭州存(杭州和广州的数据副本)。广州中心负责广州副本的存储,并将广州副本同步到福建中心,然后接收福建中心的副本。如果福建中心瘫痪了,广州中心的福建副本转为主存(原本为从机,异常后转为主机)提供性能较差的存储支撑(毕竟物理距离在那里)。如果广州中心挂了,在杭州中心的广州副本转为主存。(这里只是例举,事实上可能是华东华南华北这样,个人建议最好前后关联的中心距离相对均匀,呈等边图形)。到这里可论近后备。接下来要搭建远后备方案。远后备:哪怕数据主中心和副本中心全挂了,我依旧希望能尽量保证数据的存储功能。但是再扩展数据备份显然成本过于昂贵,所以,这边我觉得可以设定一个兜底中心,从业务层的直接增删改转向发起增删改的请求。存储各种存储请求,在主中心或副本中心恢复服务后,将对应的请求推送回去。(消息订阅没有问题,但请求先后的排序是个问题,需要具体去分析如何保证请求的先后。这个兜底中心事实上算是base理论最终一致的一种应用了。)
综上所述,对于必须要CP的数据,采用数据副本的存储模式,并根据距离相互成立近后备中心(对于核心业务的CP数据,花大成本搭建高速网络也不是不可以。终究看数据的价值),做兜底方案的远后备(是友好的提示,还是兜底方案好呢。兜底方案仅仅是可以减少系统用户一两次的无用功,毕竟虽然从直接存储变成存储请求,操作做完,消费如果成功还是成功了的。看情况吧,虽然我有这个念头,但我没办法确定这样做的价值能不能盖住它的成本)。
跨国异地
没这么高端的见识,书上说的我也觉得扯蛋。但看看阿里巴巴。国外的阿里巴巴网和国内的阿里巴巴网根本就是两套系统的样子。我觉得跨国很可能真的就可以做成两套服务系统了。其他的大数据分析之类的,可以独立出来做,并不影响。
计算高可用(数据的查)
计算高可用架构,本质是系统提供多份数据备份和多个支撑请求的服务端。以便在单点发生故障后,原本发送到故障节点的请求,分发给非故障节点,不存在数据一致性问题,只需要保证请求可达即可。所以感觉没啥复杂性,无脑水平扩就是了。(合理的多级缓存,服务降级,可以显著减少保证计算高可用的集群数量。因为达到这种需求的服务系统,经常要应对大量请求。一个节点的击穿导致整个集群的雪崩并非不可能,所以也不是真的就无脑扩,合理的多级缓存和服务降级既能节省资金,又能保证高可用,何乐不为呢)
补充一点:服务降级和熔断。以前听过大佬说,服务降级和熔断是打包起来用的,其实很含糊。我给大家落个地。服务降级是指将本服务系统的某些业务或者接口的功能降低,可以是只提供部分功能,也可以是提供旧数据的返回,更或者是完全停掉所有功能。核心思想就是丢车保帅,优先保证核心业务。而熔断的目的是应对外部服务系统故障的情况,既当外部服务系统异常时(比如一分钟内,30%的请求超时)就熔断。打包使用的因为:既然本服务系统的接口依赖的外部服务接口熔断了,那么本服务系统的接口能完美执行的条件可能就缺失了,所以在客服端调用本服务的接口时就采用服务降级的方式给与友好提示。