微服务架构 | 青训营笔记

62 阅读8分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 10 天

微服务架构原理与治理实践

背景

微服务架构是当前大多数互联网公司的标准架构。

主要学习微服务架构的由来及原理、服务治理功能工作机制。

1.微服务架构介绍

1.1 系统架构演变历史

架构演变的原因

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

单体架构 —> 垂直应用架构 —> 分布式架构 —> SOA 架构 —> 微服务架构

单体架构
  • 优势

    1. 性能最高
    1. 冗余小
  • 劣势

    1. debug 困难
    1. 模块相互影响(非核心功能可能导致程序崩溃)
    2. 模块分工、依赖管理困难,开发流程几乎无法分工
垂直应用架构

安装业务线垂直划分

  • 优势:业务独立开发维护

  • 劣势

    1. 不同业务存在冗余,无法复用
    2. 每个业务还是单体
分布式架构

抽取出业务无关的公共模块

  • 优势:业务无关的独立服务

  • 劣势

    1. 服务模块 bug 可能导致全站瘫痪
    2. 调用关系复杂
    3. 不同服务冗余
SOA 架构(Service Oriented Architecture)

面向服务的架构

  • 优势:服务注册

  • 劣势

    1. 整个系统设计是中心化的
    2. 需要从上至下设计
    3. 重构困难
微服务架构

彻底服务化的架构

  • 优势

    1. 高效的开发迭代效率
    2. 业务独立设计
    3. 自下而上设计
    4. 故障隔离可控
  • 劣势

    1. 治理、运维难度急剧增加
    2. 观测挑战
    3. 安全性问题
    4. 分布式系统本身的复杂性

1.2 微服务架构概览

从组件的维度去分析微服务架构的整体视角

  • 服务配置和治理:服务配置、服务治理

  • 消息队列 MQ

    • 用户服务:用户数据库
    • 商品服务:商品数据库
    • 订单服务:订单数据库
    • 广告服务:数据仓库、Redis
  • 链路追踪和监控:链路追踪、服务监控

  • 网关

1.3 微服务架构核心要素

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

1.4 总结

  • 系统架构的演变历史
  • 微服务架构的整体概览
  • 微服务架构的核心要素

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

2.1 基本概念

  • 服务(service)

    一组具有相同逻辑的运行实体。

  • 实例(instance)

    一个服务中,每个运行实体即为一个实例。

  • 实例与进程的关系

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

  • 集群(cluster)

    通常指服务内部的逻辑划分,包含多个实例。

  • 常见的实例承载形式

    进程、VM、k8s pod、......

  • 有状态/无状态服务

    服务的实例是否存储了可持久化的数据,例如磁盘文件。

  • 服务间通信

    对于单体服务,不同模块通信只是简单的函数调用。

    对于微服务,服务间通信意味着网络传输。

2.2 服务注册与发现

问题:在代码层面,如何指定调用一个目标服务的地址(ip:port)?

硬编码 hardcode
 // Service A want to call Service B.
 client := grpc.NewClient("10.23.45.67:8080")

硬编码 hardcode 的问题:当服务存在多个实例时,hardcode 无法调用动态变化的服务地址。

DNS

DNS 的思想就是中间层。

DNS 的问题

  • 本地 DNS 存在缓存,导致延时。
  • 负载均衡问题。
  • 不支持服务实例的探活检查。
  • 域名无法配置端口。
服务注册中心 Service Registry

解决思路:新增一个统一的服务注册中心,用于存储服务名到服务实例的映射。与 DNS 类似,也是一个中间层。

服务实例上线及下线过程
  • 当一个实例还有流量时,不能直接下线,当它没有流量时,可以下线。
  • 当一个服务下线几个实例后访问压力过大,可以添加新的实例到服务中。
  • 新启用的实例会先进行健康检查,检查无误后再注册到服务中心。
  • 健康检查是在服务运作期间一直持续进行的。

2.3 流量特征

  • 统一网关路口
  • 内网通信多数采用 RPC
  • 网状调用链路

弱化连接的概念,强调“请求”,即同一个客户端长连接发出的请求,理论上可以到达服务中所有实例。网关 gateway 可以用于身份认证,进而将 token 附在请求上。

2.4 总结

  • 微服务架构中的基本组件及术语
  • 服务注册及发现中间层
  • 平滑无损的服务实例上下线流程
  • 微服务架构中的基本流量特征

3.核心服务治理功能

3.1 服务发布

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

服务发布的难点

  • 服务不可用
  • 服务抖动
  • 服务回滚
  • 蓝绿部署问题
  • 灰度发布(金丝雀发布)问题

3.2 流量治理

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

3.3 负载均衡

负载均衡(Load Balance)负责分配请求在每个下游实例上以控制分布情况。

常见的 LB 策略

  • Round Robin
  • Random
  • Ring Hash
  • Least Request
  • ......

3.4 稳定性治理

线上服务难免会出现问题,这和程序本身正确性无关。

  • 网络攻击
  • 流量突增
  • 机房断电
  • 光纤断开
  • 机器故障
  • 网络故障
  • 机房空调故障
  • ......

微服务架构中典型的稳定性治理功能

  • 限流
  • 熔断
  • 过载保护
  • 降级

3.5 总结

  • 服务发布:蓝绿部署、灰度发布
  • 基于地区、集群、实例、请求等维度的流量治理功能
  • 几种常见的负载均衡策略
  • 微服务架构中的稳定性治理功能

4.服务治理实践

4.1 重试的意义

本地函数调用可能引发的异常
  • 参数非法
  • OOM(Out Of Memory)
  • NPE(Null Pointer Exception)
  • 边界 case
  • 系统崩溃
  • 死循环
  • 程序异常退出

本地函数没有重试的意义

远程函数调用可能引发的异常
  • 网络抖动
  • 下游负载高导致超时
  • 下游机器宕机
  • 本地机器负载高,调度超时
  • 下游熔断、限流
  • ......

远程函数需要进行重试

重试可以避免掉偶然发生的错误,提高 SLA(Service-Level Agreement)

  • 降低错误率

    假设单次请求的错误率为 0.01,那么连续两次的错误的概率为 0.0001。

  • 降低长尾延时

    对于偶尔耗时较长的请求,重试请求有机会提前返回。

  • 容忍暂时性错误

    某些时候系统会有暂时性异常,例如网络抖动,重试可以尽量规避。

  • 避开下游故障实例

    一个服务中可能会有少量实例故障,例如机器故障,重试其他实例可以成功。

4.2 重试的难点

  • 幂等性:多次请求可能会造成数据不一致。
  • 重试风暴:随着调用深度的增加,重试次数会指数级上涨。
  • 超时设置:间隔多少时间后发起重试请求。例如,服务 A 向服务 B 重试 3 次,但服务 B 需要向服务 C 重试 9 次,服务 C 需要向服务 D 重试 27 次,以此类推。

4.3 重试策略

重试只有在大部分请求都成功,只有少部分请求失败时,才有必要。如果大部分请求都失败,重试只会加剧问题严重性。

限制重试比例

设定一个重试比例阈值,例如 1%,重试次数占所有请求次数比例不能超过该阈值。

防止链路重试

链路层面的防重试风暴的核心是限制每层都发生重试,理想情况下是只有最下一层发生重试。可以返回特殊的 status 表明“请求失败,但不进行重试”。

缺点是需要侵入性修改业务代码。

Hedged requests

对于可能超时或延时高的请求,重新向另一个下游实例发送一个相同的请求,并等待先到达的响应。

4.4 重试效果验证

实际验证经过上述重试策略后,在链路上发生的重试放大效应。

4.5 总结

  • 重试的意义及难点
  • 应对重试风暴的策略

归纳总结

  • 微服务架构介绍
  • 微服务架构原理及特征
  • 核心服务治理功能
  • 服务治理实践

参考资料

什么是蓝绿部署、滚动发布和灰度发布?

Motan系列6:负载均衡(LoadBalance)

【后端专场 学习资料四】第五届字节跳动青训营