茶艺师学微服务(准备篇)
前言
我这给茶馆写 go 语言工具的茶艺师,在看资料时,经常看到的就是“微服务架构”,说是一种软件的架构风格。
“那么我写的工具,也能不能用这个架构?”
带着这问题,我忍不住一探即究竟。
基本内容
所谓的微服务架构?
微服务架构是一种软件架构风格,将应用程序拆分为一组小型、自治的服务。
每个服务都专注于一个特定的业务领域,并通过轻量级通信机制进行交互。
每个服务都可以独立部署、扩展和维护,且可以使用不同的技术栈来实现。
换句话说,就是将一个应用程序按照需要“化繁为简”,拆成一个个独立的小块。
但不能光顾着拆,还要将这些小块换个“更巧妙”的方法联系在一起,使得整个“团体”能事半功倍地发挥原先程序的功能。
除了微服务,其他的架构:
-
单体架构(Monolithic Architecture)
将整个应用程序作为一个单一的、可部署的单元构建。所有的功能模块都在同一个代码库和部署单元中。这种架构通常适用于小型应用或刚开始的项目。 -
分层架构(Layered Architecture)
将应用程序划分为不同的层,每个层负责特定的功能。常见的层包括表示层(Presentation Layer)、业务逻辑层(Business Logic Layer)和数据访问层(Data Access Layer)。这种架构有助于实现模块化和可维护性。 -
客户端-服务器架构(Client-Server Architecture)
将应用程序划分为客户端和服务器两个独立的部分。客户端负责用户界面和用户交互,而服务器负责处理业务逻辑和数据存储。这种架构有助于实现分布式计算和资源共享。 -
事件驱动架构(Event-Driven Architecture)
基于事件和消息的通信模型,组织应用程序的各个组件。组件之间通过事件进行通信和协作,以实现松耦合和可扩展性。 -
领域驱动设计(Domain-Driven Design,DDD)
将软件设计的重点放在领域模型和业务逻辑上。通过将业务需求和领域模型紧密结合,DDD旨在提高软件的可理解性、可维护性和可扩展性。 -
服务导向架构(Service-Oriented Architecture,SOA) 将应用程序划分为一组松散耦合的服务。每个服务都是独立的、可重用的功能单元,通过网络进行通信和协作。SOA有助于实现系统的模块化和可扩展性。
为什么要用微服务架构?
通过分而治之,降低复杂度,使得更加容易地开发、测试、部署和扩容。
换句话说,就是应用程序已经发展到很复杂的地步,得想个办法降低其复杂度,不然开发人员或者维护人员很难对其下手,更别说其他的了。 再来举个例子。
有一个系统 sys ,拆分后的两个子系统分别为 sys1 和 sys2 ,通过下图能看到,sys 的复杂度是远远大于 sys1 与 sys2 的复杂度之和。
也很容易看到,在原系统中,研发人员需要懂整个系统的方方面面,需要“瞻前顾后,通盘考虑”。
但在子系统中,研发人员只需要知道他要知道的东西,可想而知他无需过多负担即可展开工作。
微服务架构有什么特点?
- 组件化
- 松耦合
- 自治
- 去中心化
我目前对此的理解是:整个应该能像“乐高积木”那样搭建起来,而每个“积木”都是自己管好自己,之间没有说“谁离不开谁”,更没有说“谁是老大,大家都要听谁的”。
模块化与微服务化
在上面,我拿“积木”来打比方,说到积木,也许更容易想到模块化。
模块化也是“分而治之”,那么搞了模块化是不是就是搞了微服务化?
但细想,肯定是不行的。
- 首先,模块化的所有部件组合在一起,才是一个整体应用。而微服务要求分出的每个组件就是“独立的个体”。
- 也是同样的原因,就运维来说,他面对模块化的应用,在考虑资源时就是要全盘考虑。而面对微服务的组件时,就只考虑该组件就好。
- 就是因为“自己管好自己”,在保存 API 前后兼容情况下,微服务的组件时能独立演进。而不是模块化的“你要升级版本啊,不能,得等等大家,不然版本不一兼容不了”。
还有更宏大的层面,微服务架构,比模块化更加贴近公司的组织架构。
进阶内容
微服务的底层通信
我的理解是,微服务不能光顾着“拆”,还要设计好怎么“连”。
而这个“连”,就是微服务的底层通信。
从上图可以看到,微服务的底层通信基本分为两条路线,一条是 HTTP ,另一条是 RPC 。
我知道 go 语言里就有一个 gRPC 框架,说是用 go 语言所实现的 RPC 架构。
那么 RPC 是啥?
RPC
全称是远程过程调用(Remote Procudure Call)。
是一种计算机通信协议,它允许程序在本地调用远程计算机里的子程序,而不需要程序员额外编程。
简单来说,通过 RPC ,就是能在本地一样跑远程计算上的程序。
其中 RPC 就帮我们解决了如何编码请求、如何在网络上传输请求等问题。
RPC 本身可以基于很多协议基础上。
同样的,微服务应用的通讯也不一定用 RPC ,同样可以使用 HTTP 。(见图:微服务架构的底层通信)
额外话题:RESTful 与微服务架构
RESTful 是一种风格,符合 RESTful 风格的 Web 应用就是 RESTful Wed 。
微服务架构就是一种架构。
从此可见两者是没有什么关系。
只不过,可以这么操作:
- 通过 RESTful Web 来作为微服务架构的通信机制
- 将 RESTful Web 二次封装成 RPC ,用 RPC 协议来作为微服务架构的通信机制
微服务框架如何拆分?
怎么拆应用,方法肯定很多,包括并不限于以下:
- 业务驱动拆分
根据业务功能和业务边界来拆分微服务。将每个微服务专注于一个特定的业务领域,使其能够独立开发、部署和扩展。 - 功能驱动拆分
根据应用程序的功能模块来拆分微服务。每个微服务负责一个特定的功能,例如用户管理、订单处理、支付等。 - 数据驱动拆分
根据数据模型和数据访问需求来拆分微服务。每个微服务可以拥有自己的数据存储和数据访问逻辑,以实现数据的自治性和隔离性。 - 性能驱动拆分
根据性能需求和负载情况来拆分微服务。将高负载的功能或频繁访问的功能拆分为独立的微服务,以实现水平扩展和负载均衡。 - 事件驱动拆分
根据事件和消息的流动来拆分微服务。每个微服务可以订阅和处理特定类型的事件或消息,以实现松耦合和异步通信。 - API驱动拆分
根据应用程序的外部接口和服务契约来拆分微服务。每个微服务可以提供特定的API和服务,以满足不同的客户端需求。
当然,还有在查资料过程中发现的“显眼包”: DDD (Domain Driven Design) 领域驱动设计。
DDD 领域驱动设计
(上面已经有了它的简介,在此就不赘述了。) DDD 有着以下基本概念:
- 限界上下文(Bounded Context)
根据康威定律(组织设计出的系统,其设计结构等同于组织的沟通结构)- 解决问题的上下文
- 同样的业务模型在不同场景下,特征是不同的
- 描叙的就是微服务的边界
- 限界上下文有可能与组织架构重合
这里就那自己的工作打个比方,同样一款茶叶,作为茶艺师的我肯定关注其口感、滋味、成色,但作为仓库的我则关注其数量、规格。
在将其归入库时,我肯定不会想起滋味。
在用其招待客人时,我也不会傻乎乎的报出该茶叶的库存。
-
实体(Entity)
是指具有唯一标识和生命周期的对象。
还是那上面那茶来举例,我会给这茶编上一个作用于茶馆里的唯一编号————毕竟遇到过是一个名字却能对应到两种茶叶。
当一款茶叶卖到没了,同时以后不想再卖了,我会将该编号的茶从列表上“删除”。
在我的理解,这样的茶叶应该能算是实体。 -
值对象(Value Objbject)
“当一个领域中的实体跑到另外一个领域中,往往就成了值对象。”
就像我库存中的一款茶拿去招待客人,那它“数量、规格、在仓库位置”自然就成了不会被关心的“属性集合”。 -
聚合体(Aggregate)
- 可以看作是1个实体+ N 个值对象的集合。这时的实体也被叫成聚合根。
- 聚合体使用聚合根的ID为唯一标识符。
- 聚合体之间,只能通过ID来引用。
- 聚合根是修改聚合体的唯一入口。
-
工厂(Factory)
就是构造这些实体、值对象、聚合体的过程的抽象。
为的就是将构造过程与实际业务逻辑解耦。
当然,也不是只有“工厂”才能干这活,比如 builder 也能胜任。 -
仓库(Repository)
是数据存储的抽象,它屏蔽了缓存、数据库等问题。
大多数时候就是在对聚合体增删改查。 -
事件(Domain Event)
- 就是一般我们所说的事件。
- 事件的发布者和监听者,既可以是 Service,也可以是聚合体。
- 复杂事件依旧可以使用工厂模式来构造。
- 事件是从属于一个领域的,但是可以被多个不同领域的关心。
-
服务(Domain Service)
一般来说,我们希望尽可能将业务逻辑分散在聚合体、实体或者值对象里面。
但是部分业务逻辑跨越了多个聚合体,因此就引入了 Service 来完成这部分事情。 (在一般的增删改查项目中服务是没什么代码的,因为存储、查询相关的内容,都被 Repository 给处理掉了)
小结
到这里,我这茶艺师算是有点概念了:
- 微服务架构是一种软件架构,是对一个应用进行“化繁为简”。
- 微服务架构里的应用之间的通讯手段有很多种,对于 go 开发,直接用 gRPC 就没错。
- 微服务架构的拆分方法也是有很多种,其中 DDD 是最流行了。