云时代架构阅读笔记十二——互联网架构:屡试不爽的架构三马车

互联网架构三马车是指:微服务、消息队列和定时任务

微服务

微服务并不是一个很新的概念,在10年前的时候我就开始实践这个架构风格,在四个公司的项目中全面实现了微服务,越来越坚信这是非常适合互联网项目的一个架构风格。不是说我们的服务一定要跨物理机器进行远程调用,而是我们通过进行有意的设计让我们的业务在一开始的时候就按照领域进行分割,这能让我们对业务有更充分的理解,能让我们在之后的迭代中轻易在不同的业务模块上进行耕耘,能让我们的项目开发越来越轻松,轻松来源于几个方面:

1. 如果我们能进行微服务化,那么我们一定事先经过比较完善的产品需求讨论和领域划分,每一个服务精心设计自己领域内的表结构,这是一个很重要的设计过程,也决定了整个技术架构和产品架构是匹配的,对于All-In-One的架构往往会省略这一过程,需求到哪里代码写到哪里。

2. 我们对服务的划分和职责的定位如果是清晰的,对于新的需求,我们就能知道需要在哪里改怎么样的代码,没有复制粘贴的存在少了很多坑。

3. 我们大多数的业务逻辑已经开发完毕,直接重用即可,我们的新业务只是现有逻辑的聚合。在PRD评审后,开发得到的结论是只需要组合分别调用ABC三个服务的XYZ方法,然后在C服务中修改一下Z方法增加一个分支逻辑,就可以构建起新的逻辑,这种爽快的感觉难以想象。

4. 在性能存在明显瓶颈的时候,我们可以针对性地对某些服务增加更多机器进行扩容,而且因为服务的划分,我们更清楚系统的瓶颈所在,从10000行代码定位到一行性能存在问题的代码是比较困难的,但是如果这10000行代码已经是由10个服务构成的,那么先定位到某个服务存在性能问题然后再针对这个服务进行分析一下子降低了定位问题的复杂度。

5. 如果业务有比较大的变动需要下线,那么我们可以肯定的是底层的公共服务是不会淘汰的,下线对应业务的聚合业务服务停掉流量入口,然后下线相关涉及到的基础服务进行部分接口即可。如果拥有完善的服务治理平台,整个操作甚至无需改动代码。

消息队列

消息队列MQ的使用有下面几个好处,或者说我们往往处于这些目的来考虑引入MQ:

1. 异步处理:类似于订单这样的流程一般可以定义出一个核心流程,这个流程用于处理核心订单的状态机,需要尽快同步落库完成,然后围绕订单会衍生出一系列和用户相关的库存相关的后续的业务处理,这些处理完全不需要卡在用户点击提交订单的那刹那进行处理。下单只是一个确认合法受理订单的过程,后续的很多事情都可以慢慢在几十个模块中进行流转,这个流转过程哪怕是消耗5分钟,用户也无需感受到。

2. 流量洪峰:互联网项目的一个特点是有的时候会做一些toC的促销,免不了有一些流量洪峰,如果我们引入了消息队列在模块之间作为缓冲,那么backend的服务可以以自己既有的舒服的频次来被动消耗数据,不会被强压的流量击垮。当然,做好监控是必不可少的,下面再细说一下监控。

3. 模块解耦:随着项目复杂度的上升,我们会有各种来源于项目内部和外部的事件(用户注册登陆、投资、提现事件等),这些重要事件可能不断有各种各样的模块(营销模块、活动模块)需要关心,核心业务系统去调用这些外部体系的模块,让整个系统在内部纠缠在一起显然是不合适的,这个时候通过MQ进行解耦,让各种各样的事件在系统中进行松耦合流转,模块之间各司其职也相互没有感知,这是比较适合的做法。

4. 消息群发:有一些消息是会有多个接收者的,接收者的数量还是动态的(类似指责链的性质也是可能的),在这个时候如果上下游进行一对多的耦合就会更麻烦,对于这种情况就更适用使用MQ进行解耦了。上游只管发消息说现在发生了什么事情,下游不管有多少人关心这个消息,上游都是没有感知的。

定时任务

定时任务的需求有那么几类:

1. 如之前所说,跨服务调用,MQ通知难免会有不可达的问题,我们需要有一定的机制进行补偿。

2. 有一些业务是基于任务表进行驱动的,有关任务表的设计下面会详细说明。

3. 有一些业务是定时定期来进行处理的,根本不需要实时进行处理(比如通知用户红包即将过期,和银行进行日终对账,给用户出账单等)。和2的区别在于,这里的任务的执行时间和频次是五花八门的,2的话一般而言是固定频次的。

详细说明一下任务驱动是怎么一回事。其实在数据库中做一些任务表,以这些表驱动作为整个数据处理的核心体系,这套被动的运作方式是最最可靠的,比MQ驱动或服务驱动两种形态可靠多,天生必然是可负载均衡的+幂等处理+补偿到底的,任务表可以设计下面的字段:

  • 自增ID
  • 任务类型:表明具体的任务类型,当然也可以不同的任务类型直接做多个任务表。
  • 外部订单号:和外部业务逻辑的唯一单号关联起来。
  • 执行状态:未处理(等待处理),处理中(防止被其它Job抢占),成功(最终成功了),失败(暂时失败,会继续进行重试),人工介入(永远不会再变了,一定需要人工处理,需要报警通知)
  • 重试次数:处理过太多次还是失败的可以归类为死信,由专门的死信队列任务单独再进行若干次的重试不行的话就报警人工干预
  • 处理历史:每一次的处理结果,Json的List保存在这里供参考
  • 上次处理时间:最近一次执行时间
  • 上次处理结果:最近一次执行结果
  • 创建时间:数据库维护
  • 最后修改时间:数据库维护

除了这些字段之外,还可能会加一些业务自己的字段,比如订单状态,用户ID等等信息作为冗余。任务表可以进行归档减少数据量,任务表扮演了消息队列的性质,我们需要有监控可以对数据积压,出入队不平衡处理不过来,死信数据发生等等情况进行报警。如果我们的流程处理是任务ABCD顺序来处理的话,每一个任务因为有自己的检查间隔,这套体系可能会浪费一点时间,没有通过MQ实时串联这么高效,但是我们要考虑到的是,任务的处理往往是批量数据获取+并行执行的,和MQ基于单条数据的处理是不一样的,总体上来说吞吐上不会有太多的差异,差的只是单条数据的执行时间,考虑到任务表驱动执行的被动稳定性,对于有的业务来说,这不失为一种选择。

 

posted @ 2019-05-24 00:31  DaisyYuan  阅读(197)  评论(0编辑  收藏  举报