关于后端:一致性详解

1次阅读

共计 2447 个字符,预计需要花费 7 分钟才能阅读完成。

在后盾开发中,当咱们须要反对大规模的并发读写,同时具备横向扩大能力。这这时咱们个别会对数据进行 hash 分区,从而散布到不同的服务器中,以解决写的瓶颈。同时每个写服务器会通过主从同步散布到多台服务器下面,从而实现读写拆散,进步读的并发性能。
那么问题来了,一次性写多条数据,怎么保障多台服务器的一致性呢?如果数据同步存在提早,怎么保障写后肯定能读到呢?本文咱们就探讨一下一致性的问题。

一致性的分类

1、咱们通常把一致性分为最终一致性与强一致性,那么什么是最终一致性,什么是强一致性呢?
最终一致性(Eventually):写入数据 A 胜利后,在其余正本有可能读不到 A 的最新值,但在某个工夫窗口之后保障最终能读到。留神这里有限定某个工夫窗口。
强一致性(Strong):数据 A 一旦写入胜利,在任意正本任意时刻都能读到 A 的最新值。
从定义中咱们能够看出,这种分类办法太过于抽象,不利于理论利用。故咱们个别从数据的维度或者用户的维度进行分类。
2、数据维度的一致性:就是 A 服务器的数据与 B 服务器的数据是否统一。数据维度的一致性罕用的有如下几种:
严格一致性,也叫线性一致性、原子一致性。在分布式系统中,如果某个过程更新了数据,那么在其余过程必须能读取到这个最新的数据。在分布式系统中如果要实现严格一致性,个别读写都须要在同一台服务器上,如果读写散布在不同的服务器上,即便应用二阶段提交,因为网络有时延,也不可能做到严格的一致性。举一个购物库存的例子,如果 A 客户看到评估 11 库存有 10 台,如果其余客户也都看到库存是 10 台,那么就满足强一致性,然而如果某个客户 B 看到了库存是 11 台,那么不满足强一致性。一个典型的利用场景就是,如果业务须要满足强一致性要求,那么会到 MySQL 的主库去读写。
程序一致性是指,所有的过程以雷同的程序看到所有的批改。读操作未必能及时失去此前其余过程对同一数据的写更新,然而每个过程读到的该数据的不同值的程序是统一的。举个例子,zk 写的时候,ZAB 协定只保障超过半数的过程写入胜利就返回了,然而客户端去读的时候,可能是从任意的过程读取的,故某个客户端就有可能读到旧的数据库,然而 ZAB 能够保障依照主过程的写入程序写入其余过程,因而客户端去读的时候是满足程序一致性的。在比方聊天时,如果在手机端与电脑端看到的聊天内容的程序是统一的,那么就满足程序一致性。
因果一致性是一种弱化的程序一致性,所有过程必须以雷同的程序看到具备潜在因果关系的写操作,不同过程能够以不同的程序看到并发的写操作。MySQL5.7 开始的数据库的主从同步,其实就是满足因果一致性。在比方一个客户先购买了某只股票,前面又卖了。那么不论在哪里看到的都是先买了某只股票,再卖了某只股票,那么就是满足因果一致性的。咱们大仓风控的主从同步,就是满足因果一致性的。
3、用户维度的一致性,次要包含:
枯燥读一致性是指,如果一个过程读取数据项 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。

思考题:

1、后面介绍的只再主节点写数据,然而如果主节点挂了,就要选一个从节点作为新的主节点。那么咱们如何能力保障选出来的主节点的数据不失落呢?这时就波及到分布式共识问题了,我前面会在分布式共识外面介绍。
2、后面介绍的通过 hash 到不同的服务器,那么罕用的 hash 办法都有哪些呢?怎么做到一个工业级的 hash 呢?

正文完
 0