《深入浅出分布式技术原理》笔记
《深入浅出分布式技术原理》笔记
开篇词 掌握好学习路径,分布式系统原来如此简单
导读:以前因后果为脉络,串起网状知识体系
分布式系统解决了什么问题
- 首先,分布式系统解决了单机性能瓶颈导致的成本问题。——水平扩展
- 然后,解决了用户量和数据量爆炸性地增大导致的成本问题。——水平扩展
- 接着,满足了业务高可用的要求。——解决单点问题,鸡蛋不要都放在一个篮子里
- 最后,分布式系统解决了大规模软件系统的迭代效率和成本的问题。——分而治之,化繁为简
如何思考和处理分布式系统引入的新问题
- 怎么找到服务——服务注册和发现
- 怎么找到实例——路由、负载均衡
- 怎么管理配置——配置中心
- 怎么进行协同——分布式锁
- 怎么确保请求只执行一次——重试+幂等
- 怎么避免雪崩——限流、熔断、降级、快速失败、弹性扩容
- 怎么监控告警和故障恢复——分布式链路追踪
分布式存储如何内部协调
- 首先,理解 ACID、CAP、BASE
- 然后,确定分片策略,常见方案有 Hash、Region 分片
- 接着,确定复制方案,常见方案有:
- 中心化方案:主从复制、一致性协议,比如 Raft 和 Paxos 等
- 去中心化方案: Quorum 和 Vector Clock
- 最后,如何处理分布式事务
- 分布式 ID
- 2PC、3PC 等分布式事务方案
新的挑战:分布式系统是银弹吗?我看未必!
- 故障处理
- 网络不可靠——超时处理
- 时间不可靠——NTP、逻辑时钟
- 共识协同——共识性算法
CAP 理论:分布式场景下我们真的只能三选二吗?
在一个分布式系统中,当发生网络分区时,那么强一致性和可用性只能二选一。
注册发现: AP 系统和 CP 系统哪个更合适?
服务注册的关键:
- 统一的中介存储:调用方在唯一的地方获得被调用服务的所有实例的信息。
- 状态更新与通知:服务实例的信息能够及时更新并且通知到服务调用方。
注册中心的特性要求:
- 可用性要求非常高:因为服务注册发现是整个分布式系统的基石,如果它出现问题,整个分布式系统将不可用。
- 性能要求中等:只要设计得当,整体的性能要求还是可控的,不过需要注意的是性能要求会随分布式系统的实例数量变多而提高。
- 数据容量要求低:因为主要是存储实例的 IP 和 Port 等元数据,单个实例存储的数据量非常小。
- API 友好程度:是否能很好支持服务注册发现场景的“发布/订阅”模式,将被调用服务实例的 IP 和 Port 信息同步给调用方。
注册中心选择 AP 还是 CP:
因为服务发现是整个分布式系统的基石,所以可用性是最关键的设计目标。
负载均衡:从状态的角度重新思考负载均衡
负载均衡策略:
- 轮询
- 随机
- 加权轮询/随机
- 最少连接/请求
- 最少响应时间
- Hash
- 一致性 Hash
- 虚拟一致性 Hash
配置中心:如何确保配置的强一致性呢?
配置中心的关键挑战:
- 统一的配置存储:一个带版本管理的存储系统,按服务的维度,存储和管理整个分布式系统的配置信息,这样可以很方便地对服务的配置信息,进行搜索、查询和修改。
- 配置信息的同步:所有的实例,本地都不存储配置信息,实例能够从配置中心获得服务的配置信息,在配置修改后,能够及时将最新的配置,同步给服务的每一个实例。
配置中心特性要求:
- 可用性要求非常高
- 性能要求中等
- 数据容量要求低
- API 友好程度
分布式锁:所有的分布式锁都是错误的?
重试幂等:让程序 Exactly-once 很难吗?
在分布式系统中,程序不能保证 Exactly-once:响应超时的情况下,请求方无法判断接收方是否处理过这个请求。过程中有可能出现网络丢包问题或服务端故障。
幂等设计要点:
- 使用唯一性 ID 来标记请求,通过 ID 进行去重
- 保存状态快照+回滚模式——代价太高,一般不会用
雪崩(一):熔断,让故障自适应地恢复
在服务调用链中,服务调用时由于某一个服务故障,导致级联服务故障,并逐步扩散引起大范围服务故障的现象,称为雪崩效应。
在熔断机制的模式下,服务调用方需要为每一个调用对象,可以是服务、实例和接口,维护一个状态机,在这个状态机中有三种状态。
首先,是闭合状态( Closed )。在这种状态下,我们需要一个计数器来记录调用失败的次数和总的请求次数,如果在一个时间窗口内,请求的特定错误码的比例达到预设的阈值,就切换到断开状态。
其次,是断开状态( Open )。在该状态下,发起请求时会立即返回错误,也可以返回一个降级的结果,我们会在后面的课程“降级”中再详细讨论。在断开状态下,会启动一个超时计时器,当计时器超时后,状态切换到半打开状态。
最后,是半打开状态( Half-Open )。在该状态下,允许应用程序将一定数量的请求发往被调用服务,如果这些调用正常,那么就可以认为被调用服务已经恢复正常,此时熔断器切换到闭合状态,同时需要重置计数。如果这部分仍有调用失败的情况,我们就认为被调用方仍然没有恢复,熔断器会切换到断开状态,然后重置计数器。所以半打开状态能够有效防止正在恢复中的服务,被突然出现的大量请求再次打垮的情况。
雪崩(二):限流,抛弃超过设计容量的请求
常见限流算法
- 固定窗口限流
- 滑动窗口限流
- 漏桶限流
- 令牌桶限流
雪崩(三):降级,无奈的丢车保帅之举
降级机制能从全局角度对资源进行调配,通过牺牲非核心服务来保障核心服务的稳定性。
如何实现降级:
- 手动降级
- 自动降级:当系统的某些指标或接口调用出现错误时,直接启动降级逻辑
雪崩(四):扩容,没有用钱解决不了的问题
如何实现动态扩容
通过可观测性系统监控核心指标
过载判断 - 一旦核心指标达到阈值,触发扩容
自动扩容 - 利用 K8S 进行容器化扩容
可观测性(一):如何监控一个复杂的分布式系统?
搭建一个可观测性平台,主要通过对日志( Logs )、链路( Traces )与指标( Metrics )这三类数据进行采集、计算和展示。
- 日志信息( Logs ) - 代表:ELK
- 追踪链路( Traces ) - 代表:Jaeger、Zipkin、SkyWalking
- 指标信息( Metrics ) - 代表:Prometheus + Grafana
四个黄金指标:延迟、流量、错误和饱和度
可观测性(二):如何设计一个高效的告警系统?
告警系统的评价指标:
- 信噪比:指有效告警通知数和无效告警通知数的比例,信噪比越高越好,是用来评估“多报”问题的。
- 覆盖率:指被告警系统通知的故障占全部线上故障的比例,同样,覆盖率也是越高越好,是用来评估“漏报”问题的。
- 转交率:指被转交的告警通知数占全部告警通知数的比例,转交率越低越好,是用来评估“对比人”问题的。
故障(一):预案管理竟然能让被动故障自动恢复?
故障评价标准:
- 平均出现故障的频率:指平均多少时间出现一次故障,这个频率越低越好。
- 平均故障恢复的时间:指出现故障后,系统在多长时间恢复到正常状态,这个时间越短越好,并且,我认为这是一个更关键的指标。
被动故障的来源:
DNS 解析问题:用户本地网络的 DNS 服务不能将我们的域名正确解析到 IP 地址。
网络连通性问题:用户已经解析到正确的 IP 地址,但是从用户网络到我们服务器的 IP 地址之间的网络慢或者不通。
系统内部的硬件设施故障:比如机器突然宕机,内部网线中断等。
系统依赖的各种第三方服务:比如 CDN 服务、短信网关、语音识别等第三方服务故障。
故障(二):变更管理,解决主动故障的高效思维方式
主动故障的来源:
- 程序发布变更:指服务器、App 和 Web 等发布了新版本的程序和服务。
- 实例数目变更:指服务器新增实例和下线实例。
- 配置发布变更:指发布了新版本的配置。
- 运营策略变更:指举办了导致用户流量增长的运营活动,比如购买了新的推广广告等。
分片(一):如何选择最适合的水平分片方式?
略
分片(二):垂直分片和混合分片的 trade-off
略
复制(一):主从复制从副本的数据可以读吗?
复制的三种方案:
- 主从复制:整个系统中只有一个主副本,其他的都为从副本。
- 多主复制:系统中存在多个主副本,客户端将写请求发送给其中的一个主副本,该主副本负责将数据变更发送到其他所有的主副本。
- 无主复制:系统中不存在主副本,每一个副本都能接受客户端的写请求,接受写请求的副本不会将数据变更同步到其他的副本。
Mysql、PostgreSql、Redis、MongoDB、Kafka 都支持主从复制。
主从复制的关键在于采用同步复制还是异步复制。
复制(二):多主复制的多主副本同时修改了怎么办?
为什么需要多主复制——为了提供更好的容灾能力,需要多机房、多数据中心来进行冗余,这就需要多主复制或无主复制。
如何实现多主复制
- 首先,每一个主从复制单元内部是一个常规的主从复制模式,这里的主副本、从副本之间的复制可以是同步的,也可以是异步的。
- 其次,多个主从复制单元之间,每一个主副本都会将自己的修改复制到其他的主副本,主副本之间的复制可以是同步的,也可以是异步的。
问题:
同步会导致整个模式退化为主从复制的形式。
异步模式的多主复制会存在数据一致性的问题。
如何解决冲突
写入冲突是由于多个主副本同时接受写入,并且主副本之间异步复制导致的。
注:文中并未给出完整的解决方案。
复制(三):最早的数据复制方式竟然是无主复制?
无主复制由于写入不依赖主节点,所以在主节点故障时,不会出现不可用的情况。但是,也是由于写入不依赖主节点,可能导致副本之间的写入顺序不相同,会影响数据的一致性。
在实现无主复制时,有两个关键问题:数据读写和数据修复。数据读写是通过仲裁条件 w + r > n 来保证的,如果满足 w + r > n ,那么读副本和写副本之间就一定有交集,即一定能读取到最新的写入。而数据修复是通过读修复和反熵过程实现的,这两个方法在数据的持久性和一致性方面存在一定的问题,如果对数据有强一致性的要求,就要谨慎采用无主复制。
然后,我们了解了 Sloppy Quorum ,它相比于传统的 Quorum ,为了系统的可用性而牺牲了数据的一致性,这里我们可以进一步得出,无主复制是一个可用性优先的复制模型。
事务(一):一致性,事务的集大成者
事务是一个或多个操作的组合操作,它需要保证这组操作要么都执行,要么都不执行。
事务(二):原子性,对应用层提供的完美抽象
简单介绍了 2PC
事务(三):隔离性,正确与性能之间权衡的艺术
简单介绍了事务隔离级别
事务(四):持久性,吃一碗粉就付一碗粉的钱
简单介绍了 Redo Log + WAL
一致性与共识(一):数据一致性都有哪些级别?
按照一致性强度由高到低,有以下模型:
线性一致性——现在可以实现的一致性级别最强的是线性一致性,它是指所有进程看到的事件历史一致有序,并符合时间先后顺序, 单个进程遵守 program order,并且有 total order。
顺序一致性——它是指所有进程看到的事件历史一致有序,但不需要符合时间先后顺序, 单个进程遵守 program order,也有 total order。
因果一致性——它是指所有进程看到的因果事件历史一致有序,单个进程遵守 program order,不对没有因果关系的并发排序。
最终一致性——它是指所有进程互相看到的写无序,但最终一致。不对跨进程的消息排序。
一致性与共识(二):它们是鸡生蛋还是蛋生鸡?
略
一致性与共识(三):共识与事务之间道不明的关系
略
分布式计算技术的发展史:从单进程服务到 Service Mesh
略
分布式存储技术的发展史:从 ACID 到 NewSQL
略
春节加餐 技术债如房贷,是否借贷怎样取舍?
略
春节加餐 深入聊一聊计算机系统的时间
略
春节加餐 系统性思维,高效学习和工作的利器
略
结束语 在分布式技术的大潮流中自由冲浪吧!
略