赞
踩
本篇开始,更进一步到分布式理论层面,通过分布式相关理论学习,可以对后面的各类数据库集群、zookeeper、缓存、消息中间件等打下基础。
可是,分布式理论博大精深并且还在不断发展,系统方向的博士课题也有很多都是在研究分布式的种种问题。分布式的学习,不可避免需要多年积累,不在一朝一夕之间。
尽管分布式涉及点繁杂,但本系列仍然和前面的 mysql 系列一样,定位是由宏观到细节、由浅入深地呈现,目的只有一个,引导。
本系列的知识脉络和本文标题一样,从另一种角度来归纳总结分布式理论体系的知识脉络,大纲导入如下,是一个十分简要的导图。导图的目的本就是有个宏观的印象,而且我们学习肯定是从宏观到细节。所以那种很详细,看起来知识点特别多的导图不会去归纳,没什么用。
在CAP限制下,当P发生时,对CA的权衡不同,会引出分布式事务、一致性和共识,进而又衍生出各种细节内容。
本文也就是对此图的阐述,目标是引领入门,留下宏观映像。
走到这一步,必须推荐一本非常非常非常好的书:《数据密集型应用系统设计》 ,这个节点正好可以看起来,推荐购买纸质书籍,电子版的下篇文章给出地址。
另外,关于分布式的几个基本概念,比如集群、有状态等,建议先回顾 这篇文章。本系列针对的是有状态 ,比如数据库集群、缓存集群、消息中间件集群等。而无状态
服务一般都要和有状态服务结合,才能形成一个完整的系统。无状态服务由于不保存状态,比较简单,不是重点。
个人习惯将所有服务器分为两种:无状态和有状态。有状态的服务器要构建集群,必然涉及到集群间的数据一致性。而无状态构建集群,则不会有一致性的问题。本系列所有文章都是针对有状态
为了避免单机故障而导致整体系统不可用,我们部署会多台服务器来提升系统可用性,每个服务器可以称之为节点。各节点间的数据需要复制,这样当一个节点宕机,由另一个节点继续提供服务时,才不会出现数据不一致的问题。
可是,真的不会出现问题吗?答案当然是否定的。节点之间的复制,是通过网络传输数据。但网络是不可靠的,会存在超时、断线、请求或响应丢失等等情况,或者节点本身崩溃等。
可能发生的事情,在某一个时间点,一定会发生。而我们能做的,就是做好预案,当它发生时,我们该怎么办?
在不可靠的环境上构建可靠的系统,似乎是不可能的。但是 TCP 就构建了可靠的传输,即使 第三层的IP协议层
是不可靠的, TCP协议
仍然在不可靠之上,通过种种方案,建立了可靠传输。
当节点间的网络发生问题时,节点之间无法正常通信,就会形成网络分区
。
当网络分区发生时,我们就面临两难的抉择:
这是著名的 CAP定理
给我们提出的难点,在网络分区(P)发生的情况下,系统只能在 (强)一致性(C)和可用性(A)之间二选一。
to be or not to be, that is the question
这其实就是一道哲学命题,看你怎么权衡。所以,整个分布式系统,可以围绕着 CAP
的权衡而展开,当P发生时,我们如何权衡 C 和 A 的比重。
基于CAP定理,我们来看看分布式事务、一致性、共识。
当P存在时,分布式事务选择的占比为:C=100,A=0。非常极端,直接放弃可用性(当然,有补偿机制可以增加可用性,但是一致性会减弱,后续文章会涉及。本篇都是假设没有补偿机制,直接回滚的情况)。
单机事务中多条语句,一旦有失败的,整个事务都会回滚。分布式事务也一样,一旦某个步骤执行失败,整个事务回滚(或者说对外表现成未发生),保证了ACID属性。
站在一致性的角度,分布式事务关注的是不同有状态系统间的一致性。
比如经典的说法,A系统是工商银行,B系统是建设银行,然后你从工行卡转1000给建行卡。对于A系统来说,会扣除你的工行卡1000余额,对于B系统来说,会增加你的建行卡1000余额。假如B系统的增加失败,那么A系统必须回滚,否则1000块莫名其妙丢失。
这就是所谓的不同有状态系统间的一致性。
那么怎么实现分布式事务,并且尽量提高性能呢?这就关联到后续要学习的2PC,TCC等算法。
当P存在的条件下,兼顾C和A。分布式事务描绘的多个系统间的一致性,而这里的分布式一致性算法则是描绘单个系统内部节点之间的一致性。随着 C 和 A 的倾斜不同,也出现了多样的分布式一致性算法。
想要可用性,那么节点间数据复制不能少。节点间的数据复制分为三种:
主从复制的核心点在于,写请求只能主节点进行,而从节点只提供读请求。典型结构如下:
因为P发生时,兼顾CA,所以不同场景下会出现不同程度的一致性问题。但最关键的问题是,主节点挂掉后,我们该怎么办?当然可以人工将主节点恢复。但是我们更希望能够朝自动化方向进行,这就会引出共识算法。
主主复制的核心是系统中存在多个主节点,每个主节点都可以进行写入。现在常见的文档协作或者手机APP的离线查看都属于此类场景。典型结构如下:
最关键的问题是,主主复制的过程中,如果出现写冲突的场景,该如何处理?比如不同地区的用户都在编辑同一行数据,则此冲突如何处理。这个问题就是后续研究主主复制的重点。
无主复制的核心是大家都平等,谁都可以进行读写操作。典型结构如下:
这里存在三个重要问题:
针对第一点,要和主主复制一起讨论。
针对第二点,数据的不一致修复,主要涉及到两种形式:读时修复和反熵。以及一种有效的算法:gossip算法。
针对第三点,就会引出常见的 Quorum机制,该算法可以灵活调整 C 和 A 的比例。简单列子:三个节点,任意向其中一个节点写数据,然后读取的时候,系统内部会同时读取这三个节点的数据,通过比对后,返回最新的数据给客户端。
主从复制中提到了,当主节点挂掉后,我想自动切换新的主节点怎么办?这就涉及到了共识算法(还有另外的实现方式,比如利用VIP漂移等),利用共识算法实现节点间新主节点的选举,可以实现自动切换。
而对于主主复制和无主复制来说,共识算法所能提供的一致性保证更好。
常见共识算法有:Paxos、Raft、Zab等。关键是当P发生时,他们如何进行选举,如何处理脑裂等,这些是研究的重点。
进一步理解共识算法的选举等实现,重要的两点是理解全序关系广播
和可线性化
。
但是共识算法缺点是需要大多数节点的正常。
多说一句,假如是强AP系统,那么当P发生时,想尽量保证A的同时(比如只有1个节点,系统也能正常运行),又能实现最终一致性。这时同样可以利用 gossip协议 来实现。
以下放几个推荐的,作为补充阅读
更多后端文章详见:后端开发教程系列-java向
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。