微服务架构 | 青训营笔记

37 阅读5分钟

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

只不过是字节给我的任务罢了

系统架构演变历史

单体架构——分布式架构——微服务架构

单体架构

  • 优势

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

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

垂直应用架构

按照业务线垂直划分

  • 优势

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

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

分布式架构

  • 优势

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

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

SOA架构

面向服务

  • 优势

    • 服务注册
  • 劣势

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

微服务架构

彻底的服务化

  • 优势

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

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

微服务架构核心要素

  • 服务治理

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

    • 日志采集
    • 日志分析
    • 监控打点
    • 监控大盘
    • 异常报警
    • 链路追踪(服务链式调用)
  • 安全

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

微服务架构原理及特征

基本概念

  • 服务:一组具有相同逻辑的运行实体

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

  • 实例与进程的关系

    • 实例与进程之间没有必然的对应关系,可以一个实例对应一个或多个进程
  • 集群

    • 通常指服务内部的逻辑划分,包含多个实例
  • 常见的实例承载形式

    • 进程、VM、k8s pod
  • 有状态/无状态服务

    • 服务的实例存储了持久化的数据就是有状态的服务,反之无状态

服务间通信

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

服务注册与发现

目标服务端地址是动态变化的,因此新增一个服务注册中心,用于存储服务名到服务实例的映射

某服务实例上线前,先将服务实例添加到服务中,经过健康检查后,再将该服务实例注册到服务注册中心

某服务实例下线前,先在服务注册中心将该服务实例的记录删掉,当没有流量流入该服务实例时,就可以删除这个服务实例了

流量特征

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

核心服务治理功能

服务发布

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

  • 难点

    • 服务不可用
    • 服务抖动
    • 服务回滚
  • 蓝绿部署

    1. 将绿色集群的流量切换到蓝色集群

    2. 将绿色集群升级完毕后

    3. 将流量切换回绿色集群

    4. 再升级蓝色集群

    • 优点:简单稳定,但是需要两倍资源
  • 灰度发布(金丝雀发布)

    • 不停地添加新实例试探是否可以健康运行,可以健康运行则下线一个老实例,滚动发布

流量治理

在微服务架构下,可以基于地区、集群、实例、请求等维度,对端到端流量的路由路径选择

负载均衡

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

常见LB策略

  • Round Robin
  • Random
  • Ring Hash
  • Least Request

稳定性治理

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

  • 限流

    • 限制流量,拒绝过多的流量
  • 熔断

    • 调用某服务时,发现该服务异常,这时自身熔断,拒绝上游流量,间断性尝试调用异常的服务。
  • 过载保护

    • 某服务压力过大时,拒绝调用它的服务的一部分流量,或全部拒绝
  • 降级

    • 保障重要服务正常工作,拒绝低等级的次要流量

实践

重试的意义

远程函数调用可能出现异常

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

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

  • 降低错误率

    • 假设单次请求的错误率为0.01,那么连续两次为0.0001
  • 降低长尾延时

    • 对于偶尔耗时较长的请求,重试请求有机会提前返回
  • 容忍暂时性错误

    • 某些时候系统会有暂时性异常,重试可以规避
  • 避开下游故障实例

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

重试有这么多好处,但是默认不用

重试的难点

  • 幂等性

  • 重试风暴

    • 链路上的每个多重试,放大了重试次数
  • 超时设置

重试策略

  • 限制重试比例

    • 设定一个重试比例,重试次数占所有请求比例不超过该阈值
  • 防止链路重试

    • 限制每层都重试,理想情况下只有最下一层重试,可以返回特殊的status表明“请求失败,但别重试”
  • Hedged requests

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

参考

juejin.cn/post/719438…

juejin.cn/course/byte…