乐趣区

微服务化

问题

  1. 服务如何定义
  2. 服务如何发布和订阅
  3. 服务如何监控
  4. 服务如何治理(熔断机制等)
  5. 故障如何定位

基本组件

  1. 服务描述:

    1. RESTful API, 性能差
    2. XML, java 平台, 一般内部使用
    3. IDL, interface description language, 用作跨语言平台的服务之间的调用, 修改或者删除 PB 字段不能前向兼容

      • gRPC(google)
      • Thrift(facebook)
  2. 注册中心

    1. 服务提供者在启动时进行注册
    2. 服务消费者在启动时进行订阅
    3. 注册中心返回提供者的地址列表给消费者
    4. 当提供者发生变化, 注册中心通知消费者
  3. 服务框架

    1. 服务通信采用什么协议?
    2. 数据传输采用什么方式?
    3. 数据压缩采用什么格式?
  4. 服务监控

    1. 指标收集
    2. 数据处理
    3. 数据展示
  5. 服务追踪

    1. 消费者调用生成一个 requestId
    2. 提供者接到请求后记录 requestId, 如果需要调用其他服务, 再生成一个 requestId, 两个 id 一起往下传
  6. 服务治理

    1. 单机故障
    2. 单 IDC 故障
    3. 依赖服务不可用

注册中心

  1. 注册中心需要提供哪些接口

    1. 服务注册接口
    2. 服务注销接口
    3. 心跳汇报接口
    4. 服务订阅接口
    5. 服务变更查询接口
    6. 服务查询接口
    7. 服务修改接口
  2. 集群部署 zookeeper
  3. 目录存储, 区分版本号
  4. 服务健康状态监测
  5. 服务状态变更通知(zookeeper 的 watcher 机制)
  6. 白名单机制

RPC

  1. 客户端和服务端如何建立网络连接

    1. HTTP
    2. Socket

      1. 链路存活检测
      2. 断连重试
  2. 服务端如何处理请求: 使用成熟开源方案, 如 Netty、MINA 等

    1. 同步阻塞方式(BIO)
    2. 同步非阻塞方式(NIO)
    3. 异步非阻塞方式(AIO)
  3. 数据传输采用什么协议

    1. HTTP
    2. Dubbo
  4. 数据改如何序列化和反序列化

    1. 支持数据结构类型的丰富度
    2. 跨语言支持
    3. 性能

监控

  1. 监控内容

    1. 用户端监控: 业务直接对用户提供的功能的监控
    2. 接口监控: 业务提供的功能锁依赖的具体 RPC 接口的监控
    3. 资源监控: 某个接口依赖的资源的监控
    4. 基础监控: 对服务器本身的健康状况的监控
  2. 监控指标

    1. 请求量

      1. 实时请求量, QPS
      2. 统计请求量
    2. 响应时间
    3. 错误率
  3. 监控维度

    1. 全局维度
    2. 分机房维度
    3. 单机维度
    4. 时间维度
    5. 核心维度: 核心业务和非核心业务
  4. 监控系统原理

    1. 数据采集

      1. 服务主动上报
      2. 代理收集
    2. 数据传输

      1. UDP 传输
      2. Kafka 传输
    3. 数据处理

      1. 接口维度聚合
      2. 机器维度聚合
    4. 数据展示

追踪微服务调用

  • 作用

    1. 优化系统瓶颈
    2. 优化链路调用
    3. 生成网络拓扑
    4. 透明传输数据
  • 原理

    • 核心就是调用链: 通过一个全局唯一的 ID 将请求串起来
    • traceId: 用于标识某一次具体的请求 ID, 在第一层生成一个全局唯一的 id, 随着调用往后传递.
    • spanId: 用于标识调用在分布式请求中的位置. 第一层是 0, 进入下一层则是 0.1, 0.2, 再下一层是 0.1.1、0.1.2, 以此类推. 可以清晰查看上下游依赖.
    • annotation, 用于业务自定义埋点数据, 可以是业务感兴趣的想上传到后端的数据, 比如一次请求的 UID.
  • 服务追踪系统

    • 数据采集层, 负责数据埋点并上报给数据处理层. 1 次 RPC 请求可以分为四个阶段

      1. CS(Client Send): 生成调用上下文
      2. SR(Server Received): 生成服务端上下文
      3. SS(Server Send): 服务端上下文数据上报
      4. CR(Client Received): 将客户端上下文数据上报
    • 数据处理层, 负责数据的存储与计算

      1. 实时数据处理, 要求是秒级完成聚合运算

        1. Storm、Spark Streaming 进行聚合
        2. HBase 这样的 OLTP 数据仓库
        3. traceId 作为 RowKey, 天然将一条调用链聚合在一起
      2. 离线数据处理, 要求是小时级完成聚合运算

        1. MapReduce 或者 Spark 批处理做离线计算
        2. 存储用 Hive
    • 数据展示层, 负责数据的图形化展示

      1. 调用链路图

        • 服务整体情况
        • 每一层的情况
      2. 调用拓扑图

        • 调用依赖

微服务治理

  1. 本地调用, 变成 A 远程调用 B 之后, 可能遇到的问题

    1. 服务提供者问题

      1. B 有节点宕机
      2. B 有节点慢
      3. B 不稳定
    2. 网络问题

      1. A 和注册中心断连
      2. B 和注册中心断连
      3. A 和 B 断连
    3. 其他问题

      1. 注册中心宕机
  2. 节点管理手段

    1. 注册中心摘除机制: 如果有注册中心网络有问题会造成瘫痪
    2. 服务消费者摘除机制
  3. 负载均衡

    1. 随机算法
    2. 轮询算法
    3. 最少活跃调用算法
    4. 一致性 Hash 算法: 当有节点故障, 请求会平摊到其他节点上, 实现复杂度高.
  4. 服务路由

    1. 制定路由规则的原因

      1. 业务存在灰度发布的需求
      2. 多机房就近访问的需求
    2. 配置方式

      1. 静态配置: 放在服务消费者本地
      2. 动态配置: 放在注册中心
  5. 服务容错

    1. FailOver: 失败自动切换.

      • 调用失败或超时会切换节点重试. 要求操作幂等, 适用于读请求.
    2. FailBack: 失败通知.

      • 不重试, 通知详细失败情况, 适用于写请求.
    3. FailCache: 失败缓存.

      • 隔一段时间再重试, 如果立即重试可能加剧问题.
    4. FailFast: 快速失败.

      • 失败后记下日志就返回了, 适用于非核心业务.

Dubbo 框架里的微服务组件

  1. Dubbo 框架主要使用 XML 配置方式实现服务发布与注册、发现与引用

    1. 服务提供方

      1. xml 格式

        1. `dubbo:application` 标签, 声明 name 等提供方应用信息, 用于计算依赖关系
        2. `dubbo:registry` 标签, 声明使用 multicast 广播注册中心暴露服务地址
        3. `dubbo:protocol` 标签, 声明暴露的端口以及协议头(如 dubbo)
        4. `dubbo:service` 标签, 声明需要暴露的服务接口
        5. bean 标签, 和本地 bean 一样实现服务
    2. 服务发布
        - 根据 service 和 protocol 标签, 解析出一个 dubbo 协议头的 url, 调用 DubboProtocol 的 export()方法, 把服务暴露在相应端口
    3. 服务注册
        - 根据 registry 标签,  解析出一个 registry 协议头的 url, 调用 RegistryProtocol 的 export()方法, 将提供者 URL 注册到注册中心
2. 服务消费者
    1. xml 格式

        1. `dubbo:application` 标签, 声明 name 等消防费应用名, 用于计算依赖关系, 不要与提供方一致
        2. `dubbo:registry` 标签, 声明使用 multicast 广播注册中心暴露发现服务地址
        3. `dubbo:reference` 标签, 生成远程服务代理, 可以和本地 bean 一样使用远程接口.
    2. 服务引用
        - 根据 reference 标签, 解析出一个 dubbo 协议头的 url, 用 DubboProtocol 的 refer()方法, 得到服务的引用.
    3. 服务发现
        -  根据 registry 标签,  解析出一个 registry 协议头的 url, 调用 RegistryProtocol 的 refer()方法, 查询服务 demoService 的地址.
  1. 服务调用

    1. Dubbo 支持多种通信框架, 如 netty4, 需要在服务端的 XML 的 protocol 标签中, 定义 server 属性为框架名, 在客户端 SML 的 consumer 中, 定义 client 属性为框架名.
    2. 服务端采用 NIO 方式处理客户端的请求.
    3. 传输协议不仅支持私有的 Dubbo 协议, 还支持其他的如 Hessian、RMI、HTTP、Web Service、Thrift 等.
    4. 支持多种序列化格式, 如 Dubbo、Hession2.0、JSON、Java、Kryo 以及 FST 等, 可以在 protocol 标签的 serialization 属性定义.
  2. 服务监控

    • 无论提供者还是消费者, 在调用时都会经过 Filter 调用链拦截, 完成一些特定功能, 包括数据埋点.
  3. 服务治理

    • Invoker 是服务提供者节点的抽象, 封装了所有服务提供者的地址以及接口信息.

      • 节点管理

        • Directory 负责从注册中心获取服务节点列表, 并封装成多个 Invoker.
        • 值可能是动态变化的, 注册中心推送变更时更新.
      • 负载均衡

        • LoadBalance 负责从多个 Invoker 中选出某一的发起调用.
        • 选择是可以采用多种算法.
      • 服务路由

        • Router 负责从多个 Invoker 中按路由规则选出子集.
      • 服务容错

        • Cluster 将 Directory 中的多个 Invoker 伪装成一个 Invoker, 对上层透明, 伪装过程包含了容错逻辑.


注册中心如何落地

  1. 注册中心如何存储服务信息

    1. 内容

      1. 分组
      2. 服务名
      3. 节点信息

        1. 节点地址
        2. 节点其他信息
    2. 一般按照 ” 服务 - 分组 - 节点信息 ” 三层结构存储
  2. 工作包括四个工作流程

    1. 服务提供者注册流程

      1. 查看注册的节点是否在白名单内, 不在就抛异常, 在就继续
      2. 注册的 Cluster(服务的接口名)是否存在, 不在就抛错, 在就继续
      3. Service(服务的分组)是否存在, 不在就抛错, 在就继续
      4. 将节点信息添加到 Service 和 Cluster 下面
    2. 服务提供者反注册流程

      1. Service(服务的分组)是否存在, 不在就抛错, 在就继续
      2. Cluster(服务的接口名)是否存在, 不在就抛错, 在就继续
      3. 删除对应节点信息
      4. 更新 Cluster 的 sign 值
    3. 服务消费者查询流程

      1. 先从本机内存 (local cache) 中查找. 因为服务节点信息不总是时刻变化的.
      2. 接着从本地快照 (snapshot) 中查找, 这是持久化到本地的一个文件, 重启后连不上注册中心也可读.
    4. 服务消费者订阅变更流程

      1. 服务消费者从注册中心获取了服务信息后, 就订阅了服务的变化, 会在本地保留 Cluster 的 sign 值.
      2. 服务消费者每隔一段时间就获取注册中心 sign 值, 如果变了久就重新拉一份到本地.
  3. 注册与发现的几个问题

    1. 多注册中心: 对于服务消费者来说, 要能够同时从多个注册中心订阅服务; 对于服务提供者来说, 要能够同时向多个注册中心注册.
    2. 并行订阅服务: 避免某些服务初始化慢, 阻塞其他服务加载.
    3. 批量反注册服务.
    4. 服务变更信息增量更新: 防止网络频繁抖动出现问题, 可以只返回变更的接口.

开源服务注册中心如何选型

  1. 应用内注册

    • 定义: 注册中心提供服务端和客户端 SDK, 业务应用通过 SDK 与注册中心交互.
    • 典型应用: Netflix 开源的 Eureka

      • 组成

        1. Eureka Server
        2. 服务端的 Eureka Client
        3. 客户端的 Eureka Client
      • 特点

        • AP 型注册中心, 先保证可用性, 可能会牺牲一致性.
        • AP 型更适合微服务场景.
        • 多种语言时, 需要使用 Sidercar 解决方案.
  2. 应用外注册

    • 定义: 业务应用不通过 SDK 而是其他方式与注册中心打交道, 间接完成服务注册于发现.
    • 典型应用: Consul

      • 组成

        1. Consul: 注册中心的服务端.
        2. Registrator: 一个开源的第三方服务管理器项目, 通过监听服务部署的 Docker 实例是否存活, 来负责服务提供者的注册和销毁.
        3. Consul Template: 定时从注册中心服务端获取最新的服务提供者节点列表, 并刷新 LB 配置(如 Nginx 的 upstream).
      • 特点

        • CP 型注册中心, 先保证一致性, 会牺牲可用性.
        • 适合业务语言体系复杂的场景, 支持多语言接入.
        • 更适合云原生应用.
  3. CAP 理论

    • 意义

      • C, Consistency, 一致性
      • A, Availability, 可用性
      • P, Partion Tolerance, 分区容错性
    • 数据节点越多, 分区容错性越高, 数据一致性越难保证; 而为了保证数据一致性, 又会带来可用性的问题.

开源 RPC 框架选型

  1. 选择

    1. 跟语言平台绑定

      1. Dubbo: 阿里 2011 年开源, 仅支持 Java.
      2. Spring Cloud: Pivotal 公司 2014 年开源, 仅支持 Java.
      3. Motan: 微博 2016 年开源, 仅支持 Java.
      4. Tars: 腾讯 2017 年开源, 进支持 C ++.
    2. 跨语言

      1. gRPC: google 公司 2015 年开源.
      2. Thrift: Facebook 公司 2007 年贡献给 Apache 基金会, 成为开源项目.
  2. 明细

    1. Dubbo

    1. 组成
        1. Consumer
        2. Provider
        3. Registry
        4. Monitor, 监控系统
    2. SDK 方式提供
    3. 默认采用 Netty 作为通信框架.
    4. 通信协议: Dubbo、RMI、Hession、HTTP、Thrift
    5. 序列化格式: Dubbo、Hession、JSON、Kryo、FST
2. Motan
    1. 组成
        1. register: 服务端和客户端用来和注册中心交互
        2. protocol: 用来进行 RPC 服务的描述和 RPC 服务的配置管理, 这层可添加 filter 做统计和并发限制
        3. serialize: 序列化与反序列化, 默认使用 Hessian2.
        4. transport: 用来进行远程通信, 默认使用 Netty NIO 的 TCP 长连接方式.
        5. cluster: Client 短使用的模块, 是一组可用的 Server 在逻辑上的封装.
    2. SDK 方式提供
3. Spring Cloud
    1. 基于 Spring Boot 开发, 整合了开源行业中优秀的组件, 提供一整套解决方案.

    2. 工作流程
        1. 请求统一通过 API 网关 Zuul 来访问内部服务, 先经过 Token 进行安全认证.
        2. 通过安全认证后, Zuul 从注册中心 Eureka 获取可用服务结点列表.
        3. 从可用服务结点列表中选取一个可用节点, 然后把请求分发到这个节点.
        4. Hystrix 组件负责处理服务超时熔断
        5. Turbine 组件负责监控服务间的调用和熔断相关指标
        6. Sleuth 组件负责调用链监控
        7. ELK 负责日志分析
    3. 通信只能采用 HTTP 协议
4. gRPC
    1. 原理是通过 IDL(Interface Definition Language)文件定义服务接口, 通过代码生成程序生成具体实现代码.
    2. 通信协议采用 HTTP/2, 因其提供了连接复用、双向流、服务器推送、请求有限级、首部压缩等机制, 节省带宽、降低 TCP 连接次数, 节省 CPU, 对移动端来说延长电池寿命.
    3. IDL 使用 ProtoBuf, 由 google 开发的一种数据序列化协议, 压缩和传输效率极高, 语法简单.
    4. 多语言支持.
5. Thrify
    1. 有一套自己的 IDL
    2. 支持多种序列化格式: Binary、Compact、JSON、Multiplexed
    3. 支持多种通信方式: Socket、Framed、File、Memory、zlib
    4. 服务端支持多种处理方式: Simple、Thread Pool、Non-Blocking
  1. 未来语言不会成为 RPC 框架的约束, Dubbo、Motan 和 Spring Cloud 纷纷引入 Sidecar 组件来支持多语言.

如何搭建一个可靠的监控系统

  1. 以 ELK 为代表的集中式日志解决方案

    1. 结构

      1. Elasticsearch

        • 负责 search 和 analyze, 具有可伸缩、高可靠和易管理等特点, 基于 Apache Lucene 构建, 能对大容量的数据进行接近实时的存储、搜索和分析, 通常被用作基础搜索引擎.
      2. Logstash

        • 负责 collect 和 transform, 支持动态地从各种数据源收集数据, 并对数据进行过滤、分析、格式化等, 然后存储到指定的位置.
      3. Kibana

        • 负责 visualize 和 manage
    2. 需要在各个服务器部署 Logstash, 消耗 CPU 和内存, 所以又引入了 Beats 作为数据收集器, 后者占用的 CPU 和内存忽略不计, 可以从成百上千或成千上万台机器向 Logstash 或者直接向 Elasticsearch 发送数据. Beats 支持多种数据源:

      1. Packetbeat, 用来收集网络流量数据.
      2. Topbeat, 用来收集系统、进程的 CPU 和内存使用情况等数据.
      3. Filebeat, 用来收集文件数据.
      4. Winlogbeat, 用来收集 Windows 事件日志数据.
  2. 以 Graphiete、TICK 和 Prometheus 等为代表的时序数据库解决方案.

    1. Graphite

      1. 组成

        1. Carbon

          • 主要作用是接收被监控节点的连接, 收集各个指标的数据, 将这些数据写入 carbon-cache 并最终持久化到 Whisper 存储文件中去.
          • 对写入格式有一定要求: key+ 空格分隔符 +value+ 时间戳
        2. Whisper: 一个简单的时序数据库, 主要作用是存储时间序列数据, 可以按照不同的时间粒度来存储数据, 比如 1 分钟 1 个点、5 分钟 1 个点、15 分钟 1 个点三个精度来存储监控数据.
        3. Graphite-Web

          • 一个 Web App, 绘制报表与展示, 会先查询 carbon-cache, 查不到再去 Whisper 中找.
          • 查询方式http://graphite.example.com/render?target=servers.www01.cpuUsage&width=500&height=300&from=-24h
          • 支持丰富的函数target=sumSeries(products.*.salesPerMinute)
      2. 自身不包含数据采集组件, 但可以接入 StatsD 等开源数据采集组件来采集数据, 再传送给 Carbon.
    2. TICK

      1. 组成

        1. Telegraf(电报机), 负责收集数据
        2. InfluxDB, 时序数据库, 负责数据存储, 对写入数据格式要求<measurement>[,<tag-key>=<tag-value>...] <field-key>=<field-value>[,<field2-key>=<field2-value>...] [unix-nano-timestamp]
        3. Chronograf, 负责数据展示
        4. Kapacitor, 实时数据流处理引擎, 负责数据告警
    3. Prometheus

      1. 组成

        1. Prometheus Server: 用于拉取 metrics 信息并将数据存储在时序数据库
        2. Jobs/Exporters: 用于暴露已有的第三方服务的 metrics 给 Prometheus Server, 比如 StatsD、Graphite 等, 负责数据收集.
        3. Pushgateway: 主要用于短期的 jobs, 可能在 Prometheus Server 来拉取之前就消失了, 所有提供了 push 机制.
        4. Alertmanager: 用于数据报警.
        5. Prometheus web UI: 负责数据展示
      2. 工作流程

        1. Prometheus Server 定期从配置好的 jobs 或者 exporters 中拉取 metrics 信息, 或者接收来自 Pushgateway 发过来的 metrics 信息. 格式<metric name>{<label name>=<label value>, …}
        2. Prometheus Server 把收集到的 metrics 信息存储到时序数据库中, 并运行定义好的 aler.rules, 向 Alertmanager 推送警报.
        3. Alertmanager 根据配置文件, 对接收的警报进行处理, 发出告警.
        4. 通过 Prometheus web UI 进行可视化展示.
  3. 选型比对

    1. ELK 的技术栈比较成熟, 应用范围也比较广, 除了可用作监控系统外, 还可以用作日志查询和分析. 缺点是实时性不如时序数据库, 不能保证 10s 内的延迟.
    2. Graphite 需要搭配数据采集系统如 StatsD, 基于时序数据库, 提供了强大的各种聚合函数, 对外提供 API 可以接入 Grafana, 比原生的美观.
    3. TICK 的核心在于时序数据库 InfluxDB 存储功能强大, 支持类似 SQL 语言的复杂数据处理操作, 也建议用 Grafana 替换掉原生的 Chronograf.
    4. Prometheus 的独特之处在于采用了拉数据的方式, 对业务影响较小, 也采用了时序数据库, 支持独有的 PromQL 查询语言. 比较适合 Docker 封装好的云原生应用.

如何搭建一套适合你的服务追踪系统

  1. 服务追踪系统

    1. 埋点数据收集, 负责在服务端进行埋点, 来收集服务调用的上下文数据.
    2. 实时数据处理, 负责对收集到的链路信息, 按照 traceId 和 spanId 进行串联和存储.
    3. 数据链路展示, 把处理后的服务调用数据, 按照调用链的形式展示出来
  2. 有名的服务追踪系统

    1. 阿里的鹰眼, 为开源, 数据量大, 相对定制化, 不一定适合中小规模业务团队.
    2. Twitter 开源的 OpenZipkin
    3. 还有 Naver 开源的 Pinpoint
  3. OpenZipkin

    1. 4 个核心部分

      1. Collector: 负责收集探针 Reporter 埋点采集的数据, 经过验证处理并建立索引.
      2. Storage: 存储服务调用的链路数据, 默认使用的是 Cassandra, 也可以换成 ElasticSearch 或者 MySQL
      3. API: 将格式化和建立索引的链路数据以 API 的方式对外提供服务
      4. UI: 以图形化的方式展示服务调用的链路信息
    2. 流程是通过在业务的 HTTP Client 前后引入服务追踪代码, 在 HTTP 方法调用前, 生成 trace 信息, 返回结果后, 记录耗时, 再把这些信息异步上传给 ZipKin Collector.
  4. Pinpoint

    1. 深度支持 Java
    2. 4 个核心部分

      1. Pinpoint Agent: 通过 Java 字节码注入的方式, 收集 JVM 中的调用数据, 通过 UDP 协议传递给 Collector, 数据采用 Thrift 协议进行编码.

        • 即 JVM 在加载 class 二进制文件时, 动态地修改加载的 class 文件, 在前后执行拦截器的 before 和 after 方法.
        • 只需要在 JVM 启动时添加启动参数即可.
      2. Pinpoint Collector: 收集 Agent 传过来的数据, 然后写到 HBase Storage.
      3. HBase Storage
      4. Pinpoint Web UI: 通过 Web UI 展示服务调用的详细链路信息
  5. 选型对比

    1. 埋点探针支持平台的广泛性

      • OpenZipkin 提供了不同语言的 Library, 使用范围广, 开源社区更活跃, 生命力更强.
    2. 系统集成难易度

      • OpenZipkin 必须在配置里面添加相应配置文件并且增加 trace 业务代码
      • Pinpoint 通过字节码注入实现拦截服务调用, 不需要代码改动.
    3. 调用链路数据的精确度

      1. OpenZipkin 数据只到接口级别, 进一步的信息就没有了.
      2. Pinpoint 还能深入到调用所关联的数据库信息

如何识别服务节点存活

  1. Zookeeper 的机制是注册中心摘除机制. 当网络频繁抖动时会有问题.
  2. 动态注册中心解决方案

    1. 心跳开关保护机制

      • 给注册中心设置一个开关, 打开后即便网络频繁抖动, 也不全量通知, 而是部分通知.
      • 好处是将请求量降下来.
      • 坏处是拉取最新节点信息的延迟更高.
    2. 服务节点摘除保护机制

      • 设定一个阈值比例, 比如 20%(根据业务冗余度确定), 注册中心不能摘除超过这个阈值比例的节点, 以免引起存活实例被压垮引发雪崩.
  3. 静态注册中心解决方案

    1. 移除不可用节点放在消费者一端. 如果连续失败超过一定次数, 就可以将其标为不可用, 并且每隔一段时间做一次探活.
    2. 当业务上线或者运维人员人工增加或者删除服务节点这种预先感知的情况下, 还是有必要去修改注册中心的服务节点信息.

负载均衡算法

  1. 常见

    1. 随机
    2. 轮询
    3. 加权轮询
    4. 最少活跃连接数
    5. 一致性 hash 算法: 可以保证相同来源的请求到同一个节点, 适合服务端节点处理不同客户端请求差异较大的场景, 比如缓存用户数据的情况.
  2. 自适应最优选择算法

    1. 在客户端本地维护一份同一个服务节点的性能统计快照, 并且定时更新.
    2. 根据二八原则分成两部分, 将最慢的 20% 的节点降权.

路由

  1. 应用场景

    1. 分组调用: 异地多活
    2. 灰度发布
    3. 流量切换
    4. 读写分离
  2. 两种规则

    1. 条件路由

      1. 排除某个服务节点
      2. 黑白名单
      3. 机房隔离
      4. 读写分离
    2. 脚本路由

      1. js
      2. groovy
      3. JRuby
  3. 服务路由的获取方式

    1. 本地配置
    2. 配置中心管理
    3. 动态下发: 运维或者开发人员, 通过服务治理平台修改路由规则, 平台调用配置中心接口, 把规则持久化到配置中心.

服务端出现故障

  1. 集群故障

    1. 原因

      1. 代码 bug, 比如不断分配大对象, 没有及时回收导致 OOM
      2. 突发的流量冲击
    2. 应对思路

      1. 限流: 超过阈值的请求丢弃.
      2. 降级: 通过停止系统中的某些功能, 来保证系统整体的可用性.

        1. 通过开关来实现, 如果开关打开, 则跳过某些功能和逻辑. 正常情况下, 开关是关闭的.
        2. 用在两个地方

          1. 新增的业务逻辑
          2. 依赖的服务或资源
  2. 单 IDC 故障

    1. 基于 DNS 解析的流量切换(联通 / 电信)
    2. 基于 RPC 分组的流量切换(多个 IDC 之间的切换)
  3. 单机故障

    • 自动化重启

调用失败时如何应对

  1. 超时

    • 设置一个 P999 或者 P9999 的值, 也就是以 99.9% 或者 99.99% 的调用都在多少毫秒内返回为准.
  2. 重试

    1. 如果是偶然原因造成的调用失败, 那假如一次调用失败的概率是 1%, 连续两次失败的概率就是万分之一, 是原来失败率的 1%.
    2. 保持接口幂等性.
  3. 双发

    1. 鲁莽的双发: 每个请求直接发起两次调用, 并以先返回的结果为准, 还能降低平均响应时间. 这会给服务端 2 倍的压力.
    2. 聪明的双发: 在给定的时间内如果没有返回, 就再发起一次.

      • 这个时间比超时时间短很多, 可以取到 P99 或者 P90.
      • 设置一个最大重试比例, 避免服务端出现问题时, 大家都发两次. 可以设置成 15%.
    3. 注意接口的幂等性.
  4. 熔断

    1. Closed 状态: 正常情况下, 断路器是处于关闭状态的, 偶发的调用失败也不影响.
    2. Open 状态: 当服务调用失败次数达到一定阈值时, 断路器就会处于开启状态, 后续的服务就直接返回, 不会向服务提供者发起请求.
    3. Half Open 状态: 当断路器开启后, 每隔一段时间, 就会进入半打开状态, 这时候会向服务提供者发起探测调用, 以确定服务提供者是否恢复正常. 如果调用成功, 断路器就关闭, 如果没有成功, 断路器就继续保持开启, 并等待下一个周期重新进入半打开状态.
    4. 可以参照 Hystrix.
退出移动版