Fork me on GitHub

AIQ - 架构 | 软件服务架构的一些感悟

早想着要写一篇博客,但由于各种原因(其实因为懒),迟迟没有动笔。今日下决心,写写关于软件服务架构的一点感悟。

三层架构

从读大学开始,老师就讲三层架构。后来的项目实施基本上也都是三层架构。对于小型项目,业务逻辑相对简单的项目,三层架构是快速迭代的利器。随着项目的迭代,功能越来越多,业务逻辑越来越复杂,业务开发团队越来越庞大,单体的三层架构就逐渐暴露出它的不足。因为这样的项目是一个高内聚、高耦合的项目,一个类、一个方法可能被多处引用,给维护带来了极大的不方便,要修改一个方法、修改一个字段,可能会影响到所有引用它的方法。如果项目中还存在包引用、dll引用,可能还会导致包名冲突、命名空间冲突。这种情况下,我们会去想,如何降低业务复杂度?答案是拆分服务,微服务化。开发团队的壮大对于高效的管理也是一个问题,微服务化后,原先业务团队被拆分成多个微服务团队,也降低了管理的难度。

微服务架构

图1

图2

对于微服务如何划分,粒度多粗多细,每个团队有每个团队的划分法。从我个人的经历来看,无外乎一种细粒度划分,一种粗粒度划分。

图1,展示了细粒度的服务划分通常的一个结构。对于一个复杂的业务,如果服务划分过细(这样的服务通常绝对禁止跨库访问),业务逻辑层必然要对服务进行组装,不管是RPC的调用方式,还是Rest的方式,此时的业务逻辑层仍然是一个高内聚、高耦合的模块。对于一个需要快速迭代的产品,这样的架构快速不起来。比如一个下单服务,业务逻辑层的负责团队需要等待商品服务相应的接口、订单服务相应的接口、库存服务相应的接口等下单涉及到的接口准备就绪,才能开始编写服务。

图2,展示课粗粒度的服务划分通常的结构。这时,一个微服务接口是一个粗粒度的接口,微服务与微服务之间不允许相互调用,而允许跨库访问,降低了服务之间的依赖,这样的的微服务是一个高内聚、低耦合的模块。还是以下单服务来举例,此时负责订单服务的团队,编写服务的时候,不必等待商品团队、库存团队、用户团队(收货地址)等其他团队,他们自己可以快速着手开发下单服务。负责库存服务的团队,只写他们关心的服务,比如商品的采购、入库。而订单团队需要的库存扣减操作接口,订单团队自给自足。(这里引申一个问题,从DDD的思想来看,一个Domain的边界,到底在哪里?拿库存来说,一切有关库存的操作都写到这个Domain叫做DDD?如果只有订单模块会扣减库存,退单后会加回库存,这样的接口还写在库存服务模块?这类接口属于订单领域还是库存领域?)

微服务,不仅能够降低业务复杂度、开发团队管理难度,而且由于微服务的特性,使得部署软件的资源能更合理高效的应用,降低资源成本。

高并发

图3

软件并发量逐渐提高,不管是三层架构、还是微服务,优化的途径都差不多,读写分离-》加缓存-》分库分表。上方所示图2到图3,展示了利用一些数据访问中间件(Sharding-JDBC、Macat、Atlas&&)实现分库分表的架构。

重构

对于一个潜在的可能存在高并发场景的项目,如何能在遇到高并发的时候,从容地重构一个项目?我有一些浅见,供大家讨论:

(临时搭建的项目,凑合看吧) 

如上图所示,项目划分了两个Package,一个Product,一个Membership,请注意,ProductController里面引用了Membership这个Package里的UserService,换句话说,就是ProductController依赖了Membership这个Package里的UserService。假如我们约定,不允许跨Package依赖,那么Product这个Package里有需要用到User相关的服务的时候,自己写到Product这个Package里。那么当我要进行服务拆分的时候,只需要把Product这个Package单独打包成一个jar,即可拆分完成。这样约定,方便从三层架构重构到上图2的架构,对将来可能的分库分表没有任何影响。

如果业务进一步复杂,采用图2所示架构也会遇到问题。比如库存数据,如果除了订单服务之外还有其他的服务都去修改库存数据的话,在没有统一日志或者这样的服务数量比较多的情况下,想要知道这个库存数据是怎么来的,会非常困难。这个时候只能重构成图1的架构。采用图1的架构,需要业务专家来定义接口,使其尽可能地适应多的使用场景。

出处:http://www.cnblogs.com/DKSL/p/9225178.html


本文地址:https://www.6aiq.com/article/1530979644489
本文版权归作者和AIQ共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出