一、什么是分布式系统?
通过网络交互,协调多个服务单元共同完成数据的存储、计算等服务的系统
二、分布式系统解决的问题
解决问题:可扩展性、容错、高可用、灾备
三、分布式系统重要概念
复制,分区,事务,数据一致性
四、复制
1. 复制概念
在不同机器上保存数据的副本,目的可能有保持用户与数据在地理位置靠近,部分节点故障系统可以继续运行提高可用性,扩展可用处理请求的机器提高可扩展性
2. 复制算法分类
有主(单主、多主)、无主
有主:同步异步复制,同步容易造成系统不可用,异步复制容易造成主从不一致,处理节点宕机,从库失效,追赶恢复,主库失效,故障切换,主库切换可能有数据不一致,脑裂的问题
3. 复制日志
基于语句,基于行,WAL
4. 复制延迟
读己之写,单调读,一致性前缀读
5. 多主复制
- 多个数据中心(性能更好,容忍部分数据中心停机,容忍网络问题)
- 处理写冲突(同步异步检测,避免冲突,收敛至一致的状态,自定义冲突解决逻辑(写时、读时))
- 多主拓扑复制:环形、星型、all-to-all
6. 无主复制
- 故障恢复数据:读修复(w+r>nw + r> nw+r>n一定可以读取最新值)、反熵过程(后台运行数据检查和复制进程,将节点缺少的数据从其它节点复制过来)。
- 检测并发写入冲突:最后写入胜利(丢弃并发写入)、合并同时写入的值、版本向量
五、分区
1. 分区概念
- 根据不同策略将原本大数据集拆分成小的数据集
- 偏斜(skew),某些分区具有更多的数据
- 热点(hot spot),某些分区承担更高的负载
2.分区与复制
分区与复制并不冲突,一个节点既可以作为某个分区的leader也可以作为其它分区的follower
3.键值数据分区
- 根据键范围分区
- 根据键的散列分区(一致性哈希 - consistent hashing、复合主键、组合索引),失去范围分区的好处,当查询指定范围的数据时需要将查询发到所有分区上
- 负载倾斜和消除热点,需要依靠业务来设置策略
4.分片与次级索引
- 基于文档二级索引进行分区(local index),查询时需要分散再聚集,容易导致尾部延迟放大(MongoDB、Elasticsearch、SolrCloud、VoltDB)
- 基于关键词(Term)的二级索引进行分区(global index),关键词分区的全局索引优于文档分区索引的地方点是它可以使读取更有效率:不需要分散/收集所有分区,客户端只需要向包含关键词的分区发出请求。全局索引的缺点在于写入速度较慢且较为复杂,因为写入单个文档现在可能会影响索引的多个分区(文档中的每个关键词可能位于不同的分区或者不同的节点上) 。实践中索引的更新通常是异步的。
5.分区再平衡
平衡策略
- 反面教材(hash mod N),重新分区代价过于大。
- 固定数量的分区,对于节点的增减很容易重新分配分区,Elasticsearch采用。
- 动态分区,不仅适用于数据的范围分区,而且也适用于散列分区,从版本2.4开始,MongoDB同时支持范围和哈希分区,并且都是进行动态分割分区。
- 按节点比例分区,每个节点具有固定数量的分区。在这种情况下,每个分区的大小与数据集大小成比例地增长,而节点数量保持不变,但是当增加节点数时,分区将再次变小。由于较大的数据量通常需要较大数量的节点进行存储,因此这种方法也使每个分区的大小较为稳定
6.请求路由
路由策略
- 客户端知道所有分区节点,轮训的方式查询
- 通过路由层代理
- 客户端直接知道所请求数据直接请求目标节点
协调服务
- 一般的分布式系统都有一个独立的协调服务保存集群的元信息
- 常见的协调服务有zookeeper、etcd、consul等
执行并行查询
六、事务
1. 概念
- 将多个读写操作看作一个逻辑单元,整个操作的结果要么成功,要么失败或回滚,不存在部分失败的情况,好处是解决上层开发人员的业务处理负担,坏处是可能会影响系统性能。
- ACID含义
- 原子性(Atomicity):能在错误发生时丢弃所有写入的变更。
- 一致性(Consistency):对数据的一组特定约束必须始终成立,一致性的含义太复杂这里不做过多解释,建议详细看单独介绍一致性的文章。
- 隔离性(Isolation):事务之间相互隔离。
- 持久性(Durability):一旦完成事务,即使系统崩溃也不会丢失数据。
- 单对象操作:在单对象上易于实现原子性和隔离性(CAS,比较赋值),一般成为轻量级事务。
- 多对象操作:多对象事务的更新,特别是在分布式系统中实现尤其复杂因为涉及跨分区的协调,有的分布式系统为了系统性能放弃了事务,这也是分布式系统实现事务的最大难点之一。
- 错误处理和终止:事务的一个特性就是发生错误可以安全重试,但是有时重试是有副作用的,这些副作用需要应用程序来消除。
2.弱隔离级别
- 读已提交
- 从数据库读取数据时只能看到已经提交的数据(防止脏读)
- 写入数据库时只会覆盖已经写入的数据(防止脏写,通过行锁解决,计数器增量不属于脏写,因为是发生在前一个事务已提交以后)
- 快照隔离
- MVCC实现快照隔离,当读取操作时读取到删除的对象(update也是删除,update=insert+delete),则只能读取到当前事务id之前的对象值
- 防止丢失更新
- 原子写
- 显示锁定
- 自动检测丢失的更新
- 比较并设置(CAS)
- 冲突解决和复制
- 写偏差(如果两个事务读取相同的对象,然后更新其中一些对象(不同的事务可能更新不同的对象),则可能发生写入偏差)
- 写偏差不是幻读,幻读可能导致写偏差,一个事务中的写入改变另一个事务的搜索查询的结果,被称为幻读
- 即使在快照隔离也会发生
- 单个记录锁不能解决问题,将满足条件的记录都锁住才可以
- 或者使用数据库唯一值来强制约束
- 或者另外使用约束变量来控制偏差的问题
3.可序列化
- 三种常见的可序列化实现方式
- 字面意义上地串行顺序执行事务(参见“真的串行执行”)
- 两相锁定(2PL, two-phase locking),几十年来唯一可行的选择。(参见“两相锁定(2PL)”)
- 乐观并发控制技术,例如可序列化的快照隔离(serializable snapshot isolatio)
- 串行执行:在单个线程上按顺序一次只执行一个事务
- 两阶段锁定(2PL):只要没有写入,就允许多个事务同时读取同一个对象。但对象只要有写入(修改或删除),就需要独占访问(exclusive access) 权限,简单来说就是写阻塞读,读阻塞写(快照隔离使得读不阻塞写,写也不阻塞读)
- 谓词锁
- 间隙锁
- 可串行化快照隔离(SSI):一个相当新的算法,避免了先前方法的大部分缺点。它使用乐观的方法,允许事务执行而无需阻塞。当一个事务想要提交时,它会进行检查,如果执行不可序列化,事务就会被中止。
七、分布式系统的问题
1.网络故障
- 当网络的一部分由于网络故障而被切断时,有时称为网络分区(network partition)或网络断裂(netsplit)
2.检查故障
3.超时与无穷的延迟
- 更好的一种做法是,系统不是使用配置的常量超时时间,而是连续测量响应时间及其变化(抖动),并根据观察到的响应时间分布自动调整超时时间。
4.不可靠的时钟
5.处理暂停
八、一致性与共识
1.线性一致性或强一致性
- 基本的想法是让一个系统看起来好像只有一个数据副本,而且所有的操作都是原子性的,读取每个对象的值都是“最新”(最新是指改变生效后)。
- 表象定义:所有请求的时序,它们一定可以排列成有效的操作时序。
- 条件:
(1)原子操作
(2)op发生在inv和rsp之间
(3)总是获取最新的值 - 线性读:在多个副本间,总是读取到最新的值
- 线性写:所有副本的写都按照相同顺序写
2.全序广播
- 消息在集群内以可靠和相同顺序传递给每个节点仅一次
3.提交协议
- 两阶段提交
- 三阶段提交

5万+

被折叠的 条评论
为什么被折叠?



