单体架构>微服务?
单体架构>微服务?
微服务,这个从互联网兴起开始也跟着大伙大热的概念,在最近几年里,无论是平时架构设计或是面试中都会提及;
你们有多少个服务?用的是什么通讯....
虽然在平时接触的项目中大多是围绕各种子服务搭建起来的体系,但是在最近经常出现一个非常非常诟病的问题:
- 服务在进行私有化部署时(应用未在我方侧,而是在客户侧部署), 由于各服务的执行顺序、数据库版本、配置信息....等等的不一致导致即使采用指令编排也会出现不同程度的错误
而在解决这个问题的过程中,思路停留在了一个问题上:单体架构与微服务,两者可否相对兼容,即使用单体架构的思路引入“微服务”
问题案例
有一个应用A,由消息中心的推送服务、第三方服务的获取天气、以及用户中心构成;
在平时的云端体系下,由于是微服务架构,当我们部分服务进行版本升级、迭代时,只需要控制路由及灰度/蓝绿即可。
就像我们平时的应用中不停机更新时的场景,用户会面临两个选择:
- 旧版APP不可用,更新APP
- 旧版APP可用,部分功能不可用
这也是拆分服务的分布式体系下带给用户的体验升级。
但是这时候出现了一个问题,有一个大老板说我们的服务器不安全,他希望通过“购买”的方式让我们将应用部署在他们的服务器中,即私有化部署。
起初我们很轻松,依葫芦画瓢的指令编排依次启动一个个服务;但是随着现场部署异常次数的增多我们发现了私有化部署多服务时绕不开的现实问题:
- 现场人员不懂后台部署异常,需要远程指挥
- 部署环境落后(
Windows Server
) - 服务升级麻烦,由于资源不可控、数据库配置、权限等因素影响
- 服务与服务之间的调度中心版本问题,比如nacos服务端版本
- ...
因此在如今传统的分布式微服务的架构,在这种部署环境下非常难低成本执行,因此需要一个点子;
点子:starter包
Javaer人一定都有这种体验,在使用SpringBoot的流程中,我们如果想要接入某个框架,再引入对应的-starter
依赖后就会完成对该框架的自动配置和注入:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
这种自动装配的思路我习惯称呼为 拆箱即用
那么回到应用与服务之间的关系,如果服务也可以想SpringBoot中的Starter包一样,通过引入依赖的方式挂载到应用中;而应用使用服务中的方法,有了拆箱即用的体验。
boot-starter: 各服务的启动器,即源应用中的application
,拥有注解开启、包扫描之类的配置
xxx-core: 各服务的核心代码,即源应用中的源代码
api: 定义应用A通过哪种方式调用 core中的源代码方法
引入流程:
- 消息中心将包扫描、应用注解等包装成一个boot-starter,并且分割源业务核心代码core
- boot-starter依赖核心代码core,并且提供一个api包,方法为core层服务的接口
- 应用A引入boot-starter依赖
- 应用A调用api包中的方法
- api包,通过应用A的yaml配置文件判断本方法是使用本地方法(core包),还是使用通讯协议(http/dubbo/...),并且读取yaml中的配置组装请求方式
- 打包应用A,只有一个jar包,部署
看起来觉得乱的会觉得乱,不觉得乱的会升起一起疑惑:这和直接将子服务中的方法直接写在一个应用中有什么区别?有必要弄得如此复杂吗
对于平常部署的应用来说,这样的设计是完全违背了解耦的理念,强行将各个服务的源代码引入,除了代码、服务、逻辑等等耦合的问题。
因此觉得这样乱来的人我觉得你想的没错,因此我罗列出了如此乱来的优势与劣势:
劣势
劣势 | 原因 | 严重等级 |
---|---|---|
包名+类名不可一样 | SpringBoot中的IOC管理标识 | 非常严重(完全无法避免) |
线程池不好管理 | 由于所有应用(应用A+子服务)一个jar包执行,启动时线程池分配会出现不均匀问题 | 中等(通过配置控制) |
yaml配置稀碎 | 服务A使用a: 的值,服务B同样使用a: 的值,但两者的yaml配置冲突 | 严重(很难避免) |
开发成本高 | 从服务拆包成starter-core-api,到引入,都需要进行重构 | 高 |
低可用 | 所有服务都绑定在一个应用,挂了就等于死亡 | 还行(多应用A节点) |
不稳定 | 所有服务都绑定在一个应用,其中的一个服务代码异常阻塞,会导致整体奔溃 | 非常严重(单体架构的缺点) |
... | ... | ... |
优势
优势 | 原因 | 好用等级 |
---|---|---|
部署简单 | 一个jar包+一个配置文件解决部署问题 | 非常好用 |
异常问题排查方便 | 一个后台日志可以看到所有服务调用情况 | 非常好用 |
减少方法调用成本 | 微服务体系下应用A需要考虑很多因素,单体下由服务方的api层考虑 | 好用 |
版本管理方便 | 服务升级不需要一个一个版本变更,只需要修改引入的bootstarter依赖即可 | 好用 |
配置灵活 | 所有应用和服务共享一个yaml | 好 |
... | ... | ... |
总结
为什么想到这种一个点子,因为发现在一些有年代的旧项目中真的存在这样设计的依赖关系。
感叹之余,也疑惑他们真的不担心单体架构的低可用等等的危害吗?
不过仔细一想,在很多私有化部署的场景中,客户也根本不需要去考虑可用性、稳定性,只要你能给我一个.exe程序,我能非常简单的跑起来就是最棒的;
所以这一次的思路,打开了我对应用部署的新世界大门,简单的概括就是:
- 我们的:要上微服务
- 别人用我们的:给他越简单越好用的单体架构引入服务,即上