`

分布式设计理论

 
阅读更多


CAP

Consistence 一致性原则:读取的数据一定是最新的

Availability 可用性原则:每个操作都能在一定时间内返回

Tolerence Of Partition 分区可容忍性原则: 允许分布式系统中的某些分区down掉

CAP理论认为,三个条件不可同时存在


NWR策略:N表示需要N个数据备份,W表示数据写入N个节点才算成功,R表示需要读取R个节点的数据才能保证其中有一份是最新的。比如其中W+R>N。例如需要备份数为3份,写入2份即表示数据成功写入,则必须读取2份数据才能保证其中有一份是最新的。


主备策略:同一时刻,只有主可以写操作,备只能读取,并通过commit log保持异步数据更新。为防止一台主宕机导致数据丢失,可以采用两台写返回争取,才返回响应的策略。


动态数据均匀分布:一致性hash算法,保证动态增加节点后,不会产生数据抖动问题。


网络服务,单节点,数据一致性:通过数据版本号控制。

服务端原始数据D,版本号N,A、B客户端,通过网络获取数据并修改数据。A获取数据(D,N),B获取数据(D,N),A改变数据,并设置(D‘,N+1),B做数据操作,并设置(D’‘,N+1),服务器端收到数据设置请求后,加锁,判断版本号是否大于本地数据版本号,如果是则更新数据和版本号,然后解锁。

这里关键点事,网络服务中,客户端和服务端无法加锁。通过版本号控制数据的有效性。类似于CompareAndSet。


分布式数据容灾:

双写:客户端一次同时写两份。

异步同步:客户端写master server,异步线程将master的commit log同步至slave做数据同步

强同步:每个客户端请求,从slave到master,倒流水线的修改数据,全部完成后,返回成功

半同步:数据写入K》=1个slave和master后,返回成功。当master宕机后,slave变为master。剩下的slave可以通过异步同步。


Redis的数据持久化策略:

1、snapshot: 通过fork进程,父进程继续接受client的数据请求,子进程将fork后得到的进程内的数据全部dump到本地文件。(在下一次备份周期前,主进程crash会丢失部分数据)

2、aof(append only file),每次对redis修改操作都首先将commit log追加到本地文件,成功后才修改内存中的数据。但由于fwrite在操作系统有缓存,所以,如果主机断电,还是会有部分数据丢失。需要及时做fsync将数据持久化到磁盘。redis根据业务安全程度,可配置fsync的频率。频率越高,性能越差,数据容灾能力越强。


copy-on-write:保证读写效率,防止写操作影响频繁的读操作。每次更新数据,都是更新新copy的副本,完成更新后,原子更新指向数据的指针即可。这样在更新数据的同事,读操作仍然高效的在读取旧数据。


vector clock算法:结合NWR理论,解决多个节点读写一致性。 假设有节点A,B,C。通过每个节点对数据的保留节点版本号记录数据的有效性。写操作发送至A后,数据记录为D1(A1), 数据同步至B,C后,三个节点上的数据都是D1(A1)。写操作发送至B,数据记录在B上变为D2(A1、B1)。同时,写操作发送至C,数据在C上变为D3(A1、C1)。最后,根据NWR原理,客户端读取3份数据,为D1(A1)、D2(A1、B1)、D3(A1、C1),客户端发现D2、D3为最新数据,且有冲突。在客户端解决冲突,数据记录回A,此时A变为D4(A2、B1、C1),是合并后最新的数据。


分布式锁:

1、redis 通过redis的watch功能,实现原子操作的锁。 在修改一个变量前,先watch下,然后修改之,提交后,如果成功,代表是原子操作。失败则表示中间有其它请求修改了对应值,则失败。通过这种原子修改形式,加值锁。

2、通过zookeeper实现。对某个目录下,进行节点create操作,如果成功则表示加锁。如果失败,则表示锁失败。并且可以通过watch阻塞监听节点状态,待节点被删除后,接受到相应回调,然后再次尝试创建节点,即重新竞争锁。


分布式消息队列问题:

1、对于不可丢失的数据,数据项在入缓存队列前,必须持久化,这样保证其可靠性,但是大大降低了tps。比如邮箱的消息队列,比如AOF模式下的redis。

2、对于可丢失的数据,数据可以先入缓存队列,然后异步做持久化。这样会有高并发度。 比如redis



分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics