单体服务和微服务的相互转换

单体架构和微服务架构

架构的发展过程是单体->soa->微服务。随着业务的复杂程度加剧,单体架构服务间耦合严重的情况愈加突出。
微服务化主要是解决业务间耦合的问题,拆分为粒度更小的服务可以控制业务复杂度和故障的爆炸半径。

维度 传统单体架构 分布式微服务化架构
新功能开发 需要时间 容易开发和实现
部署 不经常而且容易部署 经常发布,部署复杂
隔离性 故障影响范围大 故障影响范围小
架构设计 初期技术选型难度大 设计逻辑难度大
系统性能 相对时间快,吞吐量小 相对时间慢,吞吐量大
系统运维 运维难度简单 运维难度复杂
新人上手 学习曲线大(应用逻辑) 学习曲线大(架构逻辑)
技术 技术单一而且封闭 技术多样而且容易开发
测试和差错 简单 复杂(每个服务都要进行单独测试,还需要集群测试)
系统扩展性 扩展性差 扩展性好
系统管理 重点在于开发成本 重点在于服务治理和调度

逆潮流?

目前我们处于单体到微服务的运动过程中,逐渐发现拆分后细粒度的微服务比较多,从而带来管理和维护成本。那如何能进行优化呢?
对于成熟的业务来说,维护开销比开发开销占比更高,是否可以将若干微服务打包为一个新的微服务呢?
逻辑独立但是部署在一起,一起对外提供完整的功能。

目标

可根据需求把所有微服务随时合并成少数几个单体服务,在保留微服务优势的前提下,消除其劣势。也可以随时在其中某个服务变得更复杂更大的时候从单体服务中拆分出来

方案

1. 所有的微服务都需要符合既定的目录规范

├── service # 服务入口,用户用例集合(实现pb定义的方法)
│ └── xxx.go 具体的入口文件

├── logic # 逻辑层,所有业务逻辑都在此层, 根据业务细分目录
│ ├── biz1 # 对应领域建模中的应用服务1
│ └── 实体1.go # 具体的业务逻辑, 实体结构体和port定义其中
│ └── 实体2.go # 具体的业务逻辑, 实体结构体和port定义其中
│ └── service.go # 非实体逻辑(类似ddd中的domain service, 有些逻辑不属于任何实体,可以找个地方归属它)
│ ├── biz2 # 对应领域建模中的应用服务2,一般没有
│ └── 实体1.go 同上

├── infrastructure # 基础设施层
│ ├── biz1 # 对应logic中的biz1
│ ├── 实体1.go # 实体1的adapter在其中实现(默认包含mysql等基础设施)
│ └── 实体2.go # 实体2的adapter在其中实现(默认包含mysql等基础设施)
│ ├── biz2 # 同上
│ └── 实体X.go 同上
│ ├── commonbiz1 # 公共服务,比如biz1和biz2都需要rpc请求XXX服务,为了避免biz1和biz2中都写XXX请求服务的代码,将其找个目录收敛起来
│ └── commonbiz1.go 同上

├── common # 通用常量,工具函数(该目录非常薄,大部分服务用不到)
│ └── constant # 多层通用常量,如果一个常量只在logic层使用就不要定义在这里
│ └──biz1
│ └── biz1.go
│ ├── util # 工具函数目录(工程独有的,否则可以考虑将工具代码合到另外的git项目)
│ └──cast # 具体的工具函数,比如转换
│ └── cast.go
├── test # 接口测试目录

2. main.go通过脚手架生成,不允许修改。里面是依赖注入和服务注册

3. 拆分合并脚本来合并不同微服务的目录,集成main.go和yaml配置文件,yaml文件中配置可以去重