微服务设计

2021-08-21 系统架构 微服务

# 一、API 网关的演进

# 1.1 阶段一:Service 直连

初期按照垂直功能进行了拆分,对外暴露了一批微服务,但是因为缺乏统一的出口面临了不少困难:

  • 客户端到微服务直接通信,强耦合;
  • 需要多次请求,客户端聚合数据,工作量巨大,延迟高;
  • 协议不利于统一,各个部门间有差异,需要端来兼容;
  • 面向“端”的 API 适配(如 ios 不同版本的适配),耦合到了内部服务;
  • 统一逻辑无法收敛,比如安全认证、限流。

# 1.2 阶段二:引入 BFF 层

接下来新增了一个 app-interface 用于统一的协议出口,在服务内进行大量的 dataset join,按照业务场景来设计粗粒度的 API,给后续服务的演进带来的很多优势:

  • 轻量交互:协议精简、聚合;
  • 差异服务:数据裁剪以及聚合、针对终端定制化 API;
  • 动态升级:原有系统兼容升级,更新服务而非协议;
  • 沟通效率提升,协作模式演进为移动业务 + 网关小组。

说明

BFF(Backend for Frontend)可以认为是一种适配服务,将后端的微服务进行适配(主要包括聚合裁剪和格式适配等逻辑),向无线端设备暴露友好和统一的 API,方便无线设备接入访问后端服务。

# 1.3 阶段三:拆分 BFF 层

阶段二的架构最致命的一个问题是整个 app-interface 属于 single point of failure,严重代码缺陷或者流量洪峰可能引发集群宕机,此外,单个模块也会导致后续业务集成复杂度高,根据康威法则,单个 BFF 和多个团队之间容易出现不匹配问题,团队之间沟通协调成本高,交付效率低下。因此接下来对 BFF 层进行了拆分,如下图所示:

但这样拆分之后,很多跨横切面逻辑,比如安全认证、日志监控、限流熔断等维护困难。随着时间的推移,代码变得越来越复杂,技术债越堆越多。

# 1.4 阶段四:引入 API 网关

跨横切面(Cross-Cutting Concerns)的功能,需要协调更新框架升级发版(路由、认证、限流、安全),因此全部抽离,引入了 API Gateway,把业务集成度高的 BFF 层和通用功能服务层 API Gateway 进行了分层处理。

在新的架构中,网关承担了重要的角色,它是解耦拆分和后续升级迁移的利器。

  • 在网关的配合下,单块 BFF 实现了解耦拆分,各业务线团队可以独立开发和交付各自的微服务,研发效率大大提升
  • 另外,把跨横切面逻辑从 BFF 剥离到网关上去以后,BFF 的开发人员可以更加专注业务逻辑交付,实现了架构上的关注分离

那么,此时的业务流量实际为:移动端 -> API Gateway -> BFF -> Microservice;在 FE Web 中,BFF 可以是 nodejs 来做服务端渲染(SSR, Server-Side Rendering)。注意:这里忽略了上游的 CDN,4 / 7 层负载均衡(ELB)。

# 二、微服务的划分

# 2.1 基于业务职能

在对业务领域不是特别熟悉的时候,可以按照 业务职能(Business Capability) 进行划分,例如客户服务部门提供客户服务的职能,财务部门提供财务相关的职能。注意划分的时候要 闭环,不要相同的功能散落到几个部门当中。

# 2.2 基于限界上下文

在系统稳定之后,积累了相关的业务经验和微服务开发经验之后,再考虑使用 DDD 限界上下文进行划分。

限界上下文(Bounded Context) 是 DDD 中用来划分不同业务边界的元素,这里业务边界的含义是“解决不同业务问题”的问题域和对应的解决方案域,为了解决某种类型的业务问题,贴近领域知识,也就是业务。

  • 如果可以闭环的解决一个用户场景,那么它应该是一个微服务;
  • 还可以根据访问频率进行区分划分,将用户高频访问的部分划分为一个服务。

这本质上也促进了组织结构的演进:Service per team

# 2.3 基于读写场景

CQRS,将应用程序分为两部分:命令端和查询端。

  • 命令端处理程序创建,更新和删除请求,并在数据更改时发出事件;
  • 查询端通过针对一个或多个物化视图执行查询来处理查询,这些物化视图通过订阅数据更改时发出的事件流而保持最新。

# 三、微服务的安全

# 3.1 外网间安全

  1. 在 API Gateway 进行统一的认证拦截,一旦认证成功,我们会使用 JWT 方式通过 RPC 元数据传递的方式带到 BFF 层;
  2. BFF 校验 Token 完整性后把身份信息注入到应用的 Context 中,BFF 到其他下层的微服务,建议是直接在 RPC Request 中带入用户身份信息(UserID)请求服务。

# 3.2 内网间安全

对于服务内部,一般要区分身份认证和授权。

  • Full Trust:假定内网服务之间是安全的,在内网裸奔;
  • Half Trust:内网服务之间需要进行认证鉴权,但是不需要所有的都进行加密;
  • Zero Trust:零信任,任务内部网络是不安全的,类似公网,所有的请求通过身份认证鉴权之后,都需要通过安全加密,防止被嗅探。
Last Updated: 2023-01-28 4:31:25