# 微服务
# 微服务
:Microservices ,一种服务器架构,将业务系统从单个大型程序,拆分成多个小型程序,称为微服务。
优点:
- 将程序从单体架构拆分成微服务架构,有利于模块化的设计模式。
- 低耦合:每个微服务作为一个独立程序运行,通过 TCP、HTTP 等协议相互通信。不同服务可由不同团队同时开发,甚至可采用不同的编程语言。
- 容易扩展:想更新一个功能时,单体架构需要整体更新部署,而微服务架构只需要更新部分服务,不会中断其它功能。
- 故障隔离:某个功能故障时(比如进程崩溃),单体架构可能整个系统不可用,而微服务架构只是部分服务不可用。
- Docker 技术流行之后,微服务变得容易部署。通常将每个微服务部署到一个 Docker 容器中,用 k8s 编排。
缺点:
- 微服务架构存在一定难度,比如要提供服务发现机制、维护分布式系统。
- 单体服务执行一个事务时,通常要调用多个内部函数。而微服务执行一个事务时,通常要调用多个微服务的 API ,进行网络通信,因此耗时更久。
从头搭建微服务系统很麻烦,通常使用开源的微服务框架。例如:
- Spring Cloud
- :一个 Java 框架。微服务之间通过 RESTful API 进行通信,性能比 RPC 低。
- Dubbo
- :一个 Java 框架,由阿里巴巴公司发布。微服务之间通过 RPC 协议进行通信。
- Spring Cloud
# API Gateway
- 假设 client 需要访问多个 server ,分别发送 API 请求。可引入一个服务器作为网关,让 client 将请求统一发送到网关,然后网关再将请求转发到各个 server 。
- 使用网关便于批量管理 API ,进行路由、身份认证、权限控制、监控等操作,比单独在每个 server 处操作更方便。
- 单体服务通常对外暴露的 API 少,没必要用 API 网关。而微服务之间需要相互调用,存在大量 API ,因此通常使用 API 网关。
- API 网关的软件举例:
- Zuul
- :由 Netflix 公司开源,成为了 Spring Cloud 自带的组件。
- 性能较差,因此出现了试图取代它的新项目 Spring Cloud Gateway 。
- Kong
- :一个基于 OpenResty 服务器的网关。
- 提供了 4 层代理(TCP/UDP)、7 层代理、动态路由、健康检查、限流、身份认证、权限控制、日志等功能。
- APISIX
- :一个基于 OpenResty 服务器的网关。借鉴了 Kong ,但功能更多、性能更好。
- Zuul
# Service Mesh
:服务网格, 2016 年提出的一种微服务技术。
- 特点:
- 在服务器增加一个网络代理层,处理各个微服务收、发的网络流量,比如过滤、修改网络包。并提供服务发现、负载均衡等功能。
- Spring Cloud 等微服务框架只适用于特定的编程语言,还需要修改业务代码来适配。而 Service Mesh 属于透明代理,与编程语言无关,不侵入业务代码,即可管理网络流量。因此可将传统程序直接迁移到服务网络中,变为微服务架构。
- 几种框架举例:
- Envoy :2016 年,由 Lyft 公司发布,后来捐赠给 CNCF 基金会托管。采用 C++ 语言开发。
- Envoy 的核心是一个透明代理软件,支持代理 TCP、UDP、HTTP、gRPC 等多种协议的流量。还提供了服务发现、健康检查、负载均衡等功能。
- Linkerd :2016 年,由 Buoyant 公司发布。采用 Golang 语言开发。
- Istio :2017 年,由 Google、IBM、Lyft 公司联合发布。采用 Golang 语言开发,基于 Envoy 代理流量。
- Consul Connect :2018 年,由 HashiCorp 公司发布,作为 Consul 的新功能。
- Envoy :2016 年,由 Lyft 公司发布,后来捐赠给 CNCF 基金会托管。采用 C++ 语言开发。
# 标签路由
微服务系统中,可能某个服务同时部署了多个版本,需要供不同客户端访问。常见的解决方案是标签路由。
仅网关的标签路由方案:
- 原理:
- 服务 A 部署多个版本的实例,分别添加 env=v1、env=v2 等标签,表示服务版本。
- 客户端发送 HTTP 请求给网关,通过 uri、headers 等方式传递 env=xx 标签。
- 网关收到 HTTP 请求,发现该请求指向服务 A ,并且标签为 env=xx 。于是网关找到正确版本的服务实例,将请求转发过去。
- 优点:
- 实现简单。只有少量服务时,可用 Nginx 反向代理,不需要修改服务代码。有大量服务时,可用 Nacos、k8s 等服务发现平台,记录每个服务实例的标签。
- 缺点:
- 只在网关处进行了标签路由,服务之间没有标签路由。如果服务 A 还会调用服务 B ,而服务 B 也部署了多个版本,则会调用任一版本的服务 B 实例。
- 原理:
全链路的标签路由方案:
- 原理:
- 部署每个服务实例时,都添加形如 env=xx 的标签。
- 每个服务收到 HTTP 请求时,都会从 uri、headers 等信息中提取 env=xx 标签。如果该服务需要调用其它服务,则只能调用与当前标签相同的其它服务实例。
- 假设服务 A 收到 HTTP 请求,其中标签为 env=v1 。然后服务 A 需要调用服务 B ,只能从服务 B 的多个实例中,找出与当前标签相同的实例,调用它。
- 服务 A 调用服务 B 时,会在 HTTP 请求中传递 env=v1 标签,以便服务 B 继续调用服务 C ,实现全链路的标签路由。
- 如果不存在相同标签的服务 B 实例,则服务 A 可以调用默认版本的服务 B 实例,或者报错 HTTP 503 。
- 优点:
- 标签不同的服务不会相互调用,从而在逻辑上隔离网络流量,称为不同泳道。
- 例如给生产环境的所有服务实例设置 env=prod 标签,然后临时部署一组实例用于测试,设置 env=test 标签。这样可以快速、低成本地创建一个小型测试环境,适合灰度发布、线上调试。
- 标签不同的服务不会相互调用,从而在逻辑上隔离网络流量,称为不同泳道。
- 缺点:
- 需要修改服务代码,主动进行标签路由。
- 传统的部署方式中,生产环境与测试环境通常物理隔离,使用不同的服务器主机。而标签路由只是流量隔离,测试实例依然有可能影响正式实例,比如访问同一个数据库、中间件。
- 原理:
基于 Service Mesh 的自动化标签路由方案:
- 以 Istio 的 VirtualService 为例,当一个 HTTP 请求发送到服务 A 时,可通过 match 条件,判断应该路由到服务 A 的哪个 subset 。
- 例:
apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: service-a spec: hosts: - service-a.default http: - match: - headers: env: exact: v1 route: - destination: host: service-a.default subset: v1 - route: - destination: host: service-a.default subset: v2
- 当服务 A 收到 HTTP 请求而调用服务 B 时,需要传递 env=xx 标签。可通过 Istio 的 EnvoyFilter 自动修改服务 A 发出的 HTTP 请求,根据当前的 k8s label 取值,在 headers 中添加 env=xx 标签。
- 例:
- 优点:
- 不需要修改服务代码。
- 缺点:
- 需要为每个服务添加标签、VirtualService 配置,依然有些麻烦。可用自研的运维平台自动完成这些操作,使得开发人员能一键部署一套 env=xx 的服务实例,并自动配置标签路由,用完则一键销毁。
- 以 Istio 的 VirtualService 为例,当一个 HTTP 请求发送到服务 A 时,可通过 match 条件,判断应该路由到服务 A 的哪个 subset 。
# 相关概念
- 南北流量(North-South traffic)
- :指客户端与服务器之间的网络流量。因为绘制网络架构图时,通常服务器、客户端分别位于上下两侧。
- 东西流量(East-West traffic)
- :指服务器内部,各个服务之间的网络流量。
- 对于微服务架构,东西流量比南北流量更复杂、流量更大。
- API Gateway 擅长处理南北流量,但也可处理东西流量。Service Mesh 擅长处理东西流量,但也可处理南北流量。