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

75 阅读7分钟

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

这里讲的主要是,微服务架构是当前大多数互联网公司的标准架构,本节课将重点讲解微服务架构背景由来及全貌,分析其基本原理及特征。治理实践是要和Service Mesh相关的昂!

微服务架构介绍

单体架构 -> 垂直应用架构 - 分布式架构 -> SOA架构 -> 微服务架构 -> ServiceMesh等架构......

单体架构

All in one

image-20230123092058186

  • 优点:

    • 性能最高
    • 冗余小
  • 劣势:

    • debug困难
    • 模块相互影响
    • 模块分工、开发流程

垂直应用架构

按照业务线,垂直划分

image-20230123092124672

  • 优点:

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

    • 不同业务存在冗余
    • 每个业务还是单体

分布式架构

抽出业务无关的公共模块

image-20230123092233976

  • 优点:

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

    • 公共服务模块bug可以导致全站瘫痪
    • 调用关系复杂
    • 不同服务冗余

SOA架构

Service Oriented Architecture

image-20230123092211467

  • 优势:

    • 服务注册
  • 劣势:

    • 整个系统设计是中心化的
    • 需要从上往下设计
    • 重构困难

微服务架构

彻底的服务化

image-20230123092454131

  • 优点:

    • 开发效率高
    • 业务独立设计
    • 自下而上
    • 故障隔离
  • 劣势:

    • 治理,运维艰难
    • 观测挑战
    • 安全性
    • 分布式系统

核心要素:

  • 服务治理:

    • 服务注册
    • 服务发现
    • 负载均衡
    • 扩缩容
    • 流量治理
    • 稳定性治理

    ...

  • 可观测性

    • 日志采集
    • 日志分析
    • 监控大盘
    • 监控打点
    • 链路追踪
    • 异常报警

    ...

  • 安全

    • 身份验证
    • 认证授权
    • 访问令牌
    • 审计
    • 传输加密
    • 黑产攻击

    ...

微服务架构原理及特征

  • Service: 一组具有相同逻辑的运行实体
  • Instance: 一个服务中,每个运行实体即为一个实例
  • 服务和实例的关系:没有必然关系,可以一个实例对应一个或多个线程
  • 集群:服务内部的逻辑划分,包含多个实例
  • 常见的实例承载形式:进程、VM、k8s pod......
  • 有状态/无状态服务:服务的实例是否存储了可持久化的数据(例如磁盘文件)

基本概念

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

image-20230123093354570

服务注册与发现

  • 如何指定一个目标服务的地址(ip:port)?

image-20230123094115333

DNS可以吗?

  • 问题:

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

解决思路:新增一个统一的服务注册中心,用于存储服务名到服务实例的映射。

image-20230123094355360

  • 服务上线以及下线的过程:

image-20230123094508740

如果服务还有流量,下线会有bug昂!先从注册服务下线对应的实例3,等到实例3没有外界流量的时候,再下线就ok了昂!

image-20230123095817865

上线反之,先拉起实例,然后测试一下,没有问题了,再去Service Registry中添加注册对应的实例,为实例引入流量昂!

流量特征

image-20230123100031892

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

HTTP是文本协议,运行效率比较低。RPC效率高得多,内部都是RPC。

核心服务治理功能

服务发布

服务发布:让一个服务升级,运行新的代码的过程。

核心问题:在线服务,一直有流量啊orz。

  • 服务发布难点:

    • 服务不可用
    • 服务抖动
    • 服务回滚

难不成,你让用户承担这些问题???

  • 发布方式:

    • 蓝绿部署(需要的资源多昂,流量低的时候好用)
    • 灰度发布/金丝雀发布(常用)

流量治理

流量控制:

image-20230123101815195

  • 流量控制的维度:

    • 地区
    • 集群
    • 实例
    • 请求

负载均衡

  • 常见的LB策略:

    • Round Robin
    • Random
    • Ring Hash
    • Least Request

稳定性治理

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

  • 常见问题:

    • 网络控制
    • 流量突增
    • 机房断电
    • 光纤被挖
    • 机器故障
    • 网络故障
    • 机房空调故障

    ......

  • 常见的功能:

    • 限流

    image-20230123102709992

    • 熔断

    image-20230123102732377

    • 过载保护

    image-20230123102807679

    • 降级

    image-20230123102823630

字节跳动服务治理实践

重试的意义

  • 本地函数调用的异常:

    • 参数非法
    • OOM
    • NPE
    • 边界case
    • 系统崩溃
    • 死循环
    • 异常退出

不用重试,肯定自己的代码有问题,再来也是一样的!

  • RPC:

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

要重试,并且重试过后可能就好了昂!

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

image-20230123103512800

  • 意义:

    • 降低错误率:假设单次请求的错误概率为0.01,那么连续两次错误概率则为0. 0001。
    • 降低长尾延时:对于偶尔耗时较长的请求,重试请求有机会提前返回。
    • 容忍暂时性错误:某些时候系统会有暂时性异常(例如网络抖动),重试可以尽量规避。
    • 避开下游故障实例:一个服务中可能会有少量实例故障(例如机器故障),重试其他实例可 以成功。

重试的难点

  • 幂等性,重试风暴,超时设置
  • 重试风暴:

image-20230123105843185

调用链很长,每一层都重试三次,直接就风暴了哈哈哈哈,害!

解决方法?

  • 重试风暴思路一:

image-20230123110026205

只有在大部分成功的情况下,才能进行重试。

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

  • 重试风暴思路二:

image-20230123110300444

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

重试策略

Hedged Requests,对冲请求

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

image-20230123110610384

重试效果验证

链路上发生的重试放大效应

image-20230123110824505