分布式系统总结

分布式系统总结数据库

 

    咱们的系统一直是分布式的。即使在虚拟化、容器技术出现以前,我想他也是一个分布式系统。今天尝试将我对分布式的理解作一些总结。缓存

为何要分布式?

    我想首先是money方面的问题。随着产品支持的容量增长,软件的计算量、存储的数据都变得很大。Grosch定理说CPU的计算能力与它的价格的平方成正比。也就是说若是你付出两倍的价钱,就能得到四倍的性能。这么看其实花钱买高性能的CPU更划算。很遗憾Grosch定理再也不适用了。另外一方面,随着计算量的增长,没有办法找到这样强大的计算机作到这么大的计算量(好比春晚摇红包的计算量估计不可能由一台计算机搞定)。这要求必须将计算能力通常的计算机组织到一块儿,完成超级计算。服务器

    其次,是部署和运维的考虑。全部计算都在一个计算机上,一个故障就全玩玩了。而多个计算机共同工做时,一个故障不会影响大局。在升级时,也能够先升级试用某一些计算机,效果满意再升级所有。网络

    第三,当业务持续增加时,分布式系统能更好应对 —— 多加入一些计算机就好了。并发

    其实不须要多说,云计算的兴起已经说明了一切。负载均衡

 

下面聊一下分布式系统中主要考虑的问题。

总的讲,一个分布式系统必须考虑的几个大块: 接入、计算、存储, 以及这几块之间的数据通讯 ——交换。运维

                               

 

1、对外统一接口,内部结点透明,多业务并发

一个系统对外必定是接口固定的,外部用户必定要有一个固定的入口接入系统。好比提供固定的IP地址、偶联地址、或者某协议地址或域名。内部的计算结点不能直接对外可见,不然没法作可靠性、水平扩展等等工做。这就要求有一个接入部分,同时要在接入部分和内部结点之间作一次负载均衡。一般负载均衡策略是根据本身的业务特色决定的。异步

最简单的就是轮选计算结点,当计算结点的个数发生变化(水平扩展或缩容)时须要负载均衡器感知到便可。但每每业务特色决定了不会选择简单轮选策略,好比:一个业务是长链接的,长链接意思是一个业务流程须要和外部多条消息交互。那么在一个业务流程中,必须将消息都发到同一个计算结点,这就须要设计本身特色的转发策略。好比下面消息3必须也发给第一个结点。分布式

                        

    再有,还可能和数据存储方式有关系,具体来讲:若是计算结点是纯计算(即不保存用户数据),那么每次业务流程的开始均可以随意选择一个计算结点,他从存储部分获取须要的数据,业务完成后再推送回存储部分。但这种方式增长了数据交换的负担。好比下图第一次业务完成后,第二次业务彻底能够选择第三个计算结点。性能

 

                        

    有时产品但愿将用户数据cache到计算结点上面,这样就不用每次业务来临都从存储部分拉去数据,这种方式减小了数据交换,可是带来了其余方面的考虑:用户数据和计算结点有强耦合关系,必须经过必定的负载策略将特定的用户发送到特定的计算结点处理。这又对可靠性、水平扩展方面带来了难度:由于必须根据用户和计算结点的关系进行负载策略的调整。   

    对多业务并发的状况是设计负载均衡策略时要考虑的又一个问题。即对同一个用户同时出现多个业务操做——即流程冲突。好比对一个用户,能够进行业务A,也能够进行业务B。 可是若是在执行业务A的时候,业务B的请求又上来了,系统须要处理这种状况。这里有两个考量:1是须要识别出正在执行A,2是若是处理AB同时进行的业务,仍是终止某一个。 其中考量1又会牵扯到负载均衡策略的设计,好比,同一个用户的业务是否都须要转向同一个计算结点?

                                  

 

    总的说,我认为应该尽量的将计算和数据解耦,由此带来的数据交换的问题能够尝试减小数据量(必须仅传输本次业务流程必须的数据)来减小。同时将业务拆分为更小、独立的service,这样也会下降数据交换。 而这样能够带来计算结点管理的简单。

2、高稳定性

    稳定性来自两个方面:一个是程序健壮,这反映的是每个结点都高可靠。 二是系统健壮,即一个结点出问题不影响整个系统运行。咱们讨论第二点。

    最先期的可靠性保证是简单、粗暴的方式,通常简单粗暴都是最有效的。好比主备热备份的方式。一个单板运行处理业务(主板),另外一个单板空转(备板),就等候着处理板出问题时本身顶上。主板实时的将处理的业务数据同步到备板。能够说备板就是主备的克隆。转发系统一旦发现主板出现问题,直接将消息链路切换到备板,备板能够继续运行。这种方式提供了高可靠性,代价是硬件的低效利用。

也许能够在上述方案上优化。好比互备的方式:即两个板子都处理业务,可是互相作备份。即把两块板子配置成好基友,每一个上面都有对方的配置和运行数据。当一块板子出现问题时,另外一个把他的业务也接管过来,本身干两我的的活。这样彷佛弥补了上面备板空跑的状况,有效利用了资源。但相信睿智的您确定发现:互备的两个基友资源使用率不能够超过50%,一旦超过,也是没法接管对方的业务。 因此本质上并无改变。

    再继续分析,其实系统中计算结点出现故障的几率是不高的,多个结点同时故障的几率更低。因此能够多个业务处理板由一个备板备份(n+1)的方式。这种方式能够提升硬件的使用率。固然还能够作n+m的备份方式。咱们不继续作分析了。

总结这些保证可靠性的思路无非两个方面:一是经过系统存在冗余的计算能力,确保计算机出问题时还有计算结点顶上去。二是在保证这种计算能力的同时,还保证了计算结点的数据(参考粗暴方案中的数据同步) 。咱们要清晰的分开考虑这两个问题,这也是我上面说的计算和数据解耦。 

    事实上,虚拟化技术的出现解决了计算能力的保证,不管是openstack,仍是容器均可以经过他们的技术使得在一个计算结点故障时,再建立一个相同能力的计算结点出来。而数据,应该放到计算以外的地方去。

3、数据存储

    为了讨论方便,咱们将数据分为两类:静态数据(配置)和动态数据(用户数据)。这两种数据的对待方式是不一样的。

    对于静态数据来讲,数据必须随时有效,必须作持久化存储。因此必须在硬盘或数据库中有数据。同时,这类数据的特色是读多写少,或几乎没有写,而读取数据的频率很是高,因此应该作一个读缓存层,数据在内存中cache,保证效率。

    对于用户数据来讲,状况就又不同。用户一旦接入网络,就须要将数据创建并存储下来,之后用户作业务就要操做这些数据。一种方案是将数据存储在业务处理结点上,这是最容易的方案。可是这种方案使计算和数据产生的绑定,在负载均衡、可靠性、水平伸缩方面都须要考虑不少。 另外一种方案是将数据拉远,放到存储服务中。这种方式下降了计算与数据的耦合,可是增长了数据交换,对网络提出了要求,同时数据获取的异步过程对编码也有一些改动。 这方面在前面也讨论了不少,计算与存储绑定的方案, 计算与存储分离的方案咱们都经历过。 总的讲我认为应该分离,由于计算结点可靠性的缘由、计算结点扩展性的缘由等等......固然也是一个权衡,须要根据项目的状况决定。

4、能力水平扩展

    这是虚拟化技术带来的功能。在虚拟化出现以前,咱们扩容一次都要从新配置负荷分担策略,整个系统重启,那时的符合分担与硬件单元是静态配置的。谈不上能力扩展。虚拟化使得系统和硬件解耦,软件看到的再也不是某框某槽某型号的CPU,而是“资源”。在增长、重启一个虚拟机很是容易的状况下,原来的不少问题都再也不是问题:好比一个硬件发生故障我想当即启动一个相同的(这在之前是不可能的除非人跑到机房去弄), 再好比业务量增多了我须要加一些资源(之前也要人去启动更多的服务器)。

    虚拟化技术带来了这些,那么怎么实现系统的能力扩展:

      1. 首先要有一套检测系统来监控系统运行的状态,

      2. 还要有一个决策机制来计算和决策弹性动做的执行

      3. 还有考虑配套的负载均衡的变化、用户数据的访问、正在进行中的业务如何处理等等。。。

      介绍一个集中管理式思路,各个计算结点将资源使用状况上报给总监控结点,再由决策机制计算后决定弹性动做。

 

        弹性过程启动资源申请或释放,同时伴随着负载均衡策略的调整,用户数据的获取等等。这里是比较难的地方,不一样的设计差异也比较大。假若有产品对业务成功率要求变态的高(好比咱们项目),要求在弹性过程当中也要保持业务成功率,而一个业务的流程又很长的时候就很麻烦。具体来讲,好比一个业务要执行10条消息交互,而在第5条的时候监控结点决策出应该扩容,又增长了一些计算结点,这必然致使负载均衡策略的调整。若是不幸的将负载均衡策略设计的与用户有关系,这时一个用户的消息将没法决策往那个计算结点转发。由于新增计算结点后,这个用户的分担策略可能调整到了新结点,可是前5条消息已经在老结点上执行了。。。这里须要根据项目本身的特色设计出符合本身的方案。这里我仍是再次推荐计算和数据分离,而弹性的过程也要与业务特色解耦,掺杂了过多的业务逻辑的弹性过程,是很痛苦的,也难以维护。

        另外,监控决策是须要时间的。若是业务量激增,可能监控来不及反应系统就冲死了。仍是应该有必定的提早预判,由人工来提早扩容。同时,系统的业务忙闲通常是呈规律性的,随着系统的进步,决策系统要增长一些自学习的能力。

5、业务链

        假设一个业务进入系统先交给A业务单元,执行完再交给B,C,... 姑且把ABC叫这个业务的执行链。业务链不该该长,应该尽可能短(固然有时系统成形后就身不禁己了)。在业务链的每一个环节,都会存在一次负载均衡选择。这都会引发不少思考。应该把业务单元作的内聚。 

        同时我也不是主张尽可能减小业务单元的类型,把ABCD类型的业务单元捏成一个。不一样的业务类型单元须要不一样的数据,有不一样的弹性伸缩需求,应该分开。 

        业务链上的结点之间应该送耦合,尽可能不须要知道上下游的标识。 

6、系统运维监控

    主要指整个系统业务运行状况的监控。如各类统计,Log日志,信令跟踪,失败信息,告警等等。

从两个层面来说:

    在系统层面,但愿将业务统计在各个业务单元之间联系起来。好比一条业务通过的业务单元,从中窥测分发状况、执行状况等等。这些东西在分析系统问题时很重要。

    另外一个是代码层面,各类统计最好是非入侵性的,散落在代码各处的统计点对维护来讲很难。