微服务架构原理与治理实践|青训营笔记

272 阅读6分钟

这是我参与「第三届青训营-后端场」笔记创作活动的第15篇笔记。

0.介绍

为什么有这门课?微服务架构是当前大多数互联网公司的标准架构。

可以学到什么?微服务架构的由来及原理;服务治理功能

1.微服务架构介绍

1.1 系统架构演变历史

为什么系统架构需要演进?

  • 互联网的爆炸性发展
  • 硬件基础的快速发展
  • 需求复杂性的多样化
  • 开发人员的极具增加
  • 计算机理论及技术的发展

架构演进

  1. 单体架构:all in one process
  • 优势:性能最高。冗余小。
  • 劣势(团队工作):debug困难。模块互相影响。模块分工、开发流程难以进行。
  1. 垂直应用架构:按业务线垂直划分

优势:业务独立开发维护 劣势:不同业务存在冗余。每个业务还是单体。

  1. 分布式架构:抽出业务无关的公共模块

优势:业务无关的独立服务 劣势:服务模块bug可能导致全站瘫痪。调用关系复杂。不同服务冗余。

  1. SOA架构:面向服务

优势:服务注册 劣势:整个系统设计是中心化的。需要从上至下设计。重构困难。

  1. 微服务架构:彻底的服务化

优势:开发效率高。业务独立设计。自下而上。故障隔离。 劣势:治理运维有难度。观测有挑战。分布式系统安全性问题。

1.2 微服务架构概览

image (2).png

1.3 微服务架构核心要素

  • 服务治理:服务注册、服务发现、负载均衡、扩缩容、流量治理、稳定性治理......
  • 可观测性:日志采集、日志分析、监控打点、监控大盘、异常报警、链路追踪......
  • 安全:身份验证、认证授权、访问令牌、审计、传输加密、黑产攻击......

2.微服务架构原理及特征

2.1基本概念

  • 服务(service):一组具有相同逻辑(同一服务源自同一代码,它们要做相同的事)的运行实体
  • 实例(instance):一个服务中,每个运行实体即为一个实例

实例与进程的关系:实例与进程之间没有必然对应关系,一个实例可以对应一个或多个进程(反之不常见)。

集群(cluster):通常指服务内部的逻辑划分,包含多个实例。

常见的实例承载形式:进程、VM、k8s pod......

有状态/无状态服务:服务的实例是否存储了可持久化的数据(例如磁盘文件)

服务间通信

  • 对于单体服务,不同模块通信只是简单的函数调用。
  • 对于微服务,服务间通信意味着网络传输

2.2 服务注册及发现

一个服务可能对应多个地址,而且地址可能变化。所以不能直接将服务的ip写在代码里。

DNS存在的问题:

  • 本地DNS存在缓存,ip变更需要刷新缓存
  • 负载均衡(一个服务对应多个ip时会使用第一个)
  • 不支持服务实例的探活检查
  • 域名无法配置端口(只能找ip,端口需要固定)

解决思路:新增一个统一的服务注册中心,用于存储服务名到服务实例的映射。服务下线前在服务中心注销,等没有流量过来时下线。注销同时注册另一个已测试的实例分担下线服务的流量。

2.3 流量特征

  • 统一网关入口
  • 内网通信多采用RPC(HTTP是文本协议,运行性能较差,RPC是二进制协议效率更高)
  • 网状调用链路

image (3).png

3.核心服务治理功能

3.1 服务发布

服务发布(deployment)即指让一个服务运行新的代码的过程。

难点:

  • 服务不可用:服务升级时不可用
  • 服务抖动:一个服务实例升级时,其他服务流量波动
  • 服务回滚:服务出现bug要回退版本,也会造成暂时不可用

蓝绿部署

集群分为两部分,分开升级。方法简单,但需要2倍资源。一般在流量低峰(凌晨)使用。

滚动发布(灰度发布)

分多批发布,直到所有实例更新。回滚困难,需要强大的平台(k8s等)支撑。

3.2 流量治理

在微服务架构下,我们可以基于地区、集群、实例、请求等维度,对端到端流量的路由路径进行精确控制。

image (4).png

3.3 负载均衡

负载均衡(Load Balance)负责分配请求在每个下游实例上的分布。

常见的LB策略:

  • 轮流
  • 随机
  • 哈希
  • 最少请求
  • .......

3.4 稳定性治理

线上服务总是会出问题,这与程序的正确性无关

  • 网络攻击
  • 流量突增
  • 机房断电
  • 光缆被挖
  • 机器故障
  • 网络故障
  • ........

为了应对这些问题,可以使用限流、熔断、过载保护、降级等方法。

4.重试实例

4.1 重试的意义

一些问题无需重试

  • 参数非法
  • OOM
  • NPE(Null pointer exception)
  • 边界case
  • 系统崩溃
  • 死循环
  • 程序异常退出

重试可能有效的情况:

  • 网络抖动
  • 下游负载高导致超时
  • 下游机器宕机
  • 本地机器负载高,调度超时
  • 下游熔断、限流
  • ........

重试的意义包括:

  • 避免偶发的错误,提高SLA(Service-Level Agreement)
  • 降低错误率:连续错误的概率比单词错误的概率更低。
  • 降低长尾延迟:对于偶尔耗时较长的请求,重试请求有机会提前返回。
  • 容忍暂时性错误:某些时候系统会有暂时性异常(例如网络抖动),重试可以尽量规避。
  • 避开下游故障实例:第一次可能恰巧使用故障机器,重试会访问同服务中未故障的机器。

4.2 重试的难点

  1. 幂等性
  2. 重试风暴(雪崩)
  3. 超时设置

4.3 重试策略

  1. 限制重试比例:设定一个充实比例阈值(例如1%),重试次数占所有请求比例不超过该阈值。
  2. 防止链路重试:链路层面的防止重试风暴的核心是限制每层都发生重试。理想情况下只有最后一层发生重试。可以返回特殊的状态
  3. Hedged requests(对冲):对于可能超时(或延迟高)的请求,重新向另一个下游实例发送一个相同的请求,并等待先到达的响应。