1. 微服务的设计与运行

微服务五大核心原则:自治性、可恢复性、透明性、自动化和一致性。

2. SimpleBank 公司微服务

用了一个虚拟的公司业务来讲解微服务。帮助用户进行投资管理。

收集微服务业务指标、日志以及服务间的链路跟踪记录对于微服务应用当前和过去的运行表现是至关重要的。

3. 微服务应用的架构

微服务应用由四层组成:平台层、服务层、边界层和客户端层。

常见的边界层模式有 API 网关和消费者驱动的网关(GraphQL)。

4. 新功能设计

良好的服务三大特性:单一职责、可独立部署、可替换。

三种服务划分策略:

  • 按照业务能力和限界上下文(有着清晰范围和明确外部边界的内聚单元)划分,服务相对粗粒度但是又紧密团结成一个整体的业务功能领域
  • 用例划分。系统中将要发生的动作
  • 易变性。未来可能变化的领域封装在内部

以 SimpleBank 为例:

  • 用户管理服务
  • 资产信息服务
  • 投资策略服务

建议由内之外地设计微服务,在构建面向操作的细粒度的服务之前,先开发粗粒度功能。 不太好确定边界的时候,先开发大一点的服务。避免过早分解省下时间完善对问题域的了解

代码开放化、接口明确化、沟通持续化、放宽 DRY 原则的要求,可以缓解团队之间的紧张关系。

5. 微服务的事务与查询

5.1 分布式应用的事务一致性

2pc 之类的分布式事务会降低可用性

5.2 基于事件的通信

不建议分布式事务,使用 事件和编排

5.3 Saga

Saga 是一组互相协作的本地事务序列,每一步操作都由前一步骤触发。 saga中会使用补偿撤销之前的操作,并让系统恢复到更一致的状态,但是不保证恢复最初状态。

常用的一致性策略:

  • 补偿:撤销之前的操作
  • 重试:反复重试直到成功或者超时
  • 忽略:什么都不做
  • 重启:恢复到最初状态,然后重新开始执行
  • 临时:执行一个临时操作,稍后确认或者取消

5.4 分布式世界中的查询操作

  • 通过 API 组合,批量查询。
  • 保存数据副本。存储成本,缓存失效
  • 查询和命令分离
    • 乐观更新。比如用户 点赞之后客户端先假显。
    • 轮询。一直到版本号大于当前这个版本号
    • 发布订阅

6. 设计高可靠服务

故障无法消除,重点应该放在容忍依赖项出现故障,减小影响或者优雅恢复正常。

6.1 可靠性定义

正常时间(uptime),故障时间(downtime),可用性(availability)

防御式的方式来满足三个目标:

  • 无法避免的故障要降低发生率
  • 无法预测的故障控制其连锁影响
  • 故障发生之后可以快速恢复(自动恢复)

6.2 哪些会出错

故障: 硬件故障;上游依赖;数据库故障;第三方服务故障;下游微服务

  • 硬件故障:主机;数据中心;主机配置;物理网络;操作系统和资源隔离。通过冗余设计(多机房可用区)提升可用性
  • 通信故障:网络中断;防火墙(安全规则);dns 错误(解析出错);消息传输(rpc);健康检查不充分
  • 依赖故障:超时;功能下线或者不兼容;内部组件故障;外部依赖(三方 API)
  • 服务实践:测试不充分;硬件无法有效扩展

控制连锁故障: 断路器;后备方案;压测;容量规划;回退;重试;适当超时

6.3 设计可靠通讯方案

  • 重试。指数退避(exponential back-off)策略,随机抖动(jitter)
  • 后备方案。
    • 优雅降级。屏蔽部分功能,仅保修重要功能可用。
    • 缓存。使用缓存数据作为备用
    • 功能冗余。一个数据源出故障了,请求另一个数据源(多余的存储成本)
    • 桩数据。显示备用数据,总比展示空白好得多。做好兜底数据用来展示
  • 超时。超时过长可能消耗不必要的资源,太短可能导致失败率升高。寻找合适的时间。各种 client 一定要设置超时时间
  • 断路器。设计合理的阈值
  • 异步通信。小心单点故障,比如作为 broker 的中间件出了故障导致服务不可用

6.4 最大限度提高服务可靠性

单个服务的可用性和容错性:健康检查和限流

  • 负载均衡和服务健康。存活性(liveness):应用是否启动起来。 就绪性(readiness):是否正确处理请求
  • 限流。限制一个时间窗口的请求频率
    • 丢弃超过容量的请求
    • 关键数据请求优先。丢弃低优先级的请求
    • 丢弃不常见客户端的请求
    • 限制并行请求量
  • 验证可靠性和容错性。优雅恢复
    • 压力测试。根据预估请求建模
    • 混沌测试。删除服务、关闭服务网络连接或者引入更高层次延时。可以停掉一些服务验证整个系统是否正常

6.5 默认安全

框架和代理

  • 框架:实现了断路器、重试和后备方案等常见的交互模式的类库。标准化
  • 服务网络: 引入 service mesh 系统管理服务之间的重试、后备方案、断路器

7. 构建可复用的微服务框架

7.1 微服务底座

简化项目启动

7.2 底座的目的

降低风险、快速启动

  • 日志
  • 配置获取
  • 度量指标收集
  • 数据存储设置
  • 健康检查
  • 服务注册和发现
  • 传输协议样例代码(http/rpc)

7.3 设计服务底座

  • 服务发现
  • 可观测性。度量指标、报告错误信息、日志聚合
    • 度量指标(metric) statsd
    • 错误报告(error report) sentry
    • 日志(log)。logstash
  • 平衡和限流。python circuitbreker

7.4 探索使用底座实现的特性

8. 微服务部署

8.1 部署重要性

稳定性和可用性

8.2 微服务生产环境

六大基础功能:

  • 部署目标或者运行平台,也就是服务运行的地方
  • 运行时管理。启动愈合、扩容
  • 日志和监控
  • 支持安全运维,网络控制、密码凭证管理和应用加固
  • 负载均衡、dns、路由
  • 部署流水线

自动化和速度

8.6 不停机部署

  • 滚动部署
  • 金丝雀
  • 蓝绿部署

9. 基于容器和调度器的部署

9.1 服务容器化

docker pull python:3.6
docker run --interactive --tty python:3.6

9.2 集群部署

10. 构建微服务交付流水线

10.1 让部署变得平淡

部署流程应该满足:节奏安全;一致性

提交代码->构建->单元测试->打包->部署到预发布->测试预发布环境->部署到生产环境

10.2 使用 jenkins 构建流水线

构建(pypi) -> 单测(pytest) -> 打包 -> 部署到预发布环境(kubermetes/kubectl) -> 测试 -> 部署到生产环境

10.3 构建可复用流水线步骤

过程式和声明式构建流水线

10.4 降低部署影响以及实现功能发布的技术

11. 构建监控系统

11.1 稳固的监控技术栈

收集、存储、展示和分析。

四大黄金标志:

  • 时延。从请求发给指定的服务到完成请求所花费的时间
  • 错误量。执行不成功切没有正确结果的请求数据
  • 通信量。qps/网络 IO 等
  • 饱和度。指定时间点服务的承载能力(受限资源:CPU、内存、网络)

度量指标的类型:

  • 计数器。一直增加的数值 (incr)
  • 计量器(gauge)。可以展示任意单一数值的度量指标,数值可以增大或者减小。连接数,内存,cpu 使用,平均负载
  • 直方图(histogram)。 采样,并根据类型、时间等指标划分到不同配置的分类桶中。请求时延、IO 时延、响应字节数。

命名规则:服务名.方法.指标类型。比如 orders_service.sell_shares.count

11.2 利用 Prometheus 和 Grafana 监控

11.3 生成合理的可执行的告警

  • 系统出错时,哪些人需要知悉。告警应该有明确的优先级
  • 触发告警的应该是症状,而非原因。尽可能减少数量防止告警疲劳

11.4 监测整个应用

多个服务进行收集和聚合可以关联起来比较。

12. 使用日志和链路追踪了解系统行为

12.1 了解服务间行为

持久化日志;集中收集;容易检索和处理。

12.2 生成一致的、结构化的、人类可读的日志

日志中的有用信息:

  • 时间戳。尽可能用 GMT/UTC 收集数据
  • 标识符。尽可能唯一比如 uuid
  • 来源。主机、类名、模块、函数名、文件名
  • 日志等级或类别。 ERROR/DEBUG/INFO/WARN

结构化和可读性。比如使用 json 格式化

12.3 配置日志基础设施

搭建 ELK(Elasticsearch、Logstash、Kibana)。使用 Fluentd 把日志从应用推送到集中式的日志解决方案中。 服务把所有信息重定向到 STDOUT(标准输出),Fluentd 守护进程的代理负责把日志推送到 Elasticsearch。

  • Elasticsearch: 集中存储数据的查询和分析引擎。对日志数据建立索引,提供高效检索和聚合操作。
  • Logstash: 服务器端处理流水线,支持从多个来源获取数据,并将数据发送到 Elasticsearch之前对其进行转换。可以用 Fluentd 替代
  • Kibana: 可视化展示 Elasticsearch 界面的工具
  • FLuentd: 开源的数据收集器,可以把数据从服务推送到 Elasticsearch。应结合 Logstash 的数据格式化和收集功能,并 使用Fluentd 推送数据。

12.4 服务间的跟踪交互

使用 Jaeger 和一套 OpenTracing API (分布式链路追踪开放标准)兼容的类库。

请求关联:

  • trace: 由单个或者多个 span 组成的有向无环图(DAG),这些 span 的边称为 reference。trace 用于聚合和关联整个系统的执行流
  • span: 触发新的 span 需要传递父span 的 id

12.5 链路追踪可视化

13. 微服务团队建设

13.1 建设高效团队

划分独立团队

  • 确保沟通渠道可控。增强协作,缓解冲突。多大规模?两块披萨规则或者 7+-3公式。

康威定律。

高效团队原则:

  • 所有权
  • 自治。
  • 端到端职责。开发团队拥有产品的“设想-构建-运行”循环

13.2 团队模型

跨职能团队比传统团队更有效率。

13.3 微服务团队实践建议

设计评审,需要包含哪些:

  • 问题与背景
  • 解决方案
  • 依赖项与集成
  • 接口
  • 扩展性和性能
  • 可靠性
  • 冗余性(备份、恢复、部署和回滚)
  • 监控和仪表;
  • 故障场景
  • 安全性
  • 上线
  • 风险和开放问题。

动态文档:

  • 概述:服务目标、用途、架构
  • 契约:API 描述(swagger 等)
  • 使用说明:操作和故障场景
  • 元数据:编程语言、版本、工具链、部署 url

本书代码:本书代码