《持续演进的Cloud Native: 原原生架构下的微服务最佳实践》
王启军/著 (公众号:奔跑中的蜗牛)
电子工业出版社
2018.10出版
Cloud Native的组成

Cloud Native需要从架构、研发流程和团队文化三个角度来实现,三者需要相互配合,缺一不可。
-
架构
Cloud Native是以云和微服务架构为基础,云包含了敏捷基础设施及公共基础组件。同时还需要考虑架构的质量属性。
-
研发流程
自动化的研发环境是Cloud Native的基础。尽量减少测试及运维对开发的协助,最好由全栈工程师独自快速交付。
-
团队文化
一切以人为主,需要建立自由开放的环境。高度信任,增强自我驱动。微服务架构要求小团队具有自主决策的权力,避免无论大事小事都要拿到会议上讨论,造成决策瓶颈。
Cloud Native成熟度模型
Cloud Native的原则
-
为失败设计原则
接受出问题是必然的这个现实,架构中能够容忍故障的发生,最小化故障的影响范围。
-
不变性原则
每个服务或组件在安装、部署完成后将不会发生更改,如果更改在丢弃老的部署新的。
-
去中心化原则
不会因为一个节点的故障导致整个系统不可用,研发流程上做到关注点分离。
-
标准化原则
一旦系统规模变大,做到标准化是无法避免的。所谓独立自主是在一定的标准下实现。
-
速度优先原则
当速度和效率发生冲突时,速度优先。
-
简化设计原则
如果你发现设计满足了所有的要求,说明你一定过度设计了。
-
自动化驱动原则
只有真正拥抱自动化才能做到持续发布,才能做到更好的用户体验。
-
演进式设计原则
架构是持续演进的,不要一蹴而就。
可用性设计
可用性和可靠性的关系
- 可用性(Availability)是关于系统可以被使用的时间的描述,以丢失的时间为驱动(Be Driven by Lost Time)
- 可靠性(Reliability)是关于系统无失效时间间隔的描述,以发生的失效个数为驱动(Be Driven by Number of Failure)
计算公式
- Availability = Uptime / ( Uptime + Downtime )
-
Reliability = MTBF / (MTBF + MTTR)
MTFB: Mean Time Between Failure 平均无故障工作时间,指上一次故障恢复后开始正常运行到这次故障的时间平均值。
MTTR: Mean Time To Repair 平均故障恢复时间,指从初心故障到完全恢复的这段时间。
可用性的衡量标准
可用性通常以N个9的方式来量化。
可用性等级 | 可用性百分比 | 年度停机时间 | 可能会用到的技术 |
---|---|---|---|
基本可用 | 99% | 87.6小时 | 简单的负载均衡 |
较高可用 | 99.9% | 8.8小时 | 灰度发布、自动化发布、自动化测试、快速回滚 |
高级可用 | 99.99% | 53分钟 | 微服务、中间件自动扩展、容错、监控、弹性伸缩 |
极高可用 | 99.999% | 5分钟 | 异地多活、智能运维 |
什么降低了可用性
- 发布
- 故障
- 压力
- 外部强依赖
大型网站典型故障案例
- 写日志过多
- 高并发访问数据库
- 缓存故障
- 应用启动不同步
- 大文件读写独占磁盘
- 滥用生产环境
- 不规范的流程
- 不好的编程习惯
发布方案
- 影子测试:在生产环境通过流量复制、回放和比对的测试方法。
- 负载均衡日志回放
- TCPCopy
ngx_http_mirror_module、tcpcopy、GoReplay 原名gor、滴滴 rdebug
- A/B Testing: 业务场景并行
-
蓝绿部署:系统群并行
在生产环境额外冗余一份相同的环境。测试通过后,可用把负载均衡/反向代理/路由从蓝色环境指向绿色环境。需要回退直接切整体环境。
-
灰度发布/金丝雀发布:部署实例新旧版本并行
在原有版本可用的情况下,同时部署一个新的版本作为“金丝雀”,测试新版本的性能和表现,以保证在整体系统稳定的情况下,尽早发现问题并解决问题。
容错设计
- 消除单点
- 特性开关
- 服务分级
- 降级设计
- 超时重试
- 隔离策略
- 熔断器
降级设计
- 关闭功能
- 请求短路
- 简化流程
- 延迟执行
超时重试技术考虑点
- 超时时间
- 重试次数
- 间隔时间
- 间隔时间衰减度
超时重试技术方案
- 简单重试模式:try-catch-redo
- 策略重试模式:try-catch-redo-retry strategy
- 基于spring-retry:
- 基于Guava-retrying
服务隔离策略
- 线程池隔离
- 进程隔离
- 集群隔离
- 用户隔离
- 租户隔离
限流算法
- 固定窗口算法 (fixed window)
- 漏桶算法(Leaky Bucket)
- 令牌桶算法(token bucket)
漏桶算法和令牌桶算法的对比
漏桶算法 | 令牌桶算法 |
---|---|
不依赖令牌,不保存令牌 | 依赖令牌 |
如果桶满了,则丢弃数据包 | 如果桶满了,则丢弃令牌,不丢弃数据包 |
不允许突发,恒定速率 | 允许突发 |
限流技术方案
- Guava限流
- Nginx限流
- waf限流
性能设计
常见的性能问题
- 内存泄漏:内存耗尽
- 过载:突发流量,大量超时重试
- 网络瓶颈
- 阻塞:无尽的等待
- 锁:通过限制
- IO繁忙:大量的读写
- CPU繁忙
- 长请求拥塞:连接耗尽
性能目标
- 响应时间 latency
- 吞吐量 throughput: QPS
- 负载敏感度
- 可伸缩性
性能目标案例
- 响应时间:99%<1s
- 吞吐量大于10万TPS
- 系统数据量:10亿>订单表>1亿
- 数据增长速度:1亿/年
- 资源限制:服务器、配置、网络
如何定位瓶颈
- 压力测试
- 日志分析
- 监控工具
性能优化方向
- 服务通讯优化
- 消息中间件
- 缓存
- 数据库优化
服务通讯优化
- 同步转异步
- 阻塞转非阻塞
- 序列化
可扩展性设计
AKF扩展立方体
描述 | 场景 | 优势 | 挑战 | |
---|---|---|---|---|
X轴 | 通常称为水平扩展,通过复制实例,前端对流量进行负载均衡,从而分摊整体压力 | 产品初期 | 架构简单,只需要负载均衡 | 有状态的服务不容易扩展 |
Y轴 | 根据服务或者资源扩展,即从单体服务演进到微服务架构 | 业务逻辑复杂,代码规模大 | 故障隔离性好,容易实现业务复杂性分解 | 对工具环境依赖高、运维复杂、一致性实现成本高 |
Z轴 | 根据查询或者计算结果进行拆分。即分片 | 大型分布式系统 | 突破单张表的数据规模 | 架构复杂、数据迁移负载 |
微服务的缺点
- 增加了服务调用的开销
- 分布式系事务
- 调试与服务治理
如何扩
展数据库
- X轴扩展:主从复制集群,Master-Slave读写分离。
- Y轴扩展:分库、垂直分表
- X轴扩展:分片(sharding)
- 区间法(Range-Based):一个月一张表
- 轮流法(Round-Robin) :n = K mod N
- 一致性哈希(Consistent Hash)
一致性设计
事务之间的关系可以通过happen-before表达为如下四种:
- 读写
- 写读
- 读读
- 写写
ANSI SQL92标准定义的四种事务隔离级别如下:
- 未提交读(Read uncommitted)
- 提交读(Read committed)
- 可重复读(Repeatable reads)
- 可串行化(Serializable)
Mysql默认事务隔离级别:可重复读
隔离级别 | 发生脏读 | 不可重复读 | 发生幻读 | 加锁读 |
---|---|---|---|---|
未提交读 | ✓ | X | ✓ | X |
提交读 | X | ✓ | ✓ | X |
可重复读 | X | X | ✓ | X |
可串行化 | X | X | X | ✓ |
分布式事务理论
- Quorum机制
- 租约机制 Lease
- 状态机 Replilcated state machine
状态机故障时节点切换算法
- Paxos算法
- Raft算法
Raft算法
Raft算法将Server分为三种类型:Leader、Follower和Candidate。
- Leader处理所有的查询和事务,并向Follower同步事务。
- Follower会将所有的RPC查询和事务转发给Leader处理,它仅从Leader接受事务的同步。数据的一致性以Leader中的数据为准实现。
Raft把一致性问题,分解成三个比较独立的子问题,并给出每个子问题的解决方法:
- 选举:描述Raft是如何选择一个leader的,这个部分很受容易理解了。
- 日志复制:描述Raft的leader是如何把日志复制到集群的各个节点上的。
- 安全性:描述Raft是如何保证“State Machine Safety Property”。
分布式系统的一致性分类
以数据为中心的一致性模型
- 严格一致性 strict consistency
- 顺序一致性 sequential consistency
- 因果一致性 causal consistency
- FIFO一致性
以用户为中心的一致性模型
- 单调读一致性 Monotonic-read consistency
- 单调写一致性 mono-write consistency
- 写后读一致性 read-your-writes consistency
- 读后写一致性 write-follow-reads consistency
业界常用的一致性模型
- 弱一致性
- 最终一致性 Eventual consistency
- 强一致性 strong consistency
如何实现强一致性
- 两阶段提交 2PC
- 三阶段提交 3PC
如何实现最终一致性
- 重试机制
- 本地记录日志
- 可靠事件模式
- Saga事务模型
- TCC事务模型
分布式锁
- 基于DBMS: 乐观锁CAS,悲观锁 select for update
- 基于Zookeeper
- 基于Redis: Set if not exists
如何保证幂等性
- 幂等令牌 Idempotency Key
- 写前检查
多版本并发控制(MVCC)