1 概述
分布式存储概览
2 ACID与CAP
2.1 概述
提到分布式存储,无人不会提及到大名鼎鼎的ACID原则,CAP原理,与BASE原则
2.2 ACID
ACID,指数据库事务正确执行的四个基本要素的缩写。包含:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)。一个支持事务(Transaction)的数据库,必需要具有这四种特性,否则在事务过程(Transaction processing)当中无法保证数据的正确性,交易过程极可能达不到交易方的要求。
- 原子性(Atomicity),一个事务要么全部执行,要么不执行
- 一致性(Consistency),事务的运行并不改变数据库中数据的一致性
- 隔离性(Isolation),两个以上的事务不会出现交错执行的状态
- 持久性(Durability),事务执行成功以后,该事务所对数据库所作的更改便是持久的保存在数据库之中,不会无缘无故的回滚
不知道你是第一次看这四个名词是什么感觉,反正我第一次看的时候感觉就是,好像有点明白,又好像有点不明白。我们重新来推导一下这四个特性,想象一下最开始的数据库连上面一个特性都没有。
2.2.1 简陋数据库
update t_user set name = 'fish1' where userId = 10001
我用客户端执行了上面一条sql,然后机器突然断电了。
select * from t_user where userId = 10001
重启机器后,我执行上面那条查询语句,发现userId=10001的name为fish,而不是我最后一次输入的fish1!
这是因为数据库在执行完update操作后,竟然没有调用file的sync,让数据强制写落到磁盘上,而是只缓存到内存中,导致数据库掉电后重启造成事务丢失。所以,数据库的第一个要求特性是持久性(Durability),让每个事务执行后都必须落地磁盘,保证即使机器掉电后数据也不会丢失。
2.2.2 D数据库
update t_user set money = money + 100 where userId = 10002
update t_user set money = money - 100 where userId = 10001
我用客户端执行了上面的一条sql,目的是让10001用户转钱给10002用户100元。很不幸的是,在执行完了第一条sql后,机器又断电了。
select * from t_user where userId = 10001
select * from t_user where userId = 10002
重启机器后,我执行上面那条查询语句,发现10002用户多了100元,而10002用户仍然是保持原值,没有增加100元!
我查,这是多么恶心的事情简直不能忍!数据库应该是要么10001用户少100,同时10002用户多100,要么是都不变,怎么会有个中间状态。所以,数据库的第二个要求特性是原子性(Atomicity),事务要么是全部提交的,要么是全部不提交的,这部分数据库是用日志来实现的。
start trasiaction
update t_user set money = money - 100 where userId = 10001
update t_user set money = money + 100 where userId = 10002
end trasiaction
在这以后,我们提交sql是这么提交的,通过start trasiaction告诉数据库这两条sql连起来是一个事务。
2.2.3 AD数据库
start trasiaction
update t_user set money = money + 100 where userId = 10002
update t_user set money = money - 100 where userId = 10001
end trasiaction
我依然用客户端执行了上面的一条sql,目的是让10001用户转钱给10002用户100元。很不幸的是,在执行完了第一条sql后,机器又断电了。
select * from userId = 10002
与此同时,10002的用户在自己家不断调用上面的sql语句,来查询自己有多少钱。我重启机器后,由于Atomicity特性,10002用户的数据回滚了。10002用户在家看到自己的钱突然多了100元,而后又少了100元。他空欢喜了一场,然后投诉我们公司,为什么给了自己100元,然后又突然抽走,他甚至还截图了自己多了100元数据的页面!
为了避免这种恶心的情况,数据库的第三个要求特性是一致性(Consistency),数据库只能看到提交后事务的数据,不能看到事务操作过程中处于不一致状态的数据。这部分数据库使用MVCC机制来实现的。
2.2.4 ACD数据库
start trasiaction
select * from t_user where userId = 10001
update t_user set money = money - 100 where userId = 10001
update t_user set money = money + 100 where userId = 10002
end trasiaction
start trasiaction
select * from t_user where userId = 10001
update t_user set money = money - 100 where userId = 10001
update t_user set money = money + 100 where userId = 10003
end trasiaction
我们进入了现实中,其实转钱前是需要查询用户够不够钱的,不够钱的话,是不会执行update操作的。所以,在sql前我加上了select操作。问题来了,我们需求是用户10001需要向10002与10003用户各转100元的,当然10001用户只有120元的情况下,他会成功么。答案是,他有可能会成功!
#事务1
select * from t_user where userId = 10001
#事务2
select * from t_user where userId = 10001
#事务1
update t_user set money = money - 100 where userId = 10001
update t_user set money = money + 100 where userId = 10002
#事务2
update t_user set money = money - 100 where userId = 10001
update t_user set money = money + 100 where userId = 10003
当两个事务按着上面的顺序交叉执行时,只有120元的10001用户竟然是可以向10002与10003用户各转100元的!
所以,数据库的第四个要求特性是隔离性(Isolation),事务间应该有隔离,如果他们有数据冲突,应该进行上锁操作的。
start trasiaction
select * from t_user where userId = 10001 for update
update t_user set money = money - 100 where userId = 10001
update t_user set money = money + 100 where userId = 10002
end trasiaction
start trasiaction
select * from t_user where userId = 10001 for update
update t_user set money = money - 100 where userId = 10001
update t_user set money = money + 100 where userId = 10003
end trasiaction
最终,我们的sql加上了for update操作,告诉mysql,我是要对10001用户的数据进行上锁的,其他并发事务要过来的话只能先等我执行完毕了。
2.2.5 ACID数据库
至此,我们用了转钱的例子,来证明了ACID的每个特性都是多么必要的,不然会导致后果很严重的金钱问题。数据不一致,钱转多了,或者转少了。最后,总结一下ACID特性
- 原子性(Atomicity),强调写一致,要么全部完成,要么全部不完成。
- 一致性(Consistency),强调读一致,只能看到已经提交的事务数据。
- 隔离性(Isolation),强调并发一致,即使事务是并发执行的,数据也不会造成不一致。
- 持久性(Durability),强调可靠,只要事务提交了,就不会丢失数据。
2.3 CAP
2.3.1 概述
在一个CAP分布式系统中, Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可得兼。
- 一致性(Consistency):在分布式系统中的所有数据备份,在同一时刻是否同样的值。(等同于所有节点访问同一份最新的数据副本)
- 可用性(Availability):在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求。(对数据更新具备高可用性)
- 分区容忍性(Partition tolerance):以实际效果而言,分区相当于对通信的时限要求。系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在C和A之间做出选择。
CAP原理就像是能量守恒定律一样,给那些想实现永动机,和想实现分布式ACID的人们当头一棒,这是不可能的!
2.3.2 分区容忍性
系统要么是分布式的,要么是单机的。
2.3.3 一致性
这个一致性和ACID的一致性不同,这个一致性是单个操作的一致性,而不是单个事务(多个操作)的一致性。分布式的一致性有以下几种:
- 强一致性。在更新完成后,(A、B或C进行的)任何后续访问都将返回更新过的值。
- 弱一致性。系统不保证后续访问将返回更新过的值。
- 最终一致性。存储系统保证如果对象没有新的更新,最终(在不一致窗口关闭之后)所有访问都将返回最后更新的值。
注意,弱一致性中包含着最终一致性的范围。
2.3.4 可用性
在分布式环境下,有N台机器
- 高可用,N-1台机器都当机了,仍然可以对外服务。
- 低可用,1太机器当机了,就不能对外服务。
2.3.5 直观
关于CAP的通俗理解,《七周七数据库》中有一个通俗的理解。
如果世界上有四个人ABCD,另外有一个健忘的人E,ABCD是与世隔绝的,E是个杰伦迷,偶尔会告诉ABCD其中一个人杰伦的最新专辑是什么,偶尔也会问ABCD其中一个关于杰伦的最新专辑是什么。
- CA系统,ABCD四个人聚在一起生活,E无论什么告诉,ABCD都会同时知道,所以E问ABCD其中一个人时,他们都会告诉E一个准确的答案。
- AP系统,ABCD四个人现在分开了。但他们约定,如果E告诉他们任何一个人关于杰伦的信息,他都会先打电话给其他人通知这个消息,在确保所有人都收到后,他才会告诉E他听到了。这种情况下,E后来无论问哪个人,数据都是准确的。由于并不是所有人的电话都能打通,所以E的每次询问并不一定会有反应。
- CP系统,ABCD四个人现在分开了。但他们约定,如果E告诉他们任何一个人关于杰伦的信息,他都会先确定他收到了,然后再打电话给其他人通知这个消息。这种情况下,E可能会收到一些过期的杰伦信息。
2.3.6 总结
CAP原理看起来是个绝望的结论,但它其实并没有限制构造这样的系统:
- CP系统,强一致性+基本可用性,即使当掉了N/2-1台机器,仍然可以对外提供一致性服务。
- AP系统,最终一致性+高可用性,即使当掉了N-1台机器,仍然可以对外服务,但是数据可能是不一致的,只保证经过一段时间窗口后,数据是最终一致的。
所以,根据CAP的原理的不同抉择,以及对不同场景下的数据需求,nosql的数据库建立了许多不同模型下的数据库。
3 伸缩性
怎样实现数据在多台机器中透明伸缩,这是个好问题。
3.1 哈希
将数据放在多台机器上,以userId为key直接哈希到对应的数据库上。
- 优点是开发简单,易维护
- 缺点是伸缩困难,例如从3台机器伸缩到5台机器的时候,由于哈希的值变化大,3与4的最小公倍数为12,也就是每12个数值下只有3个数值是放在自己的原机器,其他9个数值需要迁移到其他机器上。增加25%的机器数量,导致了75%的数据需要迁移。数据的迁移比例与增加的机器比例太高,导致迁移数据的速度超级慢,无法达成透明迁移。所以,一般只会使用倍数迁移法。2台->4台->8台这样的迁移。
3.2 一致性哈希
3.2.1 环形哈希
首先我们引入有4个key的环
每台机器在环上任意取三个点,然后key以顺时针的方式在环上找到的第一个节点作为该节点的哈希值。
3.2.2 迁移成本
当B节点数据需要摘除时,只有A节点与B节点间的数据需要迁移到C节点,而其他节点的数据不需要迁移。
当B与C节点之间新增一个新节点的时候,只有B与C之间的一部分数据需要迁移,其他数据不迁移。
3.2.3 虚拟节点
但是,当节点数量比较少时,直接的环形哈希会容易导致数据分布不平衡,相当多的数据被扔到一台机器上。解决办法很简单,引入一个虚拟层,将单个实体节点对应到N个虚拟节点上。这样当增加一台机器时,会增加N多的虚拟节点,大概均衡地将数据切成N份,导致原来的机器的数据能平均地迁移一小部分数据到这台新机器上了。这样大大地降低了迁移的成本,而且保证数据均衡分布。
以上,我们都是假设每个数据key对应的data是大致均等的,所以用了一致性哈希后,由于均衡分布了key,所以也均衡分布了data。但是如果,每个key对应的data是差异很大的,或者每台机器上的容量也是差异很大的,这得怎么做data的均衡分布呢?
3.3 一致性哈希meta+数据库
hdfs中采用了一致性哈希+数据库的方式做二级映射,数据存放在namenode与datanode两个位置,namenode存放数据的meta列表,即datanode的块数,与每块所在的机器位置,而datanode则存放数据的具体信息。当需要寻找key所在的数据时,先用一致性哈希来寻找key所在的namenode,然后在namenode中的数据库返回该key的datanode信息,再到datanode指定的机器取出来data,合并起来即可。
这样即使每个key对应的value是变长的,也会因为二级映射的方式变得均衡分布。
3.4 总结
分布式的高伸缩性主要要解决的问题是:
- 数据的均衡分布,直接哈希,虚拟节点,meta分布。
- 数据的透明迁移,环形哈希,数据库映射。
4 可用性
现在数据的确是分布到多个机器上,而且负载均衡了,但是,如果其中一台机器崩掉了,怎么办?怎样做到即使崩掉了一两台机器,系统仍然可以无损地对外服务?
4.1 单写
提高可用性的简单方法是建立多台备机,同时对外只有一台主机在服务,当主机挂掉后,备机顶上即可。由于多台机器中只有一台机器是实际对外服务的,其他机器仅作备份或只读用,所以这种方案叫单写。
4.1.2 强同步
- 应用发起更新(含增删改操作)请求,Master完成操作后向Slave复制数据
- Slave接收到数据后向Master返回成功,Master接到Slave的反馈后响应应用
- Master向Slave复制数据是同步进行的,因此Slave不可用会影响Master上的操作,而Master不可用不会引起数据不一致
显然,这是一个CP系统。
- 优点是主从机器是强一致的
- 缺点是从机当机会导致可用性降低
为了避免从机的当机造成系统可用性下降,一般会配备多个从机,以提高可用性。当然,因为从机的数量增多,导致每个请求的延迟增大,所以从机数量也不能太多。
- 优点是主从机器是强一致的,提高可用性
- 缺点是系统整体延迟增大
4.1.3 异步
- 应用发起更新(含增删改操作)请求,Master完成相应操作后立即响应应用
- Master向Slave复制数据是异步进行的,因此Slave不可用不影响主库上的操作,而Master不可用有较小概率会引起数据不一致
显然,这是一个AP系统。
- 优点是事务延时与单机无异,同步效率高,备机当机不会影响可用性。
- 缺点是主从数据在突然当机下会不一致
4.1.4 半同步
- 正常情况下半同步复制和强同步复制的流程一样
- 当Master向Slave复制数据出现异常的时候(Slave不可用或者双节点间的网络异常),Master会暂停对应用的响应,直到复制方式超时退化成异步复制。如果允许应用在此时更新数据,则Master不可用会引起数据不一致
- 当双节点间的数据复制恢复正常(Slave恢复或者网络恢复),异步复制会恢复成强同步。恢复成强同步的时间取决于半同步复制的实现方式。
显然,这是一个CP系统->AP系统->CP系统的配置。
- 优点是数据在绝大情况下是保持一致的,而且保证了一定的可用性。
- 缺点是配置麻烦。
4.2 多写
多台机器中的每一台机器都能对外服务的,机器之间的地位平等,所以这种方案叫多写。
4.2.3 主主互备
mysql设置为主主互备,互备的方式为强同步。每行写的时候,都需要在另外一台机上落地数据,然后才返回,延迟较高,还不如直接切分来提高整个系统的写吞吐量来得靠谱。不推荐使用。
4.2.4 NWR模型
NWR是完全去中心化,完全对等的超高可用性数据架构。最开始由Amazon Dynamo提出,随后有开源的实现Riak和Cassandra。
NWR是指共有N个节点,W是写入数量才返回成功,R是读出数量才返回成功。每次写入一个节点的数据,都会自动逐渐传播到其他节点上。NWR 模型将 CAP 的选择权交给了用户,由用户自己选择 CAP 中的哪两个。其中,N 代表 N 个备份,W 代表至少写 W 份才认为成功,R 代表至少要读 R 份才认为成功。
- 如果 W+R>N ,是可以保证强一致性的。因为 W+R > N, 所以 R > N-W,什么意思呢?就是读取的份数必须要大于未成功写的份数,这样至少能读到一份最新值。
- 如果 W+R<=N,则能够保证最终一致性。
在不同场景下我们会选择不同的NWR
- 如果我们要高可写的环境,我们可以配置 W=1 R=N。这个时候只要写任何节点成功就认为成功,但是读的时候必须从所有的节点都读出数据。
- 如果我们要求读的高效率,我们可以配置 W=N R=1。这个时候任何一个节点读成功就认为成功,但是写的时候必须写所有三个节点成功才认为成功。
但是,NWR模型最忧伤的地方在于,双写导致的数据冲突问题交给了用户自己来解决。例如N=3,W=1,R=2。显然这是一个,最终一致性系统。
A = [1]
B = [1]
C = [1]
刚开始时ABC三个节点的数据都是1。
A = [1,2]
B = [1]
C = [1]
用户U1给A设置为2的值。然后A节点在慢慢传播到其他节点中。
A = [1,2]
B = [1]
C = [1,3]
用户U2给C设置为3的值。然后C节点在慢慢传播到其他节点中。
A = [1,2]|[1,3]
B = [1,2]|[1,3]
C = [1,2]|[1,3]
后来A和C节点的数据慢慢地相互传播,由于有版本号的存在,现在A和C都发现了他们同时更新了同一行数据,所以现在所有节点中都保存着这种冲突的问题。
A = [1,2]|[1,3]
B = [1,2]|[1,3]
C = [1,2]|[1,3]
现在用户U3过来读节点的数据,这时节点会返回这行的数据有冲突,至于如何这个冲突,需要调用方引入合并算法来解决,NWR模型不管。目前NWR模型检测双写中存在数据冲突的方式是,向量时钟模型,以及时间戳模型,这里就不多说了。
- 优点是超高可用性,延迟低,无中心对等结构
- 缺点是由于NWR模型将双写导致数据冲突的问题直接扔给了用户,这意味着你每次从数据库读取数据后还要考虑一下冲突,需不需要合并数据。这实在是太反人类了!!!
所以,目前NWR模型仅适用于一些合并数据完全自动化的特殊业务,例如是存储图片的数据中心,他们的合并算法可以简单地设置为后写入的优先级更高。
4.3 故障恢复
这里我们探讨一下在单写的分布式结构下,如果其中一台机器崩溃了,如何向调用方透明地进行故障恢复,恢复系统的可用性。
4.3.1 paxos或raft
在多台机器中分布式地无中心地选出一个主席,是一个很头疼的问题。现有主要的是paxos算法和raft算法。这两个算法都是无比的复杂,完全可以单独拉成一本书来看,这里就不多说了。raft动画展示看这里。paxos动画展示看这里。这两个算法是故障恢复的核心,我们后面会提到。
4.3.2 dns
系统对外是一个域名,当slave与master之间使用心跳检测来确定是否双方是否存在。当slave们检测到master当机后,会启动paxos或raft的选主算法,在多个slave中选举一个做master,然后将新的master的IP地址发布到内网dns系统中。调用方在下一次调用时会用新的IP去调用。
优点:无中心,去分布式。 缺点:切换速度慢,有可能导致双写。
4.3.3 HA
使用一台单独的机器HA对外做路由器,HA在master与slave之间在心跳检测,当探测到master当机后,自动切换到slave机器,这样故障恢复时就能做到对调用方透明了。
但是,这样会造成单点故障,万一HA挂了,那就啥都完蛋了。原来引入Master-Slave是为了提高可用性,结果引入了HA后又造成了单点故障,可用性又降低了。
- 优点是切换速度快,没有双写问题。
- 缺点是中心化的HA,系统形成单点故障
4.3.4 dns+HA
建立多个HA节点,同时间只有一个HA节点对外服务,当其中一个HA崩溃后,多个HA的选举算法会推选出一个新的HA,然后发布新的HA的IP到内网dns。主的HA则会维护多个master-slave之间的故障检测与恢复。
优点:没有双写,没有单点故障,大部分情况使用HA切换,极端情况下需要dns切换 缺点:部署复杂
4.3.5 总结
在paxos与raft的帮助下,故障恢复变成了一件很简单的事情。更多关于高可用性的故障恢复资料,可以看这里
5 nosql实例
参照七周七数据库,我们列举一下七个数据库,并简要分析一下他们的架构。
5.1 PostgresSQL
典型的单机关系型数据库,满足ACID原则,显然的AC系统。
5.2 Riak
一致性哈希实现伸缩性,NWR+向量时钟实现高可用性,根据NWR的配置,既可以是AP的,也可以是CP的。但一般用作AP系统。
5.3 HBase
hbase的底层是hdfs,使用一致性哈希meta+数据库实现伸缩性,一主多从实现高可用性。显然是CP系统。
5.4 MongoDb
使用普通哈希实现伸缩性,一主多从实现高可用性。显然是CP系统。
5.5 CouchDb
没有分片,仅仅使用Master-Master,也就是双写模型来实现高可用性,显然也是AC系统。
5.6 Neo4j
没有分片,也仅仅使用一主多从来实现高可用性,显然也是AC系统。值得一说的是,neo4j难得的满足ACID属性的nosql数据库。
5.7 Redis
默认的redis是单机的,redis集群一般的话是使用一致性哈希做伸缩性,主从做高可用性,显然也是CP系统。
6 事务
CAP中的一致性与ACID是一致性是不同的,CAP强调的是单个数据在分布式中一致性,ACID强调的是多个数据在事务过程中的一致性。
6.1 原子操作
如果有两个操作要实现事务,第一个想法是能不能将这两个操作合并成一个操作,成为一个事务。例如,扣减库存问题,准确来说是两个操作
获取库存
更新库存
在并发冲突下,扣减的数据会出问题,会造成超卖。
递减库存
解决办法很简单,有提供递减数据的单条操作么,有的话就能变成一条操作,不会超卖了。
6.2 单机事务
如果有两个操作要实现事务,第二个想法是能不能将这两个操作的数据都放在同一个数据库上,利用单机数据库的事务操作实现分布式中多个操作的事务性。例如,记录每个食谱下的点赞数据,以及点赞总数,是两个操作。
更新某个人对某个食谱的点赞状态
更新某个食谱的总点赞数
在当机情况下,有可能如果第一条执行成功,第二条没有执行,那么点赞的总数表,和点赞状态的数据就对不齐了。
更新某个人对某个食谱的点赞状态,食谱ID为分区键
更新某个食谱的总点赞数,食谱ID为分区键
解决办法也简单,分区时这两个表都是以食谱ID为key,这保证了这两个表的数据都在同一个数据库下,那么我们就能用单机数据库的方法来实现事务了。
6.4 重试与幂等
如果有两个操作要实现事务,第三个想法是能不能放宽一下数据的一致性,让补偿机制不断重试运行,来保证数据最终的一致性。例如,A给B转账100元,这是两个操作。
A减少100元
B增加100元
在当机情况下,有可能如果第一条执行成功,第二条没有执行,那么A少了100元,B没有增加100元。
A给B转账的事件插入任务队列,并分配一个全局唯一的任务ID为UUID。
设置UUID下的任务状态为未开始
A用户所在数据库开启事务
A用户增加操作日志,UUID任务下减少100元
A用户金额减少100元
A用户所在数据库提交事务
B用户所在数据库开启事务
B用户增加操作日志,UUID任务下增加100元
B用户金额增加100元
B用户所在数据库提交事务
设置UUID下的任务状态为已完成
如果中途当机了,没有关系,任务会自动重启执行,由于每个任务都有一个唯一的UUID,那么任务中任何已重复的部分都不会重做,而只做那些中途当机导致数据不一致的部分。这就是幂等带来的任务可以无限重试的能力。由于幂等没有给分布式系统带来锁开销,所以是一个很常用的分布式事务方式,但是其没有保证事务一致性,而只保证最终一致性。所以,多个任务之间的顺序就很重要了。
想想看,如果转账操作是先给B增加钱,然后再给A减少钱,会有什么后果?另外一个问题,为什么增加与减少金额需要写日志,而且还要开单机事务?
6.5 两阶段提交
如果在某些情况下,确实需要保证多个操作是同时操作,而且是保证事务一致性怎么办。好了,只能使用大杀器,真正意义上的分布式事务,两阶段提交协议。
第一阶段:
- 首先,协调者在自身节点的日志中写入一条的日志记录,然后所有参与者发送消息prepare T,询问这些参与者(包括自身),是否能够提交这个事务
- 参与者在接受到这个prepare T 消息以后,会根据自身的情况,进行事务的预处理,如果参与者能够提交该事务,则会将日志写入磁盘,并返回给协调者一个ready T信息,同时自身进入预提交状态状态;如果不能提交该事务,则记录日志,并返回一个not commit T信息给协调者,同时撤销在自身上所做的数据库改
- 参与者能够推迟发送响应的时间,但最终还是需要发送的。
第二阶段:
- 协调者会收集所有参与者的意见,如果收到参与者发来的not commit T信息,则标识着该事务不能提交,协调者会将Abort T 记录到日志中,并向所有参与者发送一个Abort T 信息,让所有参与者撤销在自身上所有的预操作
- 如果协调者收到所有参与者发来prepare T信息,那么协调者会将Commit T日志写入磁盘,并向所有参与者发送一个Commit T信息,提交该事务。若协调者迟迟未收到某个参与者发来的信息,则认为该参与者发送了一个VOTE_ABORT信息,从而取消该事务的执行。
- 参与者接收到协调者发来的Abort T信息以后,参与者会终止提交,并将Abort T 记录到日志中;如果参与者收到的是Commit T信息,则会将事务进行提交,并写入记录
两阶段提交协议的假设是第一阶段的耗时较长,第二阶段的耗时很短。第二阶段在分布式中导致数据突然不一致的可能性低,从而来实现分布式事务。为了避免协调者造成单点故障,一般会引入多个协调者,以及paxos或raft来提高系统的可用性。
7 总结
分布式存储原理,这是个比较头疼的事情,涉及的算法很多。这里只是草草说明,如有不足,还请指出。
- 本文作者: fishedee
- 版权声明: 本博客所有文章均采用 CC BY-NC-SA 3.0 CN 许可协议,转载必须注明出处!