朱晔的互联网架构实践心得S1E2:屡试不爽的架构三马车

这里所说的三架马车是指微服务消息队列定时任务。以下图所示,这里是一个三驾马车共同驱动的一个立体的互联网项目的架构。无论项目是大是小,这个架构模板的形态一旦定型了以后就不太会变,区别只是咱们有更多的服务有更复杂的调用,更复杂的消息流转,更多的Job,整个架构总体是可扩展的,并且不会变形,这个架构能够在很长的一段时间内无需有大的调整。
数据库


图上画了虚线框的都表明这个模块或项目是不包含太多业务逻辑的,纯粹是一层皮(会调用服务可是不会触碰数据库)。黑色线的箭头表明依赖关系,绿色和红色箭头分别是MQ的发送和订阅消息流的方向。具体在后文都会进一步详细说明。api

微服务

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

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

2. 咱们对服务的划分和指责的定位若是是清晰的,对于新的需求,咱们就能知道须要在哪里改怎么样的代码,没有复制粘贴的存在少了不少坑。数据结构

3. 咱们大多数的业务逻辑已经开发完毕,直接重用便可,咱们的新业务只是现有逻辑的聚合。在PRD评审后,开发获得的结论是只须要组合分别调用ABC三个服务的XYZ方法,而后在C服务中修改一下Z方法增长一个分支逻辑,就能够构建起新的逻辑,这种爽快的感受不可思议。架构

4. 在性能存在明显瓶颈的时候,咱们能够针对性地对某些服务增长更多机器进行扩容,并且由于服务的划分,咱们更清楚系统的瓶颈所在,从10000行代码定位到一行性能存在问题的代码是比较困难的,可是若是这10000行代码已是由10个服务构成的,那么先定位到某个服务存在性能问题而后再针对这个服务进行分析一会儿下降了定位问题的复杂度。并发

5. 若是业务有比较大的变更须要下线,那么咱们能够确定的是底层的公共服务是不会淘汰的,下线对应业务的聚合业务服务停掉流量入口,而后下线相关涉及到的基础服务进行部分接口便可。若是拥有完善的服务治理平台,整个操做甚至无需改动代码。app

这里也要求咱们作到几个方面的原则:负载均衡

1. 服务的粒度划分须要把控好。个人习惯是先按照领域来分不会错,随着项目的进展慢慢进行更细粒度的拆分。好比对于互联网金融P2P业务,一开始能够分为:框架

a. 三方合做服务PartnerInvestService:对接合做的三方理财平台的流量

b. 普通投资服务NormalInvestService:最普通形态的资产的主流程

c. 预定投资产品服务ReserveInvestService:须要预定投资的资产的主流程

d. 周期性计划产品服务AutoInvestService:会按期自动复投的理财产品主流程

e. 投资人交易服务TradeService:专门负责处理投资人的交易行为,好比投资

f. 借款人交易服务LoanService:专门负责处理借款人的交易行为,好比还款

g. 用户服务UserService:处理用户的注册登陆等

h. 资产服务ProjectService:处理资产和标的相关

i. 帐户帐务服务AccountService:处理用户的帐户各个子帐户和帐务记录

j. 营销活动服务ActivityService:处理各类活动、用户的积分体系

k. 会员体系服务VipService:处理用户的会员成长体系

l. 银行存管服务BankService:专门用于对接银行存管系统

m. 电子签章服务DigSignService:专门用于对接三方数字签章系统

n. 消息推送服务MessageService:专门用于对接三方短信通道和推送SDK

2. 服务必定是立体的,不是在一个层次上的,如上图,咱们的服务有三个层次:

a. 聚合业务服务:高层次的串起来整个流程的具备完整业务形态的业务服务。和基础业务服务不一样的是,这里是在完整描述一方面的业务,这个业务每每是由各类基础业务拼装组合起来的。和不一样外部合做方的不一样合做形式,给用户提供的产品的不一样服务形态,都决定了聚合业务服务会有业务流程上的差别化,若是把此类服务下放到基础业务服务中,那么基础业务服务会有各类if-else逻辑(根据产品类型、用户类型进行各类if-else),随着业务的合做不合做,需求变更,基础业务服务会腐化得很厉害,为了不这个状况,咱们把变更的多的聚合业务逻辑放到独立的业务服务中。通常而言,聚合业务服务由于表明了独立的业务流程,它们之间是不会进行相互调用的,可是它们必定会调用大量的各种基础业务服务。在第一点里说的标有蓝色字体的a~d这些服务都是此类服务。这个层次的服务的业务逻辑更可能是在表达业务流程的复杂性和差别性,不会涉及到具体怎么处理帐户信息、帐务信息、用户信息,不会涉及到怎么处理具体的投资人和借款人的交易。好比对于预定这类业务形态,它关注的是先要预定资产,而后再由系统进行自动投资,底层彻底依赖于投资人交易服务来作整个交易的过程。

b. 基础业务服务:某一个领域业务相关的服务。此类服务之间是容许相互调用的,好比投资人交易服务和借款人交易服务免不了须要和用户服务、资产服务、帐户帐务服务进行通信作相关的用户信息查询、标的信息查询、记帐等业务操做。之因此投资人交易服务和借款人交易服务定位为基础业务服务是由于,它们处理的是仍是某一个具体方面的业务,并非全流程,在这个抽象层次上,业务不是那么容易变更的,对于复杂的各类业务形态(好比预定交易、自动复投交易、等额本息交易)会在这些服务之上造成聚合业务服务。在第一点里说的标有绿色字体的e~k这些服务都是此类服务。在这个层次的服务虽然拥有大量的业务逻辑,可是其实已经享受到了很大层度的公共基础服务的重用了,并且和本身业务耦合较弱的额外逻辑每每没有在本服务中堆积,由更多专职的基础业务服务来承担了这部分逻辑。

c. 公共基础服务:负责某一个方面的基础业务(没有什么领域业务逻辑在里面),能够是自治的处理某一个方面的基础业务,也能够和外部通信实现某一个方面的功能,服务之间是不会相互调用的,可是会被聚合业务服务和基础业务服务调用。在第一点里说的标有橙色字体的l~n这些服务都是此类服务。若是之后和外部的合做有变更,由于咱们已经定义了对外的服务契约,能够轻易替换这个服务来更换合做的第三方,系统其他的地方几乎不须要修改。全部的三方对接都建议独立出公共基础服务,若是同一个业务对接多个三方渠道,好比推送对接了极光和个推,甚至公共基础服务还能够由一个抽象聚合的推送服务,下面再路由到具体的极光推送和个推推送服务。

但愿在这里把这个事情说清楚了,怎么来划分服务怎么划分三个层次的服务是一个颇有意思颇有必要的事情,在服务划分以后最好有一个明确的文档来描述每个服务的职责,这样咱们在无需阅读API的状况下能够大概定位到业务所在的服务,整个复杂的系统就变得很直白了。

3. 每个服务对接的底层数据表是独立的没有交叉关联的,也就是数据结构是不直接对外的,须要使用其余服务的数据必定经过访问接口进行。好处也就是面向对象设计中封装的好处:

a. 能够很方便地重构底层的数据结构甚至是数据源,只要接口不变,外部不会感知到。

b. 性能有问题的状况下须要加缓存、分表、拆库、归档是比较方便的事情,毕竟数据源没有外部依赖。

说白了就是个人数据我作主,我想怎么搞外面管不着,在重构或是作一些高层次技术架构(好比异地多活)的时候,没有底层数据被依赖,这过重要了。固然,坏处或是麻烦的地方就是跨服务的调用使得数据操做没法在一个数据库事务中完成,这并非什么大问题,一是由于咱们这种拆分方式并不会让粒度太细,大部分的业务逻辑是在一个业务服务里完成的,二是后面会提到跨服务的调用无论是经过MQ进行的仍是直接调用进行的,都会有补偿来实现最终一致性。

4. 考虑到跨机器跨进程调用服务稳定性方面的显著差别。在方法内部进行方法调用,咱们须要考虑调用出现异常的状况,可是几乎不须要考虑超时的状况,几乎不须要考虑请求丢失的状况,几乎不须要考虑重复调用的状况,对于远程服务调用,这些点都须要去重点考虑,不然系统总体就是基本可用,测试环境不出问题,可是到了线上问题百出的状态。这就要求对于每个服务的提供和调用多问几个上面的问题,细细考虑到由于网络问题方法没有执行屡次执行或部分执行的状况:

a. 咱们在对外提供服务的时候,不但要告知用户服务提供的业务能力,还要告知用户服务的特性,好比是不是幂等的(对于订单类型的操做服务,相同的订单相同的操做强烈建议是幂等的,这样调用方能够放心进行重试或补偿);是否须要外部进行补偿(在这里你可能说为何须要外部进行补偿,服务就不能本身补偿吗,对于内部的子逻辑服务固然能够本身补偿,可是有的时候由于网络缘由请求就没有到服务端,服务端一无所知这个调用固然无从去补偿);是否有频控的限制;是否有权限的限制;降级后的处理方式等等。

b. 反过来,咱们调用其它服务也须要多问几句目标服务的特性,针对性进行设计相应的补偿逻辑、一致性处理逻辑和降级逻辑。咱们必须考虑到有些时候并非服务端的问题,而是请求根本没有到达服务端。

c. 服务自己每每也会有复杂的逻辑,做为客户端的身份调用大量外部的服务,因此服务端和客户端的角色不是固定不变的,当咱们的服务内部有许多客户端来调用服务端的时候,对于每个子逻辑咱们都须要仔细考虑每个环节。否正会出现的状况就是,这个服务是部分逻辑幂等的或是部分逻辑是具有最终一致性的。

若是你说,这么多服务,我在实现的时候很难考虑到这些点,我彻底不去考虑分布式事务、幂等性、补偿(绝不夸张地说,有的时候咱们花了20%的时间实现了业务逻辑,而后花80%的时间在实现这些可靠性方面的外围逻辑),行不行?也不是不能够,那么业务在线上跑的时候必定会是千疮百孔的,若是整个业务的处理对可靠性方面的要求不高或是业务不面向用户不会受到投诉的话,这部分业务的是能够暂时不考虑这些点,可是诸如订单业务这种核心的不容许有不一致性的业务仍是须要全面考虑这些点的。

5. 考虑到跨机器跨进程调用服务数据传输方面的显著差别。对于本地的方法调用,若是参数和返回值传的是对象,那么对于大部分的语言来讲,传的是指针(或指针的拷贝),指针指向的是堆中分配的对象,对象在数据传输上的成本几乎忽略不计,也没有序列化和反序列化的开销。对于跨进程的服务调用,这个成本每每不能忽略不计。若是咱们须要返回不少数据,每每接口的定义须要进行特殊的改造:

a. 经过使用分页的形式,一次返回固定的少许数据,客户端按需拉取更多数据。

b. 能够在参数中传相似于EnumSet的数据结构,让客户端告知服务端我须要什么层次的数据,好比GetUserInfo接口能够提供给客户端BasicInfo、VIPInfo、InvestData、RechargeData、WithdrawData,客户端能够按需从服务端拿BasicInfo|VipInfo。

6. 这里还引伸出方法粒度的问题,好比咱们能够定义GetUserInfo经过传入不用的参数来返回不一样的数据组合,也能够分别定义GetUserBasicInfo、GetUserVIPInfo、GetUserInvestData等等细粒度的接口,接口的粒度定义取决于使用者会怎么来使用数据,更趋向于一次使用单种类型数据仍是复合类型的数据等等。

7. 而后咱们须要考虑接口升级的问题,接口的改动最好是兼容以前的接口,若是接口须要淘汰下线,须要先确保调用方改造到了新接口,确保调用方流量为0观察一段时间后方能从代码下线老接口。一旦服务公开出去,要进行接口定义调整甚至下线每每就没有这么容易了,不是本身说了算了。因此对外API的设计须要慎重点。

8. 最后不得不说,在整个公司都搞起了微服务后,跨部门的一些服务调用在商定API的时候不免会有一些扯皮的现象发生,究竟是我传给你呢仍是你本身来拉,这个数据对我没用为何要在我这里留一下呢?抛开非技术层面的事情不说,这些扯皮也是有一些技术手段来化解的:

a. 明确服务职责,也就明确了服务应该感知到什么不该该感知到什么。

b. 跨部门的服务交互的接口定义能够定的很轻,采用只有一个订单号的接口或MQ通知+数据回拉的策略(谁数据多谁提供数据接口,不用把数据一次性推给下游)。

c. 数据提供方能够构建一套通用数据接口,这样能够知足多个部门的需求,无需作定制化的处理。甚至在接口上能够提供落地和不落地两种性质的透传。

你可能看到这里以为很头晕,为何微服务须要额外考虑这么多东西,实现的复杂度一会儿上升了。我想说的是咱们须要换一个角度来考虑这个事情:

1. 咱们不须要在一开始的时候对全部逻辑都进行严密的考虑,先覆盖核心流程核心逻辑。由于跨服务成为了服务的提供方和使用方,至关于除了我本身,还有不少其它人会来关系个人服务能力,你们会提出各类问题,这对设计一个可靠的方法是有好处的。

2. 即便在不跨服务调用的时候咱们把全部逻辑堆积在一块儿,也不意味着这些逻辑必定是事务性的,实现严密的,跨服务调用每每是必定程度放大了问题产生的可能性。

3. 咱们还有服务框架呢,服务框架每每会在监控跟踪层次和运维系统结合在一块儿提供不少一体化的功能,这将封闭在内部的方法逻辑打散暴露出来,对于有一个完善的监控平台的微服务系统,在排查问题的时候你每每会感叹这是一个远程服务调用就行了。

4. 最大的红利仍是以前说的,当咱们以清晰的业务逻辑造成了一个立体化的服务体系以后,任何需求能够解剖为不多量的代码修改和一些组合的服务调用,并且你知道我这么作是不会有任何问题的,由于底层的服务ABCDEFG都是通过历史考验的,这种爽快感体验过一次就会大呼过瘾。

可是,若是服务粒度划分的不合理,层次划分的不合理,底层数据源有交叉,没考虑到网络调用失败,没考虑到数据量,接口定义不合理,版本升级过于鲁莽,整个系统会出各类各样的扩展问题性能问题和Bug,这是很头痛的,这也就须要咱们有一个完善的服务框架来帮助咱们定位各类不合理,在以后说到中间件的文章中会再具体着重介绍服务治理这块。

消息队列

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

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

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

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

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

这些需求互联网项目中基本都存在,因此消息队列的使用是很是重要的一个架构手段。在使用上有几个注意点:

1. 我更倾向于独立一个专门的listener项目(而不是合并在server中)来专门作消息的监听,而后这个模块其实没有过多的逻辑,只是在收到了具体的消息以后调用对应的service中的API进行消息处理。listener是能够启动多份作一个负载均衡的(取决于具体使用的MQ产品),可是由于这里几乎没有什么压力,不是100%必须。注意,不是全部的service都是须要有一个配到的listener项目的,大多数公共基础服务由于自己很独立不须要感知到外部的其它业务事件,因此每每是没有listener的,基础业务服务也有一些是相似的缘由不须要有listener。

2. 对于重要的MQ消息,应当配以相应的补偿线做为备份,在MQ集群一切正常做为补漏,在MQ集群瘫痪的时候做为后背。我在日千万订单的项目中使用过RabbitMQ,虽然QPS在几百上千,远远低于RabbitMQ压测下来能抗住的数万QPS,可是总体上有那么十万分之一的丢消息几率(我也用过阿里的RocketMQ,可是由于单量较小目前没有观察到有相似的问题),这些丢掉的消息立刻会由补偿线进行处理了。在极端的状况下,RabbitMQ发生了整个集群宕机,A服务发出的消息没法抵达B服务了,这个时候补偿Job开始工做,按期从A服务批量拉取消息提供给B服务,虽然消息处理是一批一批的,可是至少确保了消息能够正常处理。作好这套后备是很是重要的,由于咱们没法确保中间件的可用性在100%。

3. 补偿的实现是不带任何业务逻辑的,咱们再梳理一下补偿这个事情。若是A服务是消息的提供者,B-listener是消息监听器,听到消息后会调用B-server中具体的方法handleXXMessage(XXMessage message)来执行业务逻辑,在MQ中止工做的时候,有一个Job(可配置补偿时间以及每次拉取的量)来按期调用A服务提供的专有方法getXXMessages(LocalDateTime from, LocalDateTime to, int batchSize)来拉取消息,而后仍是(能够并发)调用B-server的那个handleXXMessage来处理消息。这个补偿的Job能够重用的可配置的,无需每次为每个消息都手写一套,惟一须要多作的事情是A服务须要提供一个拉取消息的接口。那你可能会说,我A服务这里还须要维护一套基于数据库的消息队列吗,这个不是本身搞一套基于被动拉的消息队列了吗?其实这里的消息每每只是一个转化工做,A必定在数据库中有落地过去一段时间发生过变更的数据,只要把这些数据转化为Message对象提供出去便可。B-server的handleXXMessage因为是幂等的,因此无所谓消息是否重复处理,这里只是在应急状况下进行无脑的过去一段时间的数据的依次处理。

4. 全部消息的处理端最好对相同的消息处理实现幂等,即便有一些MQ产品支持消息处理且只处理一次,靠本身作好幂等能让事情变得更简单。

5. 有一些场景下有延迟消息或延迟消息队列的需求,诸如RabbitMQ、RocketMQ都有不一样的实现方式。

6. MQ消息通常而言有两种,一种是(最好)只能被一个消费者进行消费而且只消费一次的,另外一种是全部订阅者均可以来处理,不限制人数。不用的MQ中间件对于这两种形式都有不一样的实现,有的时候使用消息类型来作,有的使用不一样的交换机来作,有的是使用group的划分来作(不一样的group能够重复消息相同的消息)。通常来讲都是支持这两种实现的。在使用具体产品的时候务必研究相关的文档,作好实验确保这两种消息是以正确的方式在处理,以避免发生妖怪问题。

7. 须要作好消息监控,最最重要的是监控消息是否有堆积,有的话须要及时加强下游处理能力(加机器,加线程),固然作的更好点能够以热点拓扑图绘制全部消息的流向流速一眼就能够看到目前哪些消息有压力。你可能会想既然消息都在MQ体系中不会丢失,消息有堆积处理慢一点其实也没什么问题。是的,消息能够有适当的堆积,可是不能大量堆积,若是MQ系统出现存储问题,大量堆积的消息有丢失也是比较麻烦的,并且有一些业务系统对于消息的处理是看时间的,过晚到达的消息是会认为业务违例进行忽略的。

8. 图上画了两个MQ集群,一套对内一套对外。缘由是对内的MQ集群咱们在权限上控制能够相对弱点,对外的集群必须明确每个Topic,并且Topic须要由固定的人来维护不能在集群上随意增删Topic形成混乱。对内对外的消息实现硬隔离对于性能也有好处,建议在生产环境把对内对外的MQ集群进行隔离划分。

定时任务

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

1. 如以前所说,跨服务调用,MQ通知不免会有不可达的问题,咱们须要有必定的机制进行补偿。

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

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

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

· 自增ID

· 任务类型:代表具体的任务类型,固然也能够不一样的任务类型直接作多个任务表。

· 外部订单号:和外部业务逻辑的惟一单号关联起来。

· 执行状态:未处理(等待处理),处理中(防止被其它Job抢占),成功(最终成功了),失败(暂时失败,会继续进行重试),人工介入(永远不会再变了,必定须要人工处理,须要报警通知)

· 重试次数:处理过太屡次仍是失败的能够归类为死信,由专门的死信队列任务单独再进行若干次的重试不行的话就报警人工干预

· 处理历史:每一次的处理结果,Json的List保存在这里供参考

· 上次处理时间:最近一次执行时间

· 上次处理结果:最近一次执行结果

· 建立时间:数据库维护

· 最后修改时间:数据库维护

除了这些字段以外,还可能会加一些业务本身的字段,好比订单状态,用户ID等等信息做为冗余。任务表能够进行归档减小数据量,任务表扮演了消息队列的性质,咱们须要有监控能够对数据积压,出入队不平衡处理不过来,死信数据发生等等状况进行报警。若是咱们的流程处理是任务ABCD顺序来处理的话,每个任务由于有本身的检查间隔,这套体系可能会浪费一点时间,没有经过MQ实时串联这么高效,可是咱们要考虑到的是,任务的处理每每是批量数据获取+并行执行的,和MQ基于单条数据的处理是不同的,整体上来讲吞吐上不会有太多的差别,差的只是单条数据的执行时间,考虑到任务表驱动执行的被动稳定性,对于有的业务来讲,这不失为一种选择。

这里再说明一下Job的几个设计原则:

1. Job能够由各类调度框架来驱动,好比ElasticJob、Quartz等等,须要独立项目处理,不能和服务混在一块儿,部署启动多份每每会有问题。固然,本身实现一个任务调度框架也不是很麻烦的事情,在执行的时候来决定Job在哪台机器来跑,让整个集群的资源使用更合理。说白了就是两种形态,一种是Job部署在那里由框架来触发,还有就是只是代码在那里,由框架来起进程。

2. Job项目只是一层皮,最多有一些配置的整合,不该该有实际的业务逻辑,不会触碰数据库,大部分状况就是在调用具体服务的API接口。Job项目就负责配置和频次的控制。

3. 补偿类的Job注意补偿次数,避免整个任务被死信数据卡住的问题。

三马车都说完了,那么,最后咱们来梳理一下这么一套架构下整个项目的模块划分:

· Site:

o console

o app-gateway

· Façade Service:

o partnerinvestservice-api

o partnerinvestservice-server

o partnerinvestservice-listener

o normalinvestservice-api

o normalinvestservice-server

o normalinvestservice-listener

o reserveinvestservice-api

o reserveinvestservice-server

o reserveinvestservice-listener

o autoinvestservice-api

o autoinvestservice-server

o autoinvestservice-listener

· Business Service:

o tradeservice-api

o tradeservice-server

o tradeservice-listener

o loanservice-api

o loanservice-server

o loanservice-listener

o userservice-api

o userservice-server

o projectservice-api

o projectservice-server

o accountservice-api

o accountservice-server

o accountservice-listener

o activityservice-api

o activityservice-server

o activityservice-listener

o vipservice-api

o vipservice-server

o vipservice-listener

· Foundation Service:

o bankservice-api

o bankservice-server

o digsignservice-api

o digsignservice-server

o messageservice-api

o messageservice-server

· Job:

o scheduler-job

o task-job

o compensation-job

这每个模块均可以打包成独立的包,全部的项目不必定都要在一个项目空间内,能够拆分为20个项目,服务的api+server+listener放在一个项目内,这样其实有利于CICD缺点就是修改代码的时候须要打开N个项目。

以前开篇的时候说过,使用这套简单的架构既可以有很强的扩展余地,复杂程度上或者说工做量上不会比All-In-One的架构多多少,看到这里你可能以为并不一样意这个观点。其实这个仍是要看团队的积累的,若是团队你们熟悉这套架构体系,玩转微服务多年的话,那么其实不少问题会在编码的过程当中直接考虑进去,不少时候设计也能够认为是一个熟能生巧的活,作了多了天然知道什么东西应该放在哪里,怎么去分怎么去合,因此并不会有太多的额外时间成本。这三驾马车构成的这么一套简单实用的架构方案我认为能够适用于大多数的互联网项目,只是有些互联网项目会更偏重其中的某一方面弱化另外一方面,但愿本文对你有用。

相关文章
相关标签/搜索