分布式系统第五讲 分布式存储
第五讲 分布式存储
主要内容
- 分布式存储系统要达成的目标
- 两种基本手段:复制、分区 切片
- 实现 复制的基本方法与权衡
- 多副本分布式存储系统的一致性问题
- 实现切片的基本方法与权衡
- 案例 1 :分布式文件系统 HDFS
- 案例 2 :分布式 NoSQL 数据库 HBase
5.1 分布式存储要达成的目标
- 提高数据存储容量 系统的总存储容量是多个组成节点本地存储容量的聚合,系统总存储容量能够随着组成节点数的增加而增大。(水平可扩展)
- 提高数据吞吐量 系统的数据 读写吞吐量能够随着组成节点数的增加而增大。(水平可扩展)
- 提高可靠性 可用性 :部分存储节点发生故障时数据不丢失 ;部分存储 节点 失效 时,用户仍然可以读写数据。(容错性)
- 降低数据访问延时 使用户可以从地理位置上最接近的节点读取数据。(例子: CDN 内容分发网络)
- 提高 分布式数据处理系统的运行效率 。
5.2-1 基本手段
1. 复制
(1) 说明
- 基本 思想: 在多个不同 的节点上 保存相同数据的多个 副本 (replica )。
- 用途:
- 复制提供了 冗余,如果一些 节点不可用,剩余的节点仍然可以提供数据 服务。
- 多 个节点上存储副本也可以提高数据吞吐率、改善访问性
能。
- 带来的问题:
- 硬件成本提高。
- 在数据变更时保障多数据副本之间的之间的一致性是个复杂问题。(需要根据具体应用场景进行权衡)
(2) 基于领导者的复制(主从复制)
- 基于领导者的复制 (leader based replication) replication):也称为 主动被动 active/passive) 复制 、 主 从 (master/slave 复制 ,或主 备(primary/backup 复制 。
- 基本思想
- 副本之一被指定为 领导者 主库 其他 副本被指定为 追随者(从库)
- 客户端要向 数据存储系统写入数据时 ,它必须将请求发送给领导者领导者将新数据 写入 本地 存储,同时也 会将数据变更发送给所有的 追随者。
- 当客户想要 从 数据 存储系统读取 数据时,它可以向 领导者 或 追随者 查询 。
- 适合于 读多 写少 的应用场景。
(3) 复制方法分类
① 单主/多主/混合
单主复制:
- 一个领导者多个追随者。
- 优点:实现相对简单。大多数应用场景都是读多写少。
- 缺点:主库即是性能瓶颈,又是 单点故障节点 (Single point of failure
- 为提高容错性,自动将某个从库切换为主库时会面临 脑裂问题。
多主复制:
- 系统中有多个主库接受写入操作 。 每个主库都将 该数据更改转发给所有其他节点。每个领导者同时扮演其他领导者的 追随者。
- 应用场景:多数据中心之间的复制;协同文档编辑。
- 优点:写入性能高。
- 缺点:写入冲突问题、多副本一致性问题解决方案太复杂。
无主复制:
- 没有主库从库的 概念。
- 客户 端直接将 写入请求发送 到 到 各个 副本;或者客户端将写入发送给某个节点,由该节点充当代理节点向其他节点转发写入请求。
② 同步/异步复制
同步复制:
-
领导者写入自己的存储器,并且接收到所有跟随者已经成功更新本地存储的应答后再向用户返回成功写入应答。
-
优点:更容易实现副本之间的一致性;
-
缺点:写入速度慢; 一 个节点失效会使整体写入功能失败
(如果主库和从库的性能有差距,从库可能会拖累主库。)
(下面有图)
异步复制:
- 领导者自己 写入成功后 立即向向用户返回 成功应答,不等待其他跟随者的应答消息。
- 优点:写入速度快;容错性好;
- 缺点:保持多副本一致性复杂;(可能出现节点失效,网络断裂,数据丢包,传输延迟)
(下面有图)
混合复制:
- 与部分跟随者节点之间采用同步复制,另外的跟随者节点之间 采用 异步 复制。
同步复制时序图
- 领导者给多个追随者进行数据复制的过程是可以并行的
- 但是必须所有追随者都应答之后主节点才能给用户应答
- 当用户收到应答的时候,表明所有的数据都被安全的保存到副本中了
- 当某一个从节点变慢或者失效的话,会影响整体的效率
- 但是也会使用
- mysql可以设置,在管理员配置页面中,将一个mysql配置为主服务器,另一个配置为备份服务器,将备份的ip地址设置成主的ip,设置模式为同步
- 然后用网线一连(网络连接即可),所有客户端对主服务器的CRUD都会更改备份服务器
- 商业级别的数据库都有这样的设置的
异步复制时序图
如果出现丢包或者失效等问题,很难保证一致性
短期的不一致可以接受,但是长期的不一致是不能接受的
所以现在很多只要追求最终一致性
(4) 主从复制时数据更新命令的级别
实现主从复制时,主库需要将每个数据库更新命令广播给所有从库。那么采用哪个级别(高 or 低)的数据库更新 命令更合适?
- 高级别数据更新命令(如 SQL 命令):
- 优点:实现简单;
- 缺点:从库需要重新解释SQL 浪费计算资源; SQL 命令不是原子操作,很容易使主、从库不一致。
- 低级别命令(如 CPU 机器指令):
- 效率太低
- 中间级别数据更新命令(如数据库更新日志中的数据更新指令):
- 效率和实现复杂度之间的更优平衡点
- 更容易实现原子操作(下面有说明)。
(5) 数据库更新日志
更新日志:
数据副本节点一般 分两步处理数据写入 或复制 请求:
- 先将更新操作信息 追加 到 更新日志 ;
- 再根据操作参数更新 本地存储系统 (或称为 本地状态机 )。
在传统数据库中的用途:
- 更新 本地 存储系统 失败后,还可以根据日志重试失败的更新操作。(例如计算机本身 Fail Stop Recover 了)
- 更新失败后也 便于 本地存储系统 恢复到之前的一致性状态
- 保存了整个更新历史,便于出现错误时进行问题回溯。
- 某些设计中,写入请求成功追加到日志就可以应答用户。这样只在日志文件尾部追加,提高了写入速度。
在分布式存储中的新用途:
- 便于落后的追随者追赶上领导者的最新状态。
- 便于实现分布式事务
日志的特点:
- 持久性:日志是硬盘上的文件,写入后就丢不了了
- 只在尾部追加
为什么主库收到请求之后,不直接更改,而是写到数据库中呢?
性能角度:往日志中写数据是在尾部追加,是连续写,不论是机械硬盘还是固态硬盘,连续写的速度是随机写的3-10倍
(因为写的过程中磁头会动,连续写不用动的很大)
原子性角度:
- 在数据库中查找时分别有两部分,一部分是 多分B+树,一部分是保存在硬盘中的数据
- 树的叶子节点保存着数据记录在磁盘的哪里
- 同理,在写数据的时候要往这两部分写,既要更改B+树,又要在磁盘中写入,二者要么都完成,要么都不完成,这就需要保证原子性。而且在往树中写的过程中还可能涉及到节点分裂的问题。
因此接受到请求的时候,先写到日志中,然后单独在后台抽出一个线程来,根据日志指令来执行
如果后台失效了,日志中仍然记录着原始的指令
- 不但主节点有日志,从节点有这样的日志也有同样的作用
- 主库只要将自己的日志传给从库即可
- 将数据库的的复制问题转换为日志问题
基于数据库更新日志的同步
- 如果能将 Leader 的更新日志复制给各个 Follower ,那么就可
以保证各个副本的本地存储系统是一致的(或最终一致的) - 复制状态机( Replicated state machines )的思想
复制状态机:
- 计算机的程序一定可以抽象成有向状态机,就是S0,S1,S2之间的转换
- 如果想要实现“双机热备”:主服务器和备份服务器装着完全相同的服务器,表示初始状态一致,但是如何保证后续状态一致?
- 一个程序的当前状态决定于:初始状态 + 指令序列
- 因此保存了日志就相当于保证了指令序列的一致
复制状态机
这是状态机的一种
复制状态机(Replicated state machines)
- 目标:使不同的计算节点能够从完全相同的初始状态运行完全相同的确定性指令序列,那么在任意时刻,这些节点的当前状态也是相同的。
- 用途:当一个计算节点失效以后,可以立即切换成另一个复制节点继续为用户(客户端)服务(多机热备份)
- 复制状态机的实现方法:
- 每个节点都维护一个日志(指令序列日志),日志用于存储状态机(可以看成是CPU)将要依次执行的指令
- 利用分布式共识协议使不同节点的指令序列日志保持一致
- 实现复制状态机的协议:
- Raft协议(本质是一个容错性分布式共识协议)参考官网: https://raft.github.io/
- MultiPaxos协议
就是让AB各自跑一个线程,但是将A 的指令复制给B,那么AB最终的状态就会一致了
所以实现数据库复制的问题就是实现日志同步的问题
(6) 容错性分布式日志复制
根据前面,我们选择
- 单主复制(比较简单,多主复制还要考虑指令的顺序问题)
- 混合复制(后面的Raft协议就是使用的混合复制)
- 日志复制
那么就要结局异步复制所带来的问题
① 容错要容的问题
这里要容的错包括:
- 节点失效问题(只考虑主节点,因为从节点挂了就挂了,不影响)
- 网络传输延时抖动(网络(暂时)断裂也算这种,算是大型的延时问题,网络永久性断裂问题怎么也解决不了)
首先是节点失效问题:
从库失效是可以容忍的,但是主库的失效比较麻烦
- 当主库有数据的时候发数据包,没有数据的时候发心跳包,当很长时间没有发心跳包的时候,说明主库已经失效了
- 这时候应该选取一个新的leader,随之而来的问题是,新的leader的日志可能很落后,可能会将其他节点的指令给冲掉
- 每个从节点接受到指令之后,要做两件事,先写到日志,然后更新本地状态机
- 但是有一个问题,就是我更新了状态机,会不会其他节点不会更新它们的状态机
- 比如主1给从1发了o1指令,从1执行了o1之后主1就挂了,从2都接受不到指令,从1和从2的状态就不一致了
② Raft协议
Raft本质上是解决分布式复制状态机的问题,不仅仅是数据库同步的问题。Raft解决的就是日志复制的问题
说明
- Leader接收来自于不同客户端的执行指令请求,并将它们按接收顺序存入自己的日志;
- Leader利用Raft协议将新增日志项复制给所有的Follower
- 针对日志中每条指令,每个参与者在确信该指令已经被安全复制之后,将该指令应用到自己的本地状态机
关键就在于如何确信被安全复制
过程
- 当Leader收到一个客户端的请求操作,Leader将该请求追加到自己的本地日志中,然后再努力用Raft协议将新追加的操作请求广播给其他节点。
- Followers将收到的操作请求写入自己的本地日志,然后给Leader返回一个针对该日志项的ACK。
- Leader针对followers回答的ACKs进行计数
- 关于某个操作请求(日志项),如果Leader收到了超过半数的Followers的ACK,则Leader将该日志项标记为“已提交”(commited),并将该日志项中记录的操作请求应用的自己的本地状态机。(即在状态机中执行该操作)。
- Leader将日志项已提交的信息广播给其它从节点
- 从节点接受到commited已提交信息之后,执行这个信息,并向主节点返回ACK信息
分析/思考?
Raft要解决两个问题:
- 一个是节点失效问题
- 一个是网络(暂时)断裂、延迟抖动问题
上述步骤是怎么解决这两个问题的呢?而且要思考下面两个问题
- Raft协议是如何在容忍部分节点失效(小于半数个节点失效)的情况下保证安全性的?
- 为什么Leader收到半数以上Follower已经把某个日志项存储到本地日志的ACK消息之后,就可以通知大家可以安全地应用(commit)该日志项中存储地指令了?
使用到下述思想:
-
萧规曹随思想:新的leader会执行原来leader的使命,就是原来的leader做什么,新的leader也做什么
-
新Leader选举时日志PK(如何选取新的leader):采用拉票制
-
当大家发现主节点挂了之后,每个从节点让自己随机睡眠一段时间,睡醒了之后开始拉票
-
比如从4先醒,向从1从2发出request vote请求,从1从2如果同意,但此时就不能拉票了,每个从节点只有一个选票
(随机睡眠是保证一个时刻只有一个节点拉票,而不是说只有最先醒来的才能拉票。当有节点拉票并且一个节点投票了,那么这个节点就不要再拉票了,没投票的可以再拉票)
-
但是不是要选票就给,只有当从4的选票比从1从2的新或者至少等同,从1从2才会给从4选票,也就是进行日志PK
-
当拉票的节点能够得到超过半数的选票(当然包括自己),就能够成为主节点
-
为什么leader只要收到超过半数的ACK,就会commit并执行呢?
如下
- 之前老leader执行的指令,必定已经得到了半数以上的节点的ACK,也就是半数以上得到了
- 而成为新主节点的节点,必然也经过了半数以上的投票
- 两个半数以上,那么必定是有交集的
- 所以新的leader必定会在 左边的那个集合中产生(假设在右边的空集合中产生,那么不可能有半数以上的给他投票的)
- 总之最新更新的日志已经传递给新主了,新主继续执行并且发commit
这里还有问题
- 伏地魔思想:一直把灵魂传递下去
总结
- 主节点挂了,选取新节点
- 新主要能完成老主未完成的意愿
-
功能:容错性分布式日志复制协议(配合分布式复制状态机)
-
安全性保证:
-
官方:一旦某一个节点将某一日志条目应用于自己的状态机,则其他节点不可能在此日志索引上应用其他不同的日志条目
-
更简单一些的解释:一旦某一个节点将日志中的某条指令应用于自己的状态机之后,它确信其它节点(如果还活着)迟早会将同样的指令(在日志中相同的位置)应用到它们自己的状态机
-
Raft协议容错性:最多可容忍(n-1)/2(取下整),即小于半数个节点出错,n表示组成系统的节点个数;
n一般取奇数(n = 5,容忍2个,n=7,容忍3个)。
-
Raft只能容忍失效停止(或失效-停止-恢复)类节点错误,不能容忍拜占庭类节点错误(拜占庭节点错误会有随机行为,主要来说是搞破坏的节点)。
-
Raft可以容忍网络不可靠:丢包、延迟、断裂、乱序,容忍节点时钟不同步
-
Raft不仅仅能够实现数据库的复制(这只是Raft的用处之一),Raft实现的是分布式日志的复制,这个应用还能实现进程的复制,因为有了初始状态和,日志,就能恢复进程的状态
让多个进程保持一致
-
指令不允许有随机指令,必须是确定的
- PBFT协议就是解决拜占庭问题的协议
- 有的协议不用Raft,而是用Paxos协议
分布式系统的一致性
1. 多副本分布式存储中的一致性问题
- 多个客户端“同时”对分布式存储系统进行读写。
- 分布式节点之间的网络不可靠:丢包、延迟、断裂、乱序
- 部分存储节点会失效
- 节点的局部时钟不同步
2. 一致性的定义
- 多个客户端在读写数据时,分布式存储系统为客户端提供的关于数据外在表现的保证。
- 客户端和多副本分布式存储系统之间一种服务约定。
- 在多副本分布式存储中(指单主),写只能向主节点写,但是读可以从 从节点 读
- 但是会存在给主节点写了,但是还没来得及给从节点同步,此时从从节点读取的数据与写后的数据不符的问题
3. 强一致性和弱一致性
- 强一致性 :(线性一致性 原子一致性)
- 在客户端看来,分布式存储系统的外在表现和单副本存储系统的外在表现完全一致。(类似于多个线程访问同一个寄存器)
- 任意客户端看到的所有针对分布式系统的 操作 读、写等 原子操作 按全局一致的顺序排列(线性化),并且该排序满足多个操作在时间维度上的实际发生先后顺序。
- 顺序一致性
- 任意客户端看到的所有针对分布式系统的 操作 读、写等原子操作 按全局一致的顺序排列(线性化 ),同一个客户端发出的多个操作的顺序与该全局一致排序并不矛盾。
- 因果 一致性
- 不同客户端 看到的所有针对分布式系统的操作 读、写等原子操作 排序不一定一致,但该排序不违背操作发生的因果关系。
- 最终一致性
- 在分布式系统停止更新时,最终所有读操作都可以获得最新版本的数据。
保证强一致性的方法:
- 采用同步复制,当所有节点都复制完之后给用户响应,但是代价很高,单一节点可能影响总体的效率
- 读取的时候全部向主节点读取,这样从节点仅仅起备份的作用
但是真正的系统中,不一定非要满足强一致性,比如分布式论坛,如果帖子丢了,刷新可以出现就行了
- 几乎所有的分布式存储系统都支持最终一致性。
- 分布式系统的一致性保证越强,客户端应用程序越容易编写;一致性保证越弱,客户端程序逻辑就越复杂。
- 一致性保证越 强,分布式系统的实现代价就越高,性能就越低。因此可以通过牺牲部分一致性获得更好的性能和容错性。
以下产品就有说明
4. CAP定理
- Consistensy 一致性 ):不同节点上数据 的强 一致性
- Partition Tolerance( 割断容忍性 )):允许部分节点与其它节点断裂
- Availability( 可用性 )):发出的请求在规定时间段内总能返回结果(请求响应延时短,可用性高;否则可用性低)
- CAP 定理:在设计分布式系统时,三者只能取其二,不能三者兼得。
- 所以使用,Redis会出问题
以银行为例
银行的POS机,需要满足一致性(两台机器要时刻一直),又要满足可用性
- 于此同时,如果要满足隔断容忍性,也就是如果网络断裂,那么就无法保证强一致性了
5. BASE定理
BASE定理是一种理念,并不是实际的定理
- BASE 理论 是 对 CAP 中一致性和可用性权衡的结果 ,来源于 对大规模互联网分布式系统实践的总结,核心思想是即使无法做到强一致性,但每个应用都可以根据自身业务 特点降低部分一致性获得可用性。
- 基本可用 Basically Available
- 在出现故障的时候,允许损失部分可用性 ,保证 核心可用。
- 软状态 Soft State
- 允许系统中的数据存在中间状态 ,允许 系统在多个不同节点的数据副本 存在更新延时 。
- 最终一致性 Eventually Consistent
- 不可能 一直 处于软状态 ,在一定期限后应当 保证所有副本保持数据一致性,从而达到数据的最终一致性
5.2-2复制手段
2. 分区、切片
当mysql的数据达到将近100w左右的时候,查询速率会骤降
因此可以分区,就是不要将所有的数据都放在一张表中,比如大一的放在一张表中,大二的放在一张表中,大三的放在一张表中
这就是一种朴素的分区思想
但是这里是一种普遍的技巧
(1) 说明
基本思想: 将一个 大型数据文件 或数据库 拆分 成较小的子集( 称为分区 partition 或切片 shard)再将不同 的 分区指派给 不同的 节点。
用途:
- 提高了吞吐率:访问数据的负载被分散到多个节点上。
- 提高 了可靠性:鸡蛋被放到多个篮子里
- 方便了实现数据的并行处理。
带来的问题:
- 跨区查询(分布式索引问题)
- 合理、动态分区问题(大数据如何拆分)
- 负载均衡问题(各个切片如何合理地分配给不同节点)
- 分布式事务处理
(2) 主键(连续)分区
- 合理数据分区的 目标:将 数据和查询负载 均匀分布 在各个节点上 ,避免 出现 偏斜 skew) 和 热点
(hot 问题。 - 分区方式要兼顾跨区查询问题
根据主键范围进行分区:
- 数据集合中每个元素(块、对象、记录)都可以找到一个主键,根据主键的连续范围进行分区。
- 各个主键范围分区一般都是 非均匀分布 的。
- 不同的主键范围分区分配给不同的物理存储节点。在特定分区进行分裂或合并时会产生数据移动。
- 优点:按主键进行连续查询很方便。
- 缺点:在主键范围非均匀分布时必须建立 全局索引 以记录数据分区和存储节点的对应关系。一般要专门指定一个节点维护全局索引,该节点是中心节点。
① 倾斜问题
均匀分区:
- 10000个记录,分10个节点。就是1-1000,1001-2000这样分,但是出现的问题就是可能出现偏斜,因为实际的数据分区,并不是均匀分布的,可能分布在很小的一段区间,这样就会导致存着这部分区间的节点负担较大
- 找节点ID就是 k MOD N
- 但是如果增加一个节点,也就是N + 1,也是靠 ID = key mod N的话,那么要进行大量的数据迁移,再靠索引分区的话就麻烦了
非均匀分区
- 如果已经知道数据的分布规律的话,可以使用非均匀分区,让节点承担的压力尽量均衡
- 也是连续分区,只是分区不是平均的了
- 额外代价:需要全局索引表、需要指定一个代理节点proxy来维护索引(因为均匀分区很容易得到分区所在的节点)
二者都是一种连续分区的方法
② 热点问题
- 如上,数据本来只有N0 — N3 4个节点保存
- 但是可能某一时间段内访问人数骤增,致使节点压力过大。这就是热点问题
- 此时如果要增加节点的话,那么就涉及数据迁移问题,而连续分区的话数据迁移会很麻烦,特别是均匀分区
(3) 简单哈希分区
hash函数
- 确定性:相同的输入会产生相同的输出;
- “随机性”:输入输出的对应完全是随机的。对于给定的输入字符串,函数输出“随机”落在值域空间的某个点上。两个输入值即便只相差 1 个 bit
,输出值可能相差很远。 - 无碰撞性:假定函数输出 n 比特的整数,任取两个输入,它们的输出值相等的概率为 2-n 。
- 理想的hash函数多用在安全方面,但是计算代价太高
- 分布式计算领域常用计算代价没那么高,但是有类似功能的函数
说明
根据主键的哈希值进行分区:
- 将整个哈希空间均匀分成 k 个区间( k 个 桶 ),每个存储节点负责一个 哈
希区间( 桶 )。 - 计算新插入数据元素主键的哈希值,然后计算该哈希值落入了哪个 桶最后将该数据元素分配给该 桶 所 对应的 存储 节点。
- 在增加或删除物理节点时会产生大量数据移动(为什么?)。
优点:
- 可以在一定程度上避免了偏斜和热点问题。
- 无须全局索引,因而也无须中心节点。
缺点:
- 基于主键进行连续范围查询效率极低。
- 在物理存储节点较少时仍然 会出现偏斜和热点 问题。(可以采用虚拟节点的方法进行缓解)
- 桶的个数改变时会产生大量数据移动。
节点的ID = H(key) mod N,是用hash值模N
同样存在问题:就是在增删节点的时候会有大量数据移动
(4) 一致性哈希分区法
- 一致哈希 是一种特殊的哈希算法。在使用一致哈希算法后 桶数量的 改变平均只需要 对 K/n 个关键字重新映射,其中 K 是关键字的数量 n 是桶的数量 。
- 均衡性 :每个桶中映射的关键字数量保持均衡
- 单调性:当增加新的桶时,部分关键字被放入新桶中,但 不会出现部分 关键字在两个旧桶之间转移的情况
说明
- 找一个普通的理想哈希函数 HASH 。
- 将该 HASH 函数的值域空间首尾相接做成一个 环 。
- 假定每个存储节点(每个节点负责一个 桶 )都有一个唯一标识(例如针对每个节点生成一个随机数作为其标识;或用其 IP 地
址,总之这个不一定是固定的): ID1 ID2 ,……, IDn 。 - 每个节点的唯一标识作为输入计算其 HASH 函数输出,并将其输出值映射到 环 上,会产生 n 个 映射点 。
- 节点 IDi所负责的桶就是环上从映射点 HASH( IDi开始到下一个映射点之间的连续哈希值区间。(假定 按顺时针旋转)
思考问题:
- 增删节点时多少个桶会 受到 影响?
- 当节点较少时每个节点负责的桶的大小不均衡怎么办?(虚拟节点法)
增删节点时分区再平衡
可以看到node5插入之后,一部分节点由node5存储
问题:
- 只有node4的任务被分担了,123的任务都和往常一样
- 这是因为节点比较少,出现了倾斜问题
- 一致哈希 是一种特殊的哈希算法。在使用一致哈希算法后 桶数量的 改变平均只需要 对 K/n 个关键字重新映射,其中 K 是关键字的数量 n 是桶的数量 。
- 均衡性 :每个桶中映射的关键字数量保持均衡
- 单调性:当增加新的桶时,部分关键字被放入新桶中,但 不会出现部分 关键字在两个旧桶之间转移的情况
虚拟节点法
由于上述的平均问题,可以采用虚拟节点法
- 就是为每个节点都套一个马甲,也就是多设几个ID值
- 这样在换上的桶的数量就多了,看起啦就均匀了
- 但是实际上仍然只有那么几个点
- 新插入的节点也穿着几个黄马甲,那么可以给原来的每个节点分担任务了
一致性hash算法 在分布式应用广泛
这个算法的一个好处是,不需要中间代理节点了,知道了key就能自动知道哪个节点负责
- 分布式系统难就难在节点之间需要相互协作
- 一个最高效的工作模式是不工作
- 在分布式领域,需要降低交互复杂度的时候,就上hash
假设目前有M个数据,N个节点,当新增一个节点时,理想的数据移动量:为 M / (N + 1)
一致性hash + 虚拟节点 大致可以实现这个数量
负载均衡
一致性hash算法也使用在负载均衡中
使用负载均衡器的好处
- 负载均衡
- 提高了安全性,黑客只能知道负载均衡器的ip,但是不知道具体服务器的ip
常用的负载均衡策略
- 随机
- 轮询
- 固定权重值
- IP 哈希(基于一致性随机散列函数,就是这里的一致性hash分区算法,根据请求的ip值)
- 最少 TCP 连接数
- 最小响应时间
- 基于各服务器实际负载的动态负载均衡算法
ip hash的好处:只要请求来源的ip不变,那么就会一直访问一个服务器,这在处理有登录状态的请求的时候是有好处的
前面四个都没有考虑实际的压力
后面三个就考虑到了
一般不使用最后一个
这个可以看老师之前的网课
5.3 案例:分布式文件系统
文件系统
- 就是在软件层面只暴露文件的目录信息
- 使用者不需要管文件存在磁盘的哪个位置,只需要知道文件的路径就可以查看文件
- 就是将数据从硬盘上在逻辑上抽象成为文件树的形式
分布式文件系统也一样
1. 说明
- 分布式文件系统:将分布式系统中多个节点的存储资源整合在一起,向用户 应用程序呈现统一的存储空间和文件系统目录树。用户无需关心数据存储在哪个节点上。
- 大文件被自动分块并分别存储到不同的节点上(但是逻辑上不用管这些)。
2. 特点
- 由分布式文件系统中间件自动处理文件的分块、存储节点选择和副本备份等问题。
- 统一名字空间:每个文件、目录在分布式文件系统中都有统一的、唯一的名字。
- 锁管理机制:对多个用户的并发读写具有锁控制措施。
- 副本备份机制:一般都支持利用多副本提高数据容错性。
- 数据存取方式:随机写入或追加式写入
- 安全机制:对读写文件有权限控制措施
- 可 扩展性:支持通过增加节点扩充存储容量
- 高吞吐率:多副本可以提高数据吞吐率-
3. 常见的分布式文件系统
- GFS: Google File System Google 公司内部所用,见论文《 The Google File System 》
- HDFS Hadoop Distributed File System Apache 根据GFS 论文实现的开源分布式文件系统,Hadoop 生态系统的重要组成部分
- Ceph :加州大学的 Sage 开发的开源分布式文件系统,被云平台广泛应用,已被集成到 Linux 内核。同时支持块存储、对象存储和文件存储。
- TFS Taobao File System
- FastDFS
- GridFS
- MogileFS
GFS:就是采用分区思想,最早Google要爬取全世界所有的网站存起来,但是买不起那么多的服务器,就使用PC机,PC机的好处
- 偏移
- 容易更换
更换PC机之后,文件的数据也会自动更换到新的PC机上
4. HDFS 分布式文件系统
(1) 说明
- HDFS 遵循主 从架构,由单个 NameNode (NN) 和多个DataNode (DN ) 组成。
(2) 特点
- 高 容错: 采用 数据多 副本方案 ,部分 硬件的损坏不会导致全部数据的 丢失。
- 高 吞吐量:支持多个客户端同时与多数据节点直接通信,实现了高 吞吐量的数据 访问。(不同于低延迟数据访问)
- 大文件支持: HDFS 适合于大文件的存储,文档的大小应该是 GB 到 TB 级别的 。( 为什么不适合大量小文件存储
- 简单一致性 模型: HDFS 更适合于一次写入多次读取 (write once read many) 的访问模型。支持将内容追加到文件末尾,不能 从文件任意位置新增数据。
(3) 工作原理
-
HDFS采用三副本存储,就是每存一个文件,就会放到三个服务器
-
HDFS处理的基本单位是文件,是将文件以128MB为一个块划分的,超过128MB就分一块
所以一个文件对应着多个 <块ID,块内容>
因此也不能使用前面的一致性hash算法
-
找了一个集中的点来记录这个对应关系