聊聊分布式存储——问题与矛盾

本文将介绍分布式存储相关内容。关于分布式存储的内容将从不同的角度和主题分为多篇文章完成,这是第一篇并没有复杂的技术和概念,算是前言或当成一篇了解分布式存储的科普文也是不错的。

网上关于分布式存储的文章有很多,但大部分都是罗列概念或者知识点过于分散,看了很多却“只见树木,不见森林”,学了很多往往只能“知其然,却不能知其所以然”。所以想写一篇文章,将这些内容串联起来,目的在于搞清楚知识点之间的来龙去脉。

那么该如何“串联”呢?

答案就像上面这句一样:提出问题。带着问题,发散、深入,先了解整体思路,最后深入感兴趣的细节。

我们总会遇到问题,为了解决问题会通过思考或实践总结出很多结论和方法,它们可能是某个定义,某种理论,一套技术工具,一些方案等。这些内容就是我们需要学习的所谓的“知识点”。所以学习知识的基本思路是先搞清楚我们遇到了什么问题,然后才去了解有哪些理论,技术,方案是可以解决这些问题的。因此本文的重点不在于罗列出所有的知识点和定义,而是希望通过问题与答案的因果关系,帮助读者对分布式存储涉及的知识点形成一个完整的知识图谱。

全文的基本思路如下(非目录):

》为什么需要分布式
    》为什么需要分布式存储
        》分布式存储带来什么问题与挑战
            》如何解决
                》解决过程中衍生了哪些知识点
                    》这些知识点在工程中又是如何使用和体现

一个问题

什么叫问题?问题就是事物的矛盾。哪里有没有解决的矛盾,哪里就有问题。——毛泽东

在开始讨论分布式存储之前,先来思考一下“分布式”这三个字:为什么需要分布式?

我想先用一个成语来回答,曰:逼上梁山。

虽然答案有点“皮”,但“货真价实,童叟无欺”——我们的确是被迫使用分布式的,因为我们的用户太多了,服务器和应用程序扛不住了,用王大锤的话形容就是“要死啦,要死啦,要死啦”。如果可以的话,请记住:坚决不要分布。根据“皇室定律”:皇帝每多娶一个老婆,后宫就平添无数险恶。(“熵越高则混乱度越高”)—— 每增加一个分布节点(程序,数据等)系统的复杂度都会成倍增加,稳定性也更容易被破坏。

既然如此,为什么总想着三妻四妾…是爱么?是责任么?不,是高性能高可用

虽然复杂度和混乱度增加了,但总是可以通过其他技术手段来管理。但通过分布式,能提升核心业务的性能和稳定。简单解释一下:当我们把鸡蛋放在不同的篮子里,减轻被一锅端的风险时——这就是通过分布式来提升稳定性。当我们在售票窗口买票时,如果只开一个窗口,那么将会排很长很久的队,整体等待很长时间。但如果能多开几个窗口就可以提升售票效率——这就是利用分布式来提升性能。

不难发现,分布式的目的就在于追求高性能与高可用这两个特性。我们学习分布式系统时,遇到的各种理论、技术以及设计方案,其本质上就是为了解决这两个关键性问题而已。

在想清楚了这个观点之后,那所谓的分布式也并没有这么高大上,深不可测。它无非是提出一些技术方法来解决遇到的一堆问题,我们只需顺着这个思路各个击破即可。

一对矛盾

矛盾是事物发展的源泉和动力。 ——唯物辩证法

高性能与高可用是矛盾的,等下再来解释这个关系。

分布式主要可以分为分布式计算和分布式存储,这里主要关心后者,还是先思考两个问题:为什么需要“分布式存储”?分布式存储会带来什么问题与挑战?

如果老板很高兴,说明网站业务快速发展,数据量和访问量快速增长。但此时数据库的压力越来越大,我们需要对其减压,有哪些减压思路?

《大型网站系统与JAVA中间件实践》第五章第一节第二小段给出了三个减压思路:

1.优化应用,即业务层的优化,通过优化业务设计,流程来改善对数据的依赖。

2.引入性能中间件,看看那有没有其他办法来降低对数据库的压力,如引入缓存,搜索引擎等。

3.对数据和访问进行拆分,分散访问,分散数据,降低单点压力。

【注】:单机优化不在此文范围,如连接优化(连接池),索引策略等。

事实上,前两个思路是一致的,可以总结为一个原则:阻止过多的访问数据库(尽量少访问数据库)。不使用它,当然可以减少它的压力,但无论如何减少访问,大量的数据库访问依然在所难免,主要原因有:

1.缓存的创建和重建需要依赖数据库。

2.对数据库的写操作,不容易引入缓存策略。

所以采用“拆分”是一个很重要的选择。

减压是为了提升性能,而另一方面,我们还要追求高可用。这方面常用的思路有“主从复制”,“读写分离”等。

说到这里,我们可以看到不管是为了高性能进行数据库拆分还是为了高可用而采取的主从复制,这些方案都会将我们的数据存储变成分布式结构。但问题来了,分布式结构可以为我们带来了高性能和高可用,但这两者往往难以完美统一,共同达成:比如我们要设计一个分布式存储系统,出于对性能的考虑,记录数据时先写一个份数据到某个机器上并立即返回,然后异步发起多个数据备份过程(副本)。这种设计的性能最好,但存在“容错性”的风险,即写完数据后,目标机器立即发生故障,会导致数据丢失!如果同时写多个副本,每个副本写成功以后再返回,则又导致性能下降,因为这个过程取决于最慢的那台机器的性能。这就是高性能与高可用之间的矛盾。

除了两者之间的矛盾,分布式存储还带来的其它问题与挑战,其中主要有两点:拆分导致的问题与事务问题。这里简单的介绍一下,因为后面很多知识点与这些问题有关(为解决这些问题而出现):

1.拆分导致的问题

数据拆分主要有两种方式水平拆分和垂直拆分:

    水平拆分:根据一定规则将同一业务单元拆分到多个数据库中

    垂直拆分:不同业务单元的数据分到不同数据

这两种拆分方式或多或少的都会带来如下影响:

(1)单机的ACID被打破了。数据到了多机后,原来在单机通过事务来进行的处理逻辑会受到很大的影响。我们面临的选择是,要么放弃原来的单机事务,修改实现,要么引入分布式事务。

(2)多表的关联查询如何进行。一些Join操作会变得比较困难,因为数据可能已经在两个数据库中了,所以不能很方便地利用数据库自身的Join了,需要应用或者其他方式来解决。

(3)无法使用外键约束。

(4)依赖单库的自增序列生成唯一ID会受影响。

2.事务问题

分布式存储不再直接提供事务支持。我们需要事务的原因在于需要通过事务保证“数据一致性”。换句话说,如果数据不一致了,那么当我们使用数据时,则会得到不可信,不可靠,不可用的结果,这不是我们希望发生的情况。

当然,除了上面提到的两个问题之外还有一些其他问题,比如:通信异常,网络分区,三态,节点故障等。

总结一下:

1.对高性能和高可用的追求,导致我们的数据变成了分布式存储。

2.高性能与高可用又是相互关联和矛盾的。在追求高性能的时候,会影响了高可用的实现。当我们通过某些方式实现了高可用时,又需要通过各种方案和技术来保证高性能。

综上,我们无法避免分布式存储,但分布式存储又是不可靠的,这就是问题与挑战,是我们需要面对和解决的。搞清楚了这些问题,我们就可以顺理成章的带着这些问题开始学习那些为解决些问题而出现的各个“知识点”了。

一些知识点

世界观决定方法论,方法论体现世界观。 ——马克思主义

这都是知识点啊,同志们,还不快记! ——脱口秀“艺术家”池子

上文提到了在分布式存储在追求高性能和高可用之间有一种“剪不断,理还乱”的矛盾。为解决矛盾衍生出了很多理论,如:ACID,分布式事务,CAP,BASE,一致性协议。下面将试着理清楚这些概念的作用和关系。

还是一开始提到的,这里不是介绍具体的概念,而是为了能理解这些知识点为何而来,了解他们有何作用。

ACID与事务

ACID是四个单词的缩写:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)。它们是事务需要具备的四个特征。

我们知道,数据库的操作往往离不开“事务”。为什么需要使用事务?主要有两个作用:

1.当多个应用程序并发访问数据库时,事务可有在这些访问之间提供一个隔离方法,防止彼此操作互相影响。

2.事务为数据库操作提供了一个从失败中恢复到正常状态的方法。

简而言之:事务的主要作用是为了保证“数据的一致性”,也就是保证数据的“高可用”。

通过实践和研究发现,为了达到这个目的,事务需要具备一些特点,这些必备的特点就是ACID。换就话说,只要满足了ACID这四个特性,就能满足事务的需求,就能满足“高可用”的要求。

关于事务和ACID的详细讲解可以参考下面这篇文章,这里我们只关心它的作用。

《拨开云雾见天日:剖析单机事务原理》

分布式事务

在单机数据库中,我们很容易实现能满足ACID的事务处理系统。但进入到分布式领域后,数据分散在不同的机器上,如何对这些数据进行分布式的事务处理就具有非常大的挑战了。

为了保证分布式应用的可靠性,依然需要实现事务的特性。分布式事务和单机事务不同。单机事务可以理解为一种技术,但分布式事务应该理解为一种概念。分布式事务需要我们主动的去实现,比如下面将提到的CAP和BASE理论就与此相关。

CAP与BASE

如果我们期望实现一套严格满足ACID特性的分布式事务,很可能出现的情况就是在系统的可用性和严格一致性之间出现冲突——因为当我们要求分布式系统具有严格一致性时,很可能就需要牺牲掉系统的可用性。但毋庸置疑的一点是,可用性又是一个所有消费者不允许我们讨价还价的系统属性,比如说像淘宝网这样的在线购物网站,就要求它能够7×24小时不间断地对外提供服务。而对于一致性,则更加是所有消费者对于一个软件系统的刚需。因此,在可用性和一致性之间永远无法存在一个两全其美的方案,于是如何构建一个兼顾可用性和一致性的分布式系统成为了无数工程师探讨的难题,并出现了诸如CAP和BASE这样的分布式经典理论。

之前我们提到分布式存储带来了分布式事务问题,我们可以”狭隘”的认为,CAP和BASE是为了解决分布式事务问题而给出的理论方案。

还是需要简单了解下CAP和BASE是什么:

1.CAP理论是指:一个分布式系统不可能同时满足一致性(C:Consistency),可用性(A:Availability),分区容错性(P:Partition tolerance)这三个基本需求,最多只能满足其中两项。

2.BASE理论是基本可用(Basically Available),软状态(Soft state)和最终一致性(Eventually consistent)的简称。

我们很容易记住这两个单词以及定义,但可能并没理解透彻,甚至可能误认为是并列的两个概念,其实不然。

我对这两个理论的理解总结为一句话:CAP提出了问题(论证了问题),而BASE给出了解决思路(实现方案)。也就是说CAP的作用是告诉了我们一个结论::说我们无法做到什么。然后BASE告诉我们在CAP的情况下该如何做,如何做到兼顾平衡。

理解了上面这段句话,再回头关心学习CAP是什么,BASE又是如何实现的才会明晰他们的意义。

拓展:建议看下这篇文章,了解一下CAP为什么不可同时达成。

《分布式系统的CAP理论》

一致性协议

我们注意到CAP和BASE理论都重点突出了一个关键词“一致性”。尤其是BASE理论提出“通过牺牲强一致性来获得可用性,并允许数据在一段时间内是不一致的,但最终达到一致性”。

如何详细了解了两个理论的内容,就会知道这样一个思想:在满足可用性的情况下,尽量改善“不一致性”。

所以,分布式存储问题的重点聚焦在了如何满足“一致性”这个问题上。也由此又发散衍生出了N多理论,如2PC,3PC,Paxos,Raft等。此时,我们同样无需详细了解每个算法的细节,我们只要记住:这些算法产生的原因和目的——为了解决(改善)“数据一致性”问题。

至此,介绍了一些主要的学术性的知识点。我们看到,分布式系统带来分布式问题,分布式问题产生解决方案,这些方案有概念,有理论,有算法。理解这些是基础,在了解了这些概念之后,回归到实际问题解决上,就相对从容了。

这篇文章偏理论理解,下面在《聊聊分布式存储(二)》中将介绍在实际工程中,我们会遇到的那些具体的分布式存储的业务问题,我们一般如何解决这些问题,如何实践这些理论,体会有哪些方法应用了这些理论。

参考文献

《大型网站系统与Java中间件实践》

《架构解密》

《从Paxos到Zookeeper》

分享到:

1 条评论

昵称
  1. Pingback: 聊聊分布式存储——图解Paxos | 7player