浅谈单体向微服务架构的演进

一、什么是架构

首先,要理解架构,我们需要先理解几个有关系又相似的概念,包括:系统和子系统、模块和组件、框架和架构。
我们以一个学生管理系统为例。

1. 系统和子系统

  • 系统:
    • 系统泛指由一群有关联的个体组成,根据某种规则运作,能完成个别元件不能单独完成的工作的群体。它的意思是“总体”“整体”或“联盟”。
  • 子系统
    • 子系统也是由一群有关联的个体所组成的系统,多半会是更大系统中的一部分。

一个可用的、完整的学生管理系统便是一个系统,系统一般是具有完整性的。
而学生管理系统又可以包括用户子系统,学生信息管理子系统,成绩管理子系统等等,我们可以明显看出其中差距,一个系统一般会有一个或者多个子系统构成。多个子系统相互协作构成较大的系统,划分子系统的原则往往是按照业务场景来,并不是绝对的,所以子系统也可以再次细分为多个子系统。系统也有可能是其他更大系统的子系统。

2. 模块和组件

  • 模块:
    • 是一套一致而互相有紧密关连的软件组织。它分别包含了程序和数据结构两部分。现代软件开发往往利用模块作为合成的单位。模块的接口表达了由该模块提供的功能和调用它时所需的元素。模块是可能分开被编写的单位。这使它们可再用和允许人员同时协作、编写及研究不同的模块
  • 组件
    • 定义为自包含的、可编程的、可重用的、与语言无关的软件单元,软件组件可以很容易被用于组装应用程序中

模块和组件往往容易被滥用,它们都是系统的组成部分,只是拆分的角度不同, 从逻辑的角度去拆分系统,得到的单元就是模块,例如学生管理系统可分为成绩模块,学生信息模块,而从物理的角度去拆分,又可以拆分为 web服务、MySQL、nosql、NGINX 等。
划分模块的目的是对职责进行分离,而划分组件的目的却是为了复用,因此组件一般是具有独立性的,可以替换的,跟一个完整的零件似的,例如我们使用 Apache、Tomcat、NGINX 等

3. 框架和架构

  • 框架
    • 通常指的是为了实现某个业界标准或完成特定基本任务的软件组件规范,也指为了实现某个软件组件规范时,提供规范所要求之基础功能的软件产品。
  • 架构
    • 指软件系统的“基础结构”,创造这些基础结构的准则,以及对这些结构的描述。

应该没有人不熟悉框架了,框架其实主要是提供了规范性和基本的功能代码包,例如 go 的 gin、beego、go-zero 等框架,主要是定义了基本的目录结构以及提供了一些基本的代码处理和工具包,可以帮助开发快速去使用。

架构的定义相比之下比较模糊,不同的角度或者维度,可以将系统划分为不同的结构(架构),例如从物理部署的角度来说,它的架构可能是这样的:

在这里插入图片描述

我们可以说这是一种纯技术选择的架构,这也是大多数人熟悉的架构定义,使用了哪些技术栈(语言、工具、框架),彼此之间的关联关系是什么。

在这里插入图片描述

当然,代码结构也是一种架构,例如我们常说的 MVC 架构,这可是前几年校招必问的题目,这是从开发规范的角度来定义的。

而从业务角度来看,这样的模块划分关系图也是架构

在这里插入图片描述

架构的终极定义:
参考李老师的说法,架构的定义应该是软件系统的顶层结构,首先“系统是一群关联个体组成”,这些“个体”可以是“子系统”“模块”“组件”等;架构需要明确系统包含哪些“个体”,其次,系统中的个体需要“根据某种规则”运作,架构需要明确个体运作和协作的规则。

二、单体架构的外貌特征

怎么样才算是单体架构,像博主身边有些同学就觉得,不是微服务架构就是单体架构,其实这样理解是不大正确的,单体架构风格就是简单地意味着所有应用代码被部署并运行在单一节点的单一进程中,第一个词“部署”的意思是运行时代码的组织方式,无论代码在物理上是存储在一个还是多个代码库之中。而第二个词“节点”的意思是即便是在横向扩展的情况下我们将应用部署到了多个服务器,它依然是一个单体。

以常见的 lmnp 架构为例,就是一个单体架构,所有的应用代码都是跑在了一个进程里面。内部相关的函数调用均在进程内处理,而非进程间通信。例如我司的大单体架构,代码量也已达到了百万级别(git clone下来几个G大小啊),常见的单体架构往往是这样的。

在这里插入图片描述

当然这个图忽略了负载均衡、cdn 相关的内容。我们可以清晰的看到,基本上,一个系统会包含很多的模块,并且不同的模块共用相同的资源(MySQL、Redis…),整体依赖性是十分的强,并且如果某个模块代码出现问题导致MySQL挂了,也就意味着整个系统就挂了。在上一篇《浅谈微服务》中,我说明了单体架构和微服务架构的优劣势。在这里我不在赘述。
重点记住这句话:无能力不微服务化、无能力不微服务化、无能力不微服务化

重点的事情讲三遍
微服务所带来的的技术复杂性、人力成本是一般中小公司无法承受的。

三、微服务架构

3.1 为什么要考虑微服务?

在这里插入图片描述

我们可以看看上面这张图。随着时间的推移,单体应用的复杂度只会呈线性去增长,而微服务架构确实复杂度呈线性较少。但是要搭起微服务这一套是十分复杂的。写代码只是其中的一小部分,想搭起适合公司的微服务体系,往往没有你想象中那么简单。当公司慢慢趋于稳定了,有较多的盈利了,这个时候为了后期的发展,就可以(必须)得考虑微服务架构了,找几个牛逼的技术专家+运维+领域专家+一堆开发,用DDD 去拆分领域,部分人继续维护老代码,部分人开始进行重构升级工作(大多数公司都是这么弄的),毕竟不能一刀切,重构的工作往往耗时较久,日常的迭代需求还是要开发的。这也是为什么搞微服务重构的公司会大量的招人,就是为了给重构让出必要的资源,为了让重构变的更有业务价值,往往会揪出当前业务的痛点,进行梳理,这样对公司来说,重构也是对业务有所帮助的。

所以,之所以要考虑微服务,主要是因为领导者预见了未来,并在资源充足的情况下所作出的决策。
用人话来说,就是有钱了为了提升工作效率,就去买了 Mac(当然也可能买其他性能较好的电脑,即选择其他的架构,不过Mac是开发公认较好的工具了),如果没钱还是继续用旧电脑刚吧。

3.2 微服务的核心是什么?

微服务其中一个重要的核心就是去中心化,我们可以看看百度百科对其定义:
去中心化,不是不要中心,而是由节点来自由选择中心、自由决定中心。简单地说,中心化的意思,是中心决定节点。节点必须依赖中心,节点离开了中心就无法生存。在去中心化系统中,任何人都是一个节点,任何人也都可以成为一个中心。任何中心都不是永久的,而是阶段性的,任何中心对节点都不具有强制性。

中心化容易引发的一个问题就是单点奔溃。比如说我们的网站只有一个网关,如果这个网关挂了,没有其他的备用网关,那么整个系统也就凉了。在这里又不得聊起分布式,分布式一定是去中心化吗?
其实不然,去中心化一定是分布式的实现,但是分布式却不一定是去中心化。我们举个例子,MySQL的主从集群是去中心化吗?
一般来讲,存在主/从关系的系统是中心化系统。在这类系统中,主节点负责系统的整体运行管理,从节点则负责运行主节点安排的任务。在这种系统中,一般主节点出故障容易引起系统的崩溃,而从节点出问题则一般不会引起系统的崩溃。

在这里插入图片描述

这就意味着,由原本的中央集权控制,变成了人民自己当家做主(依靠的规则就是法律)

在这里插入图片描述

四、从单体迈向微服务架构

微服务架构在不同的公司有着不同的实现方式,不同的框架和语言,都有着自己的特色。例如 Java 的spring cloud, go 的 go-zero 框架,博主主要涉及的是 go + grpc 的模式。我简单画了一下微服务化的架构图。

在这里插入图片描述

4.1 如何拆分服务?

我们通过图中可以看到,服务是位于最底层的。不同的服务一般拥有自己的资源库,例如自己的MySQL、Redis。这样,只要保证向前兼容,就可以随便的升级改造服务接口,不需要通知调用方做调整,拆分服务是微服务设计的最重要的一环,一般来说,没有绝对的拆分姿势,不过有一些公认的拆分规则:

  • 服务要可以单独部署,不依赖其他的服务
  • 服务尽可能的小,但是不能拆分的太小,拆分的太小容易引发过度设计的问题,拆分的太大就会过于粗糙
  • 使用DDD设计,尽量按业务模块拆分

说起 DDD 就比较烦了,太抽象了,等博主学完一波再来搞它。

4.2 微服务的请求链路

以上图为例(不同公司的设计不同,这里只是举了一个例子)
实际上,图示请求链路是: 外网-> API GATEAWAY -> frontend -> bff -> microservice

这里要重点说明的是 API GATEAWAY 和 BFF 。

其实这张图是相对比较成熟的架构了(听说小破站也是这么搞的)。很多公司搞微服务既没有 API GATEAWAY 和 BFF, 更没有按服务拆分数据库。只是单纯将原本的后端代码拆分重构成微服务,对整体的架构并没有太大的变化,可以说做的并不彻底。
不过这也是受公司组织以及规模来决定的。有能力有资源当然要做彻底一点。

像以前,可能会存在这种直连的模式。

在这里插入图片描述

这种方式,虽然是按照 SOA 服务化架构去设计,但是对外暴露了很多微服务,也因为没有统一的出口容易遇到很多的问题:

  • 强耦合
  • 需要多次请求,客户端对数据进行聚合
  • 面向端的适配,会让微服务的涉及耦合很多业务
  • 无法进行统一的逻辑收敛,每个服务都要实现一套验证
  • 协议不统一,需要客户端进行兼容

界内有这么一个说法,当某一层不能实现一些事情的时候,我们就在上面再加一层。
通过 API GATEAWAY 我们可以不再直接对外暴露服务,并且 API GATEAWAY 还可以帮我们实现一些通用的鉴权,限流等操作。这样就不需要每个服务自己去实现相关的逻辑。

那 bff 到底是干嘛的呢?

BFF 可以认为是一种适配服务,将后端的微服务进行
适配(主要包括聚合裁剪和格式适配等逻辑),向其他客户端
设备暴露友好和统一的 API,有了BFF,后端在设计微服务的时候,就可以尽量的避免业务逻辑侵入。业务逻辑让 bff 那一层去实现。

像我司,bff 是通过 nodejs 实现的,我们后端在实现完微服务后,前端会写 bff 通过 rpc 调用来调用我们的后端服务。然后前台再去调用 bff。

同时为了保证系统的高可用,往往这些玩意也都不会进行单节点部署。因此,微服务架构和分布式架构基本是无法分隔的。

猜你喜欢

转载自blog.csdn.net/qq_38378384/article/details/115429354
今日推荐