什么是网络分区:
分布式通常假设网络是异步的,意味着网络可能会导致任意的重复、丢失、延迟或者乱序的节点间消息传递。在实际中,TCP状态机会保证节点间消息传递的不丢失、不重复、时序。但是,在Socket级别上,节点接发消息会阻塞,超时等等。
检测到网络失败是困难,因为我们唯一能跟得到其他节点状态的信息就是通过网络来得到,延迟跟网络失败也无从区分。这里就会产生一个基本的网络分区问题:高延迟可以考虑作为失败。当分区产生后,我们没有渠道去了解到其他节点到底发生了什么事: 它们是否还存活?或者已经crash?是否有收到消息?是否正在尝试回应。当网络最终恢复后,我们需要重新建立连接然后尝试解决在不一致状态时的不一致。
很多系统在解决分区时会进入一个特殊的降级操作模式。CAP理论也告诉我们妖么得到一致性要么高可用性,但是很少有数据库系统能够达到CAP理论的极限,多数只是丢失数据。
redis网络分区后的情况
举个例子 假设集群包含 A 、 B 、 C 、 A1 、 B1 、 C1 六个节点, 其中 A 、B 、C 为主节点, A1 、B1 、C1为A,B,C的从节点, 还有一个客户端 Z1 假设集群中发生网络分区,那么集群可能会分为两方,大部分的一方包含节点 A 、C 、A1 、B1和 C1 ,小部分的一方则包含节点 B 和客户端 Z1
Z1仍然能够向主节点B中写入, 如果网络分区发生时间较短,那么集群将会继续正常运作,如果分区的时间足够让大部分的一方将B1选举为新的master,那么Z1写入B中得数据便丢失了.
注意, 在网络分裂出现期间, 客户端 Z1 可以向主节点 B 发送写命令的最大时间是有限制的, 这一时间限制称为节点超时时间(node timeout), 是 Redis 集群的一个重要的配置选项
Redis集群通常是主备,primary node负责写入和读取,而slave node只是用来备份。当primary node失败时,slave node有机会被提升为primary node。但是因为primary node和slave node之间是异步传输,因此slave node被提升为primary node后会导致0~N秒的数据丢失。此时Redis的一致性已经被打破,Redis这个模式的集群不是一个CP系统!
CP、AP、CAP解释
要想分析CP和AP两种模式的优缺点,首先要弄懂什么是CAP.
C-Consistency,强一致性。A-Available,可用性。P-Partition tolerance,分区容错性。
在分布式中P是必须要有的,所以分布式有CP和AP两种模式。AP的就是可用性强,一致性弱;CP就是一致性强,可用性弱。你可以把强弱理解成优缺点。
CAP原则又称CAP定理,指的是在一个分布式系统中,一致性(Consistency)、可用性(Availability)、分区容错性(Partition tolerance)。CAP 原则指的是,这三个要素最多只能同时实现两点,不可能三者兼顾。
Redis有一个官方组件叫Sentinel(参考Redis Sentinel,它是通过类似Quorum的方式来连接Sentinel instance,然后检测Redis集群的状态,对故障的primary节点试用slave节点替换。Redis官方号称这个是HA solution,通过Redis Sentinel来构建一个CP系统。
网络分区带来的问题
考虑Redis Sentinel在网络分区时候的情况,这时Redis集群被网络分成两部分,Redis Sentinel在的大区域可能会提升Slave node作为primary node。如果这时候一直client在连接原来的primary node,这时会出现两个primary node(split-brain problem,脑裂问题)!也就是说,Redis Sentinel并没有阻止client连接Old primary node。在此时,已经连接到old primary node的client会写入old primary node,新的client会写入到new primary node。此时,CP系统已经完全瘫痪。虽然Redis集群一直是保持运行的,但是因为依赖于Quorum来提升slave节点,因此它也不会是AP系统。
如果使用Redis作为Lock service,那么这个问题会成为致命问题。这会导致分区后同时可以有两个client获取同一个锁并成功,lock service必须是严格的CP系统,像Zookeeper。
如果使用Redis作为queue,那么你需要接受一个item可能会被分发零次、一次或者两次等等,大部分的分布式队列都保证最多只分发一次或者最少分发一次,CP系统会提确切一次的分发然后带来较高的延迟。你需要明确使用Redis作为队列服务的话必须要接受网络分区后队列服务可能导致的不稳定。
如果使用Redis作为database,那么可想而知,利用Redis Sentinel建立的database是不能称为database的。
最后,以目前的Redis来说,使用官方提供的组件它只能成为Cache。