如何设计出合理的架构

一、架构师职责架构师是业务和技术的桥梁,要同时懂业务和技术,很容易两头不讨好(业务会说为什么这也不能做那也不能做,技术有可能会说这个东西你为什么要承诺)。根据

一、架构师职责

  架构师是业务和技术的桥梁,要同时懂业务和技术,很容易两头不讨好(业务会说为什么这也不能做那也不能做,技术有可能会说这个东西你为什么要承诺)。

        

  根据架构设计环分析,架构师要具备判断、拆解、取舍的能力。

    判断需要业务理解能力、技术能力、沟通能力;

    拆解能力要有技术广度、宽度、深度;

    取舍要有设计理念、说服能力、决断能力。

  例如业务理解能力,老板说一个系统访问人数预测100W,但是作为架构师要有自己的判断,再例如决断能力,对于简单的业务,老板要求用复杂业务的设计思路,但是架构师要有自己的判断,哪个更适合。因此架构师对于综合能力的要求更高。

        

   除了对应的三种能力外,还应该有三种思维能力:确定性思维、创造性思维、系统性思维

    确定性思维:消除模糊、不确定的说法和信息,例如大量用户等,应该明确为具体多少万用户

    创造性思维:通过排列组合,得到更多的方案

    系统性思维:系统思考,有逻辑和推导过程,例如为什么用Redis而不用Memcached

        

二、架构设计流程

  架构设计 VS 方案设计:

    架构设计指的是影响系统结构的设计,而方案设计指的是不会影响系统结构的设计,从架构设计4R模型中,架构设计的范围:

      Rank:改变系统分层的设计属于架构设计,例如将支付宝提升到和淘宝同级别

      Role:修改角色(增删改拆合)属于架构设计,例如微服务拆分

      Relation:修改角色关系属于架构设计,例如使用消息队列代替访问接口

      Rule:调整角色间的运行规则属于架构设计,例如将MongoDB的选举算法从Bully改为Raft。

  架构设计阶段划分:

    在架构设计阶段可以分为前期、中期和后期,前期主要是进行判断,澄清不确定性,中期是拆解和取舍,设计备选架构方案和选择最终的架构方案,后期是对于架构的细化。

        

   那在前中后期具体应该做什么内容呢:

    前期:和相关人员开会

      前期的主要任务:确认需求、澄清不确定性(确定利益干系人的诉求、消除冲突的诉求、对诉求优先级进行排序) && 识别复杂性(识别核心场景、明确或预估质量需求、试别复杂度)

      工作模式:与业务方交流、与干系人交流

      关键输出:总体业务架构图、核心场景梳理

    中期:架构小组开会 & 写架构设计文档

      主要任务:设计备选方案(头脑风暴、筛选方案、设计备选方案) && 选择备选方案(360评估、明确选择标准、选择最终方案并汇报)

      工作模式:架构小组讨论、架构小组写文档、向利益干系人汇报

      关键输出:备选方案、方案评估结论、方案汇报结论

    后期:写文档  & 开会宣讲

      主要任务:细化架构(按照4R架构定义细化架构) & 完善架构(可维护性、可测试性、可运维性、成本、安全)

      工作模式:写架构设计文档、给技术团队宣讲架构

      关键产出:完整的架构设计方案

    架构验证阶段:

      主要任务:收集意见(开发、测试、运维意见)、跟进架构落地效果(性能测试结果、压力测试结果、线上运维情况)

      工作模式:总结复盘、收集吐槽

      关键输出:架构优化建议、架构迭代计划

  架构设计团队是一个怎样的团队呢?

    架构设计团队是精英团队,小而美的团队,组成类似于外科手术团队(主刀医师、麻醉师、助理医师、洗手护士等),团队成员包括了主架构师和各个领域专家,架构团队的运作方式是项目制的虚拟团队,在架构方案设计时,团队讨论,主架构师拍板。

三、架构设计前期怎么做

  上面讲到,架构设计前期主要是和相关利益人开会,分析需求、澄清不确定性,那么谁是利益干系人呢?

    对于一个系统来说,投资者、监管者、构建者、维护者、使用者、评估者,都是相关的利益干系人:

      投资人:分为内部投资人和外部投资人,内部投资人就是决定投入人力物力财力开发系统的管理者,其利益诉求是:成本、时间、竞争力;一般会是自己的上级或者是事业线的负责人;外部投资人是指购买系统的人,一般是2B业务,其利益诉求是:价格、时间、竞争力。

      监管者:分为政府监管者和媒体监管者,政府监管者是指按照法律对系统进行监督的机构,其利益诉求是:合规、处理投诉;例如银保监会、消委会等;媒体监督者指对系统相关的事件进行广泛报道的媒体,其利益诉求:消息披露、事件回应;例如315晚会、焦点访谈等

      构建者:是指负责构建系统的人员,其利益诉求是:技术、复杂度、时间,例如开发团队、施工队、生产商/供应商等

      维护着:指负责维护系统的人员或其它系统,其利益诉求:可维护性、高可用;例如运维部门、IT部门、IT系统等

      使用者:使用系统完成业务功能的人或其他系统,利益诉求:高可用、易用性,例如用户和下游系统

      评估者:对系统评估的人或者其它系统,利益诉求:可观测性、可测试性;例如:评测团队/测试团队,运维监控体系等。

        

   以钱包项目为例,相关的利益干系人如下所示:

        

   外包系统的相关利益干系人:

        

   有各种利益关系人的利益诉求,有相同的利益诉求,也有不同的利益诉求,也可能有冲突的利益诉求,我们应该如何解决?

    对于诉求的优先级,应按照分组、排序、沟通的步骤进行确认。

    分组:分组可以按照时间、成本、范围、质量几个维度进行分组,但是不同的业务对于诉求的优先级也是不一样的,例如互联网项目一般对成本不是非常敏感,除非需要成千上万的服务,而外包项目的成本就是一个非常重要的诉求点,因此架构师必须具备一定的行业经验。

        

    排序:排序主要考虑差异性(相同维度,不同诉求,例如上级期望五个月交付,大老板期望4个月交付)和冲突性(不同维度,冲突的诉求,例如缩短项目时间,可以通过减少需求、降低项目质量、增加成本(加人))

    取舍:无法做到面面俱到,需要根据业务目标决定哪个优先,一般我们会按照影响力的大小来进行取舍排序:监管者 > 投资者 > 评估者 > 使用者 > 构建者 > 维护者

    沟通:如果是差异性诉求,按照影响力,谁的权力大就听谁的,点对点沟通告诉其结果即可;如果是冲突性诉求,那就需要让各方PK,作为架构师需要给出自己的意见,但是如果各方都不让步,那么就需要让老板拍板。

    复杂度分析:要根据干系人诉求和业务需求核心场景进行分析,试别可能的复杂度,最终明确复杂度

 四、架构设计中期怎么做

  1、选择备选架构

  架构设计常见的思维错误:用最牛的、用最火的、用最熟的,这些都是不可取的,应该按照架构方案设计三原则,选择最合适的架构。

  备选架构应该从架构模式和技术选型两个维度来考虑,架构模式例如高性能、高可用、可扩展等,再细化就是负载均衡、主备、分片、数据复制、微服务、微内核等,技术选型就是应该使用具体哪个技术。

        

   备选架构的设计过程:

    过程可以分为:头脑风暴、红线筛选、4R设计(确定Role、Relattion、基于核心场景来设计Rule)

    头脑风暴是指对可选技术进行排列组合,得到可能的方案,例如我们要用分布式数据一致性和数据存储,分布式数据一致性有ZK和Raft,存储有Redis、Memcached、Mysql、MongoDB等,那么就需要将这些方案进行排列组合

    红线筛选是指根据系统明确的约束和限定,一票否决某些方案,例如MTR直接要求数据库必须使用Oracle,那我们就不能用其他的存储选型;再或者成本要求不超过100W,那肯定就不能用Oracle

  备选架构设计技巧:

    备选架构的数量一般为3~5个最为合适:少于3个可能是因为思维狭隘,考虑不周全;多于5个则需要耗费大量的精力和时间,且方案之间的差别并不明显,做取舍的时候自己都很难取舍。

    备选架构的差异性应该比较明显,例如主备方案 vs 集群方案 、 Zookeeper vs Keeplived,但是像Zookeeper心跳超时是1分钟还是5分钟,这个属于具体的方案设计,并不是架构设计。

    需要覆盖核心的业务场景,即能够实现核心业务场景即可,无需全面细化。

          

   备选架构设计常见困难和应对技巧:

    在备选架构方案设计时,常见的困难就是不知道哪些可用或者不知道能不能用,不知道哪些可用,原因是技术宽度不够,需要平时多积累;不知道能不能用是因为学的太浅或者只学细节,总体的原因就是对一个技术没有从整体了解,这个就需要每个技术的关键性指标,通过比较学习法并对相似技术进行优缺点对比。

        

     例如我们在选型缓存方案时,到底应该用redis还是memcached,那么就需要先知道两者的差异,再从我们使用缓存的场景进行选型,比较学习法:

        

   2、评估和选择备选方案

    常见错误方法就是让领导选,或者使用综合打分的方案,让领导选的问题时可能领导也不是很懂,作为架构师应该做的是选好具体哪个架构,告诉领导为什么选这个;但是有个问题,如果我们的方案和领导的想法相悖,那么我们就要解释我们为什么这么设计,如果领导坚持自己的方案,那也没有办法,只能按照领导的想法先进行设计。综合打分的问题是所有维度一视同仁,因为不同的诉求对于环评的结果影响很大,有的可能是一票否决,因此正确的做法是按照优先级进行评估。

    正确的做法是: 360度环评 + 优先级排序

        

     360度环评样例:这里有个问题,对于性能指标,不要用一个高中低的概念描述,而是应该具体的量化,例如下图中Kafka的TPS为 百万/s。

        

     维度排序样例:样例排序需要根据自己的业务及诉求优先级排序进行排序,按照优先级进行选择

        

     常见备选架构评估维度和注意事项:

      备选架构评估时,一般会从性能、可用性、可扩展、成本、安全、技术复杂度、团队技术储备等几个方面进行评估,但是这个和具体的业务有关,有的场景可能不需要这么多的维度,有的场景可能还要增加一些维度。

      性能和可用性要满足一定时期内业务的发展,但也不是越高约好,例如我们的需求是 1000 TPS,那么我们设计的方案可以达到3000 TPS 就足以满足需求,就没有必要必须要用百万 TPS的组件;

      可扩展,如果有明确的后续扩展内容,就需要进行可扩展的设置,如果无法预测,就不要压测,后续有了再”演化“即可;

      成本是需要综合考虑,例如硬件成本、采购成本、开发成本等,如之前所说,成本也包含人力成本,一般情况下,加机器是成本最低的方案;

      安全是需要综合成本考虑,如果要求特别高的安全,那么我们就需要买更好的防火墙,或者做更多的研发投入,因此安全要在成本范围内做安全处理;

      技术复杂度和团队技术储备需要在满足合适的前提下,尽量使用熟悉的技术,除非团队想开拓新的技术,可以引入新的技术。

        

 五、架构设计后期怎么做

  1、详细架构设计

    备选架构设计:设计完备选架构后,输出备选架构设计文档,给老板和利益干系人看,因为老板和利益干系人不太关心实现的细节,主要关心核心架构模式、技术选型和架构方向等对架构后续演进有关键影响的内容。

    详细架构设计:备选架构确认后,进行详细架构设计,详细架构设计是在备选架构方案的基础上进行细化的,例如细化系统,明确4R,细化更多的细节,同时会优化系统,提升质量,例如成本、安全、可维护性、可测试性、可观测性等,像这些内容部都是在详细架构设计时考虑的,而在备选架构设计时一般不太关注这些;详细架构设计需要输出详细架构设计文档,给下一级架构师和开发团队看。这里说一下为什么会有下一级架构师,有可能我们的项目非常复杂,是一个电商中台,那架构就是领域的划分,例如交易域、支付域、营销域等,那么下一级架构师就可能是负责交易域和支付域的架构,那在下一级架构师可能是设计交易域的各个子系统,然后再下一级可能去设计具体的子系统设计等等,这个要看系统的复杂度。因此详细架构设计也不一定就可以直接给开发团队看并进行开发,这个跟架构规模和分层相关的。

    方案设计:方案设计是根据架构设计来实现自己的需求和一个个的业务功能,例如调用哪个接口,二维码怎么生成等,要输出项目方案设计文档,这个就是给开发团队和测试团队看的,开发团队根据这个进行开发,测试团队根据这个编写测试用例等。

        

     详细架构内容包括架构规范和架构质量:

      架构规范包括:交互协议、数据格式、开发框架等,是用来提升架构落地的效率,以交互协议为例,如果在详细架构方案中不设计,那么多个子系统直接都要互相沟通,会影响效率;其实架构规范就是对Role和Relation的具体设计。

      架构质量包括:可测试性设计、可维护性设计、可观测性设计、以及更多的质量设计等,是用来提升架构落地质量的。

    对于架构规范和架构质量,在设计过程中也是可以调整的,不会影响总体架构设计。

        

     架构设计案例:

      方案一:以Zookeeper中follower将写请求转发给leader为例:

        备选架构设计:follower将写请求转发给leader为例

        详细架构设计:follower和leader之间建立点对点的TCP连接,采用jute作为序列化组件,请求头和响应头设计如下图所示

        

         可以看到,Zookeeper的备选架构方案只是一句话,描述了Role、Relation,但是在详细架构设计时,更细化的表述了Rule,描述了连接协议、序列化组件、请求包、响应包等内容。

      方案二:微服务

        备选架构设计:采用微服务,划分为交易、支付、物流、账务共四个服务,采用Springcloud作为微服务基础框架

        详细架构设计:采用Springboot2.x作为开发框架,服务间数据接口采用Json,服务间的响应时间不能超过50ms。

        

         可以看到,在微服务备选架构设计方案中,只简单描述了Role和Relation,,在详细架构设计方案中具体定义了Rule,例如开发框架,数据交互格式,响应时间等,从上图也可以看到,在详细架构方案设计时,已经将报文格式定了下来,特别是公共包头。

  2、架构设计文档写作

    架构设计文档一般分为三部分,第一部分是业务背景和约束限制,第二部分是总体架构设计和详细架构设计,第三部分是架构质量设计和架构演进规则。

        

     (1)业务背景

        业务背景要描述:系统要解决什么问题、带来什么价值、达成什么目标、完成什么任务、处于什么地位

        典型的案例:推荐系统:实现千人千面;消息队列:解耦服务间依赖;XX系统重构:提升团队开发效率;XX买菜:从0到1构建业务系统

        技巧:使用系统边界黑盒图描述系统定位(Rank和业务背景);

        系统边界黑盒图表示将系统当成黑盒,描述系统与同级别其它系统的交互和关联关系。以OMS系统为例:

        

    (2)约束和限制

        约束一般来自利益干系人的利益诉求。主要包括:成本、时间、技术、质量的限制

        典型的案例:在具体时间点前完成;成本不超过XXX万;数据库必须采用Oracle;质量标准需要符合ISO9001-XXX标准

    (3)总体架构设计

        要描述:Rank、Role、Relation

        描述内容来源于备选架构设计文档,用系统边界白盒图来展示Rank,用系统架构图来展示Role和Relation,其中系统边界描述的是外部结构,系统架构图展示的是内部结构;

        系统边界白盒图表示将系统作为白盒,描述系统内的Role与同级别其他系统的交互和关联关系。

        下图是Promethues的系统边界白盒图,但是这个图有两处画的不太好,即Alertmanager和PromQL,其没有连接到Promethues中具体的模块中。

        

    (4)详细架构设计

        要描述Rule和架构规范

        可以结合备选架构的Rule和架构规范,用系统序列图来展示Rule

    (5)架构质量设计

        需要描述可测试性、可维护性、可运维性、安全/成本等方面的设计

        这里可能会增加新的Role,例如后台管理系统等,因为管理后台并不会影响系统架构,因此在这个阶段是可以增加role的。同时对于质量的设计,并不是所有的系统都需要面面俱到,要根据自己系统的实际需要进行设计。

    (6)架构演进规则

        描述架构分期落地规划,这个主要是为了设定项目计划。

六、消息队列架构设计实战

(一)架构设计前期

  1、需求调研和利益干系人利益诉求分析

  背景:2014年左右,游戏业务发展很快,系统也越来越多,系统间协作的效率很低,例如发布版本和VIP充值,都需要多个系统间频繁调用,每个调用都代表一种独立的接口协议,包括通信方式和数据格式,那么就需要使用消息队列来做系统解耦。

  团队情况:中间件团队规模不大,大约6人左右;中间件团队熟悉 Java 语言,但有一个同事 C/C++ 很牛;开发平台是 Linux,数据库是 MySQL;目前整个业务系统是单机房部署,没有双机房;刚刚被阿里以创纪录的金额收购;

  在做备选方案时,上面的背景和团队情况都会对我们的备选方案有影响。

  利益干系人的利益诉求:

    老板:都被阿里收购了,怎么不切换阿里的?

    业务:你们的技术实力能够自研么?比 Kafka、RabbitMQ 好在哪里?

    运维:你们要保证可维护性,我们已经被 RabbitMQ 搞烦了!

    测试:不建议自己开发,测试工作量太大了!

  对利益干系人的利益诉求进行分析:

    差异性诉求:运维希望自研保证可维护性,业务方希望开源扩展保证可维护性;老板认为直接用阿里的成本小,业务和测试认为用开源的成本小

    冲突性差异:老板希望用阿里的节省成本,运维认为机房3年内无法互通;测试不希望自研而用开源,运维希望自研而不是开源;业务方有的想用 Kafka,有的被 RabbitMQ 搞怕了。

  对利益干系人的诉求排序:可以看到,老板的诉求放到了最低优先级,因此在对利益诉求排序时,架构师要有自己的判断,并不一定是老板的诉求就是最优先的。

    可用性:业务优先考虑可用性

    可维护性:各种维护操作要方便,例如收发消息情况、权限控制、上下线等。

    成本:开发成本不能太高

  复杂度分析:

    高性能:不需要高性能,游戏新版本发布和 VIP 充值的消息并不多。

      高可用:需要,游戏版本发布和 VIP 都是高优先级业务

    可扩展:不需要,消息队列的功能基本明确,无需扩展

    成本:开发投入人力和时间不能太长。

  2、备选架构设计

  (1)备选架构方案一:使用Kafka

      对比Kafka和RabbitMQ,Kafka是Scala语言和java语言编写,性能强劲,业界用的比较多;RabbitMQ用的是Erlang语言编写,可靠性高,业界应用较少。

  (2)备选架构方案二:自研 + mysql 存储

      使用 Java 语言编写消息队列服务器,消息存储使用 Mysql ,SDK 轮询服务器进行消息写入和读取,Mysql双机保证消息尽量不丢,使用Netty自定义消息格式,并且支持 Http 接口。

      这里的方案可以变化,例如底层使用 Hbase 、 Redis 进行存储等。

        

   (3)备选架构方案三:自研集群 + 自研存储

      模拟Kafka的原理,使用Java实现,也可以使用 LVM 数据结构来存储消息,可以保证高可用和高性能,加上可维护性的各种能力,嵌入到已有的运维体系中。

        

   (4)备选架构方案四:使用案例的 MetaQ

      其实就是开源的RocketMQ,是模拟Kafka的实现原理,使用Java语言实现的,刚刚被阿里收购,属于自己人,有什么需求可以给他们提,让他们改;同时 MetaQ 加入了很多新功能,应用性上比Kafka更强大。

(二)架构设计中期

  1、方案评估

  (1)使用Kafka

    人力成本:测试代表倾向于使用Kafka,因为Kafka比较成熟,无需太多测试投入;中间件团队部分研发也支持使用Kafka,因为使用Kafka能节省大量的开发投入

    可维护性:Kafka是Scala语言开发,运维团队没有维护Scala语言开发的系统经验,出问题后很难快速处理;且运维团队已经有一套成熟的运维体系,包括部署、监控、应急等,使用Kafka无法融入这套体系,需要单独投入运维人力

    业务场景:部分人员认为Kafka可能并不适合我们的业务场景,Kafka是大容量的日志消息传输,而我们的消息队列是为了业务数据的可靠传输。

    学习成本:业务主管倾向于采用Kafka方案,因为Kafka已经比较成熟,各个业务团队都或多或少的了解过Kafka。

        

     (2)自研集群 + Mysql 存储

      成本:中间件研发团队认为这个方案简单,实现成本低;但测试代表认为这个方案测试人力投入比较大,因为需要测试消息队列的所有场景;运维认为这个方案硬件成本比较高,一个数据分组就需要4台机器(2台服务器 + 2台数据库)

      可维护性:方案可以维护到现有的运维体系中,而且使用Mysql进行数据存储,数据可靠性有保证,运维团队也有丰富的Mysql运维经验;业务主管对这个方案既不肯定也不否定,因为开发和运维都不是业务团队,对于业务团队来说,只要保证消息队列稳定可靠即可。这里的可维护性是个定性的结论,不是具体的可维护性的功能,因此在方案评估阶段也有可能要对可维护性有一个定性的评估。

      业务场景:可以根据业务场景定制开发各种特性,例如权限控制、消费速度预警等

      性能:部分研发人员对于该方案的的性能持有怀疑态度,毕竟使用Mysql来进行消息存储,性能肯定比不上使用文件系统存储。

      其他:是否会影响中间件团队的技术声誉,毕竟使用Mysql来做消息队列,看起来比较土,比较另类。对于这一方面,要看具体的结果,例如Kafka性能是5W,而使用Mysql做出的性能是2K,那肯定会影响声誉,但是如果使用Mysql能做到三四万,那么不但不会影响声誉,反而会提升声誉,因为我们用了非常简单的方案就做出了性能较高的消息队列。

          

      (3)自研集群 + 自研存储

        成本:要做到稳定可靠的存储系统,需要长时间的迭代和投入成本,自研存储系统的测试难度大,投入也大

        可维护性:可以融入现有的运维体系,但自研存储系统需要较长时间才能成熟,增大了运维风险和投入

        业务场景:可以为业务场景定制开发各种特性,例如权限管理、消费速率预警等

        性能:性能比Mysql高,但是初步评估并不能高很多

        可用性:从历史经验来看,新系统上线肯定 有Bug,而存储系统出现Bug是最严重的,一旦出Bug则会导致数据丢失,影响很严重,运维代表不太赞成这个方案,因为运维遇到过几次类似的存储系统故障导致数据丢失的问题,损失惨重

        团队技术实力:方案复杂度太高,按照目前团队人力和技术实力,要做到稳定可靠的存储系统,有较大风险,运维团队并不相信目前的中间件团队的技术实力足以支撑研发一个存储系统。

           

      (4)直接使用阿里的 MetaQ

        成本:低,接入即可

        可维护性:机房隔离,难以打通,如果在自己的机房部署MetaQ,部署、维护、升级的人力成本太高,且预计三年内不会做机房切换

        业务场景:可以为业务场景定制各种特性,例如权限控制、消费速率预警等

        性能:性能上与Kafka基本持平

        可用性:已经上线运行,支撑阿里业务,久经考验

      后话:上面的评估有两点回头看是有问题的,第一个是业务场景,中间件团队是否会为了我们的业务而定制化,这个要看具体的业务,如果我们的业务是核心业务,那么毫无疑问,是会支持的,但是向这种边缘业务,很难会因为小的业务做定制化开发的;第二个是接入成本,这里不一定指MQ的接入,在很多对接时,对接成本是很高的,需要经过大量的沟通,然后还有确定接入方案等等。

          

  2、360度环评

    在360度环评中,对性能、复杂度(根据团队实力)、硬件成本、人力成本、可维护性、可用性、业务契合度、团队声誉等多个维度进行评估

        

   3、架构决策

    在上图中,如果要是根据评估维度平均选择,那么会发现 1、3、4 的最优方案是很多的,那么是否这些是最合适的呢?在前面说到,在决策架构前,需要确定维度排序规则,按照排序进行决策。

    在本案例中,顺序为:可用性、可维护性、人力成本,那么就按照这个顺序先进性决策:

      可用性:由于自研存储复杂度和风险太大,因此排除 自研集群 + 自研存储 的方案,排除方案三

      可维护性:引入kafka无法嵌入到已有的运维体系中,使用MetaQ也因为机房网络问题和机房规划问题没法解决或者成本太高,因此排除方案一和方案四

      人力成本:人力成本这个需要给领导一个简单的评估,目前看,没有哪个绝对不可用或者必须要用哪一个

    评估完必要性的维度后,就剩下了方案二,然后再看其他的一些评估维度:

      性能:由于业务场景对性能要求不高,因此方案二符合

      复杂度:方案二的复杂度一般

      硬件成本: 自研集群 + mysql 的方式实际算下来只需要不到20台机器,因此也适合

      业务契合度:符合

      团队声誉:如上面所说,如果能用简单的方案做到和开源的性能不是相差很大,对团队的技术声誉反而是个提高,也合适

    经过360度环评后,最终架构决策使用的是 自研集群 + Mysql存储  的方式。

        

 (三)架构设计后期

  1、架构设计细化

    详细架构包括架构规范和架构质量,架构规范用来提升架构落地效率,包括交互协议、数据格式、开发框架等;架构质量用来提升架构落地质量,包括可测试性设计、可维护性设计、可观测性设计和更多质量设计

        

   2、详细架构设计  --  Role & Relation

     客户端Role设计:客户端采用Java语言开发,基于Netty实现与服务端交互

     服务端Role设计:服务器采用Java语言开发,基于Netty与客户端交互,采用Reactor网络模型;两台服务器组成一个sharding,整个系统可以有多个sharding,每个sharding包含一主一从两台服务器;主服务器提供消息读写功能,从服务器只提供读消息功能,服务器基于Zookeeper进行主从切换。

    客户端和服务器的Relation:客户端与服务器采用TCP连接,采用Json传递数据,为了兼容非Java系统,服务端同时提供HTTP接口;这里有可能有人会觉得Json的性能不好,是否要用ProtoBuff,这个要看具体的业务场景,前面分析了,我们对于性能的要求不是特别高,因此不使用也可以,另一方面,Protobuff做序列化时确实性能比Json高,但是在全流程并不一定有性能的影响,为了简单起见,可以先设计使用Json,如果后续发现Json确实是性能瓶颈,则可以转而用ProtoBuff。

    Mysql的Role和Relation:采用Mysql主从同步,每个消息队列对应一张表,消息表最多存储30天内的消息,过期自动清理,直接使用mysql的主从复制来实现数据复制

  3、详细架构设计  --  Rule

    消息发布:消息队列系统有生产者和消费者两个角色,每个角色有唯一名称,消息队列提供 SDK 供各业务系统调用,SDK 从配置中获取所有消息队列系统的服务器信息,SDK 采用轮询算法发起消息写入请求给主服务器,如果主服务器无响应或返回错误,SDK 将发起请求发送到下一台主服务器,相当于在客户端实现了分片功能

    消息读取:消息队列系统提供SDK供各业务系统调用,SDK从配置文件中读取所有消息队列系统的服务器信息,轮流向服务器发起消息读取请求,消息队列服务器记录每一个消费者的消费状态,即消费者已经读取到了哪条消息,当收到消息读取请求后,返回下一条未被读取给消费者,默认情况下,主服务器提供读写服务,当主服务器挂掉后,从服务器提供读消息服务。

    服务器主从切换:同一主从服务器配置相同的group名称,在Zookeeper建立对应的PERSISENT节点,主从服务器启动后,在对应的group节点下建立EPHEMERAL节点,名称分别为master和slave,从服务器watch主服务器的master节点状态,当master节点被删除后,从服务器接管读消息,收到客户端SDK的读消息请求后返回消息,收到客户端SDK的写消息后直接拒绝。

  4、详细架构设计

    画出系统边界图,描述各个系统的Role和Relation,然后再画出消息队列管理系统的模块划分

         

 七、详细架构设计文档模板

前言

[可选,用于总体上描述本篇文档的内容和目的]

[样例:本文是游戏业务线消息队列中间件详细架构设计文档,用于指导消息队列后续的开发、测试和运维]

 

词汇表

[可选,用于明确定义和说明一些英文缩写、术语等,请用表格来呈现

[样例:

Reactor: 网络编程模式

Netty: 开源的网络编程框架

]

 

1. 业务背景

[必选,从以下常见的角度来回答,你准备构建或者重构系统的目的和所处的位置是什么,可以是 1 个角度,也可以是多个角度,一般挑选重点的 3 个目的就差不多了:1.解决什么问题;2.带来什么价值;3.实现什么目标;4.完成什么任务;5.处于什么地位。

]

[样例:

随着前浪微博业务的不断发展,业务上拆分的子系统越来越多,目前系统间的调用都是同步调用,由此带来几个明显的系统问题:

  • 性能问题:当用户发布了一条微博后,微博发布子系统需要同步调用“统计子系统”“审核子系统”“奖励子系统”等共 8 个子系统,性能很低。

  • 耦合问题:当新增一个子系统时,例如如果要增加“广告子系统”,那么广告子系统需要开发新的接口给微博发布子系统调用。

  • 效率问题:每个子系统提供的接口参数和实现都有一些细微的差别,导致每次都需要重新设计接口和联调接口,开发团队和测试团队花费了许多重复工作量。

基于以上背景,我们需要引入消息队列进行系统解耦,将目前的同步调用改为异步通知。

]

[技巧:使用系统边界黑盒图来描述系统与外界的边界和交互关系]

 

2. 约束和限制

[必选,列出明确的约束和限制,常见的约束和限制有:1.投资方的成本要求;2. 监管方的监管要求;3. 技术选型的硬性要求;4. 项目时间要求;5. 质量要求]

[样例:

1.必须在 2021.06.30 号完成

2.成本不能超过 1000 万

3.数据库采用 Oracle

4.质量标准符合 ISO9001-XXXX 标准

]

[技巧:约束和限制越多越好]

 

3. 总体架构

[必选,描述经过备选架构决策后定下来的架构方案,这一章主要是描述架构的 3R:Rank、Role、Relation]

[技巧:1. 系统边界白盒图描述系统内的角色与外界的交互(Rank + Role + 外部 Relation);2. 系统架构图来描述内部的 Role + 内部 Relation]

[注意:不建议一张图同时描述系统架构的 3R 以及与外界的交互,因为图太复杂,画系统边界白盒图的时候,系统内部的 Relation 可以不画]

 

3.1 架构分析

[可选,这部分主要是架构复杂度的分析,基本上从备选架构文档中提炼关键内容过来即可]

[样例:

3.1.1 高可用

对于微博子系统来说,如果消息丢了,导致没有审核,然后触犯了国家法律法规,则是非常严重的事情;对于等级子系统来说,如果用户达到相应等级后,系统没有给他奖品和专属服务,则 VIP 用户会很不满意,导致用户流失从而损失收入,虽然也比较关键,但没有审核子系统丢消息那么严重。

 

综合来看,消息队列需要高可用性,包括消息写入、消息存储、消息读取都需要保证高可用性。

]

[技巧:常见的复杂度都要覆盖到,即使分析后不涉及也要描述,避免评审的时候被人认为遗漏了关键点]

 

3.2 总体架构

[必选,描述总体架构设计]

[样例:此处省略架构图,文字描述样例:

1)采用数据分散集群的架构,集群中的服务器进行分组,每个分组存储一部分消息数据。

2)每个分组包含一台主 MySQL 和一台备 MySQL,分组内主备数据复制,分组间数据不同步。

3)正常情况下,分组内的主服务器对外提供消息写入和消息读取服务,备服务器不对外提供服务;主服务 4)器宕机的情况下,备服务器对外提供消息读取的服务。

5)客户端采取轮询的策略写入和读取消息。

]

[技巧:

1.用系统架构图来描述架构,如果是前端或者客户端,用前端架构图或客户端架构图来描述架构

2.基于架构图中的内容,使用文字描述 Role、Relation 的基本内容,文档目录可以自由调整

]

 

4. 详细设计

[必选,描述核心场景或者流程的实现机制]

4.1 核心功能

[必选,描述核心场景或者流程的实现机制,对应 4R 架构中的 Rule,每个核心场景一个小节]

[样例:

4.1.1 消息发送流程

4.1.2 消息消费流程

]

[技巧:使用系统序列图来描述 Rule,跟项目开发中写设计文档一样的写法]

 

4.2 关键设计

[必选,描述系统的一些关键设计点是如何实现和取舍的]

[样例(如果你有兴趣,可以对比一下 kafka 的文档:Kafka design):

1)消息发送可靠性

业务服务器中嵌入消息队列系统提供的 SDK,SDK 支持轮询发送消息,当某个分组的主服务器无法发送消息时,SDK 挑选下一个分组主服务器重发消息,依次尝试所有主服务器直到发送成功;如果全部主服务器都无法发送,SDK 可以缓存消息,也可以直接丢弃消息,具体策略可以在启动 SDK 的时候通过配置指定。

如果 SDK 缓存了一些消息未发送,此时恰好业务服务器又重启,则所有缓存的消息将永久丢失,这种情况 SDK 不做处理,业务方需要针对某些非常关键的消息自己实现永久存储的功能。

2)消息存储可靠性

消息存储在 MySQL 中,每个分组有一主一备两台 MySQL 服务器,MySQL 服务器之间复制消息以保证消息存储高可用。如果主备间出现复制延迟,恰好此时 MySQL 主服务器宕机导致数据无法恢复,则部分消息会永久丢失,这种情况不做针对性设计,DBA 需要对主备间的复制延迟进行监控,当复制延迟超过 30 秒的时候需要及时告警并进行处理。

3)消息如何存储

每个消息队列对应一个 MySQL 表,消息队列名就是表名,表结构设计为……(此处请自行补充)

]

[技巧:常见的关键设计点包括高性能、高可用、可扩展、安全等]

 

4.3 设计规范

[必选,描述 Role 和 Relation 相关的开发框架、连接协议、数据包格式等]

[样例:

1)消息队列服务器使用 Spring Boot + Netty 开发

2)MySQL 使用 Innodb 存储引擎

3)TCP 包的结构设计……(此处省略,请自行补充)

]

[技巧:如果某个规范涉及内容比较多,请独立章节描述,例如数据包格式定义]

5. 质量设计

[必选,描述和质量相关的设计,包括:可测试性、可维护性、可观测性、成本等设计]

[样例:

5.1 消息队列管理后台

5.2 成本

]

[技巧:如果某个维度不涉及,也请在文档中说明,避免评审的时候被认为考虑不周全]

 

6. 演进规划

[必选,可以是演进规划,也可以是项目计划,需要描述每个里程碑或者版本具体要实现的能力]

[样例:

6.1 消息队列一期

6.2 消息队列二期

]

[技巧:开发阶段快速迭代,小步快跑,但要基本完善后才能正式推出给其他人用]