在后台开发中,当咱们须要支持大规模的并发读写,同时具有横向扩展能力。这这时咱们通常会对数据进行hash分区,从而分布到不一样的服务器中,以解决写的瓶颈。同时每一个写服务器会经过主从同步分布到多台服务器上面,从而实现读写分离,提升读的并发性能。
那么问题来了,一次性写多条数据,怎么保证多台服务器的一致性呢?若是数据同步存在延迟,怎么保证写后必定能读到呢?本文咱们就探讨一下一致性的问题。数据库
一、咱们一般把一致性分为最终一致性与强一致性,那么什么是最终一致性,什么是强一致性呢?
最终一致性(Eventually):写入数据 A 成功后,在其余副本有可能读不到 A 的最新值,但在某个时间窗口以后保证最终能读到。注意这里有限定某个时间窗口。
强一致性(Strong):数据 A 一旦写入成功,在任意副本任意时刻都能读到 A 的最新值。
从定义中咱们能够看出,这种分类方法太过于笼统,不利于实际应用。故咱们通常从数据的维度或者用户的维度进行分类。
二、数据维度的一致性:就是A服务器的数据与B服务器的数据是否一致。数据维度的一致性经常使用的有以下几种:
严格一致性,也叫线性一致性、原子一致性。在分布式系统中,若是某个进程更新了数据,那么在其余进程必须能读取到这个最新的数据。在分布式系统中若是要实现严格一致性,通常读写都须要在同一台服务器上,若是读写分布在不一样的服务器上,即便使用二阶段提交,因为网络有时延,也不可能作到严格的一致性。举一个购物库存的例子,若是A客户看到评估11库存有10台,若是其余客户也都看到库存是10台,那么就知足强一致性,可是若是某个客户B看到了库存是11台,那么不知足强一致性。一个典型的应用场景就是,若是业务须要知足强一致性要求,那么会到MySQL的主库去读写。
顺序一致性是指,全部的进程以相同的顺序看到全部的修改。读操做未必能及时获得此前其余进程对同一数据的写更新,可是每一个进程读到的该数据的不一样值的顺序是一致的。举个例子,zk写的时候,ZAB协议只保证超过半数的进程写入成功就返回了,可是客户端去读的时候,多是从任意的进程读取的,故某个客户端就有可能读到旧的数据库,可是ZAB能够保证按照主进程的写入顺序写入其余进程,所以客户端去读的时候是知足顺序一致性的。在好比聊天时,若是在手机端与电脑端看到的聊天内容的顺序是一致的,那么就知足顺序一致性。
因果一致性是一种弱化的顺序一致性,全部进程必须以相同的顺序看到具备潜在因果关系的写操做,不一样进程能够以不一样的顺序看到并发的写操做。MySQL5.7开始的数据库的主从同步,其实就是知足因果一致性。在好比一个客户先购买了某只股票,后面又卖了。那么无论在哪里看到的都是先买了某只股票,再卖了某只股票,那么就是知足因果一致性的。咱们大仓风控的主从同步,就是知足因果一致性的。
三、用户维度的一致性,主要包括:
单调读一致性是指,若是一个进程读取数据项 a 的值,那么该进程对 a 执行的任何后续读操做,老是获得第一次读取的那个值或更新的值。说白了,就是不能读到新数据后,再读到比这个数据还旧的数据。好比在微博的场景中,某个明星发布了一条微博,若是某个粉丝读到了这条微博,再读到这条微博事后,从新打开APP,发现那条微博不见了(明星没有删除微博),那么就不知足单调一致性。
单调写一致性是指,一个进程对数据项 a 执行的写操做,必须在该进程对 a 执行任何后续写操做前完成。这个很容易知足,注意这里是一个进程,全部的写操做都是顺序的。
写后读一致性是指,一个进程对数据项 a 执行一次写操做的结果,老是会被该进程对 a 执行的后续读操做看见。这个比较常见,好比数据库采用 Master-Slave 结构部署时,写完 Master 数据库,若是从 Slave 读取,有可能读不到,就不知足写后读一致性了。再具体一点的例子就是,某个明星发布了一条微博,可是这个明星再次打开APP时,若是看不到本身发布的微博,那么就不知足写后读一致性。
读后写一致性是指,同一进程对数据项 a 执行的读操做以后的写操做,保证发生在与读时的版本上或者更新的版本上。好比下文介绍的Quorum机制,写的服务器的数据版本是有可能比读的时候旧的,若是写成功了,那么就不知足读后写一致性。服务器
上文提到高并发写的时候,咱们经过多机器hash处理,从而实现每一个机器的写并发都不会太大,可是业务通常都有都多写少的特色,故咱们又经过复制多个副本,而后读操做都在副本上面实现,那么咱们要如何作到读后写一致性呢?
好比 MySQL,就能够采用一个 Master,多个 Slave 的方式,全部的写都在 Master 上更新,全部的读都在 Slave 上进行,但这里存在一个问题,就是怎么保证写后读一致性?咱们能够监控读写的延迟,而后设置一个最大的读写延迟的阈值,若是写后读再阈值之内,那么就去master读,若是超过了阈值,就去slave读。
前面的方法是只再主节点里面写数据,那么咱们是否能够一次写多个节点呢?这时Quorum 机制(NWR 模型)就派上用场了。
Quorum 机制就是要知足公式 W+R > N。其中,W 表示必须至少写入成功的节点数,R 表示至少读取成功的节点数,N 表示总节点数。这个公式把选择权交给了业务用户,让用户来作出最终决策。那么业务端怎么知道读取出来的就是最新的数据呢?就是利用版本号,每次写数据的同时,都记录这条数据对应的版本号,读数据的时候判断版本号,版本最新的就是最终数据。这里还存在另一个问题,那就是,若是写的时候只写入的节点<=N/2,当存在并发写操做时,版本会存在冲突,这就要求咱们写数据的时候最好是遵循 W>N/2。网络
一、前面介绍的只再主节点写数据,可是若是主节点挂了,就要选一个从节点做为新的主节点。那么咱们如何才能保证选出来的主节点的数据不丢失呢?这时就涉及到分布式共识问题了,我后面会在分布式共识里面介绍。
二、前面介绍的经过hash到不一样的服务器,那么经常使用的hash方法都有哪些呢?怎么作到一个工业级的hash呢?并发