分布式系统的完整介绍(二)

分布式系统的类别

接下来我们将逐个分析几个分布式系统的类别,并且列举外界已知的在生产环境中它们最大的使用规模。注意,当你读到这篇文章的时候,下面提到的数字很可能已经过时了,并且很可能已经变的更大了。

1. 分布式数据存储

分布式存储的应用最为广泛,被称为分布式数据库。大部分的分布式数据库是NoSQL非关系型数据库,限于使用键值对的语义。它们以一致性和可用性为代价换来了令人难以置信的性能和伸缩性。

已知规模:在2015年的时候,苹果公司使用75000个Apache Cassandra节点存储了10字节(1拍字节=250次方字节)的数据。

讨论分布式数据存储免不了得先介绍一下CAP定理。

CAP定理

早在2002年CAP定理就被证明了,CAP定理指出分布式的数据存储不能同时满足一致性(Consistency),可用性(Availability)和分区容忍性(Partition Tolerance)。可以选择三者中的两个,但是不能是一致性和可用性。

上图中可以三选二,但是不能同时选取一致性和可用性。

一些简单的定义:

  • 一致性– 按次序读到的和写入的数据和预期是一样的(还记得前面“主从数据库复制”策略的缺陷吧)
  • 可用性– 整个系统不会挂掉– 每个没有挂掉的节点总是能返回结果
  • 分区容忍性– 当发生网络分裂的时候系统依然工作并且保证一致性/可用性。

在实际情况中,分区容忍性对于分布式存储是必需的。你不能够在没有分区容忍性的情况下获得一致性和可用性。

想一下,如果你有两个接受数据的节点并且节点之间的连接挂了,两个节点怎么样可以做到都可用并且保证数据的一致性?它们没有办法知道彼此在做什么,所以它们要么连不上(不可用)要么只能提供老的数据(不一致)。如图:

最终,你将面临在网络分裂的情况下选择强一致性还是可用性。

实践表明,对大部分的应用来说,可用性的价值更大。强一致性并不总是必需的。甚至可以说,取“可用性”而舍“强一致性”,主要并不是因为你需要100%的可用性保证,更多是因为由强一致性造成的网络延时是一个很大的问题。为了获得强一致性,机器间不得不同步数据,这会造成网络延时。这些原因以及其他一些因素使得应用程序倾向于选择高可用性的方案。

这样的数据库最终选择了最弱的一致性模型– 最终一致性(可以搜索了解强一致性和最终一致性相关的解释)。这个模型保证如果一个数据项再没有被更改,最终所有对该数据项的访问都将返回最近更改的值。

那些系统提供BASE属性(相较于关系型数据库的ACID)

  • 基本可用(Basically Available)– 系统总是返回结果
  • 软状态(Soft state)– 随着时间的推移,即时没有输入(更改),系统状态也可能发生变化(因为最终一致性)
  • 最终一致性(Eventual consistency)– 当没有输入(更改)的时候,数据迟早会扩散到每一个节点,从而达到一致的状态

这样的分布式数据库的产品有– Cassandra,Riak,Voldemort。

当然,也有倾向于强一致性的分布式数据存储产品– Hbase,Couchbase,Redis,ZooKeeper。

CAP定理本身值得写文章单独阐述,已经有一些文章存在,有些讨论如何根据客户端的行为调整系统的CAP属性,有些讨论为什么CAP没有被恰当的理解。

Cassandra

Cassandra像前面提到的那样是一个分布式的NO-SQL数据库,它倾向于CAP属性中的AP,使用最终一致性。我必须承认,这有一点儿误导,因为Cassandra具有很强的配置功能,你可以以放弃高可用性为代价来使它提供强一致性,但是这不是它最常用的方式。

Cassandra使用一致性哈希算法(consistent hashing)来决定集群中的哪一个节点来处理你传入的数据。同时你需要设置一个复制因子,这个因子主要用来指定你想复制数据到多少个节点。

下图是一个写数据的例子:

读数据的时候,你只会从那些复制的节点读取。

Cassandra的伸缩性非常强,可以为写操作提供相当高的吞吐量。

下图展示了每秒写入数据的基准:

尽管这个图可能有些不公平,因为看起来我们让Cassandra和一些设置了提供强一致性的数据库进行比较(图中MongoDB的节点从4个增加为8个的时候,性能反而下降了,这应该是因为MongoDB提供强一致性导致的),但是这个图还是能够展示出进行适当配置过的Cassandra的能力。

无论如何,在使得分布式系统获得高伸缩性和令人难以置信的高吞吐量的权衡中,Cassandra并没有提供类似于ACID数据库的一些基本功能– 比如事务处理

共识

数据库事务在分布式系统中的实现非常复杂,因为需要每个节点同意接下来的正确的行动(终止还是提交事务)。这被称作“共识”,这是分布式系统的一个基础性的问题。

如果参与的进程和网络环境完全可靠,达成是否提交事务的共识是很简单直接的一件事情。然而,现实中的系统可能会有很多种情况的失败,比如说进程崩溃,网络分裂,丢失,失真或者重复消息等。

这会产生问题– 已经被证明,在不可靠的网络环境中,是无法保证在给定的时间段内达成正确的共识的。

但是,在实践中有一些算法可以使得在不可靠的网络环境中非常快的达成共识。Cassandra实际上提供了轻量级的事务,它是通过使用为达成分布式共识的Paxos算法来实现的。

2. 分布式计算

分布式计算是最近这些年大数据处理大量涌现的关键。分布式技术可以把单一机器不可能完成的巨大任务(比如聚合1000亿条记录)拆分成很多普通机器就可以完成的小任务。你把巨大的任务拆分成很多小任务,在多台机器上同时执行他们,合理的进行聚合,从而解决你最初的问题。这种方式同时使得你获得横向伸缩的能力– 当你有一个更巨大的任务的时候,可以简单的增加更多的节点进行计算。

已知规模– Folding@Home(可以在维基百科中查询)项目,在2012年的时候就有160,000台在线的机器。

在这个领域中谷歌是比较早的一个创造者,因为他们需要为分布式系统发明一种新的范式来处理海量的数据– MapReduce。谷歌在2004年发表了一篇相关的论文,基于此论文开源社区在之后创建了Apache Hadoop。

MapReduce

MapReduce可以简单的定义为两步– 映射(map)数据和规约(reduce)映射的结果为有意义的数据。

我们举例说明一下。

假设我们是一个媒体企业,我们在作为数据仓库的次级分布式数据库中存储了海量的信息。我们想获得从2017年4月开始每天的点赞次数。

这个例子很简单也很清楚,但是想象一下面对的海量数据(假设有数十亿级的点赞数)。我们显然不会把所有的信息存放在一台机器上,并且我们也不会只用一台机器做数据分析。我们也不会直接访问生产环境的数据库,而是访问专门为低优先级的离线任务创建的数据仓库。

每一个Map job运行在一个单独的节点上,转换尽量多的数据。每一个任务遍历给定存储节点中的数据,把它们映射(map)成一个元组,每个元组包含日期和数字1。接下来,会完成三个中间步骤(很少有人提及)-- 打乱,排序和分片。这些步骤基本上是用来进一步的安排数据把它们代理给合适的Reduce job。因为我们在处理海量的数据,我们为每一个日期都创建一个单独的Reduce job来处理。

这是一个好范式,令人诧异的是它可以让你做更多的事情,比如你可以把多个MapReduce串联在一起。

更好的技术

现今,MapReduce有点儿过时了,并且它自身也有一些问题。因为它是多个job同时工作,当你的job失败的时候问题就来了– 你需要重做所有的事情。一个需要两小时的job的失败可以拖慢你的整个数据处理流水线,你至少不愿意这样,尤其是在高峰时间。

另外一个问题是直到你获得数据所要等待的时间。在实时分析系统中(大多具有海量数据,因而使用分布式计算),数据尽可能的保持最新是非常重要的,几个小时以前的数据是不能接受的。

因此,为了解决这些问题,其他架构出现了。即Lambda架构(批处理和流式处理的混合)和Kappa架构(只是流式处理)。一些新的工具使得这些新的架构得以实现– Kafka Streams,Apache Spark,Apache Storm,Apache Samza。

3. 分布式文件系统

分布式文件系统可以被认为是分布式数据存储。从概念上讲,它们是一回事儿– 从看起来像一台机器的机器集群中存储和访问海量数据。它们经常和分布式计算联系在一起。

已知规模– 雅虎在2011年的时候在多于42,000个节点上运行着HDFS,保存了600PB的数据。

维基百科定义分布式文件系统的区别为它允许文件以和本地文件相同的接口和语义进行访问,而不是通过定制化的API,比如Cassandra Query Language(CQL)进行访问。

HDFS

HDFS(Hadoop Distributed File System)是基于Hadoop框架的分布式计算系统使用的分布式文件系统。它被广泛的采用,可以跨机器存储和备份大文件(GB或TB大小)。

它的架构主要包括“名字节点”和“数据节点”。名字节点用以保存集群的元数据,比如哪个节点存储了哪些文件块。它们通过判断哪里存储和备份文件最好,跟踪系统的健康状况,扮演了网络协调者的角色。数据节点只是简单的存储文件和执行命令,比如备份文件,写新文件等等。

HDFS最适合于Hadoop计算,因为它为计算任务提供了数据的可知性。计算任务可以在存储数据的节点上运行。这充分利用了数据所在的机器,优化了计算并且减少了网络上的数据传输。

IPFS

星际文件系统(Interplanetary File System)是分布式文件系统中的一个令人兴奋的新的点对点协议/网络。通过区块链技术,它可以构建出没有单一拥有者和单点失败的完全去中心化的架构。

IPFS提供名称系统(和DNS很像)称作IPNS,使得用户可以很容易的访问信息。它保存文件的历史版本,就像Git一样。这允许访问文件以前的状态。

尽管IPFS还在紧锣密鼓的开发过程中(写文章的时候是v0.4),但是已经有项目使用它了(FileCoin)。

4. 分布式消息

消息系统为你的整个系统提供了存储和传播消息/时间的中心。它使你可以对程序直接和其他系统对话进行解耦。

已知规模—LinkedIn的Kafka集群每天处理1万亿的消息,高峰时间每秒钟处理4500,000的消息

简单的说,消息平台工作方式如下:

一个消息被程序(此程序也可能是消息的创建者)广播出去(此程序被称为生产者),进入到消息平台然后被感兴趣的程序(可能有多个)读取(这些程序被称为消费者)。

如果你需要保存一个消息到多个地方(比如创建用户到数据库,数据仓库,邮件服务和其它你能想到的地方),消息平台是最干净的方式。

消费者可以从消息中间件拉取信息(拉模式)或者使消息中间件直接推送信息(推模式)。

有几个出色的消息平台:

RabbitMQ—消息中间件,允许你通过路由规则或者其它容易配置的设置对消息的传递轨迹进行精细的控制。可以被称为智能的中间件,因为它有很多的逻辑,并且它紧密的跟踪传递的消息。提供CAP理论中对AP和CP的设置。通知消费者的时候使用推模式。

Kafka—消息中间件,有一点儿靠近底层,因为它不会跟踪记录哪些消息被读取了,并且不能设置复杂的路由逻辑。这使得它获得了惊人的性能。我认为在开源社区的开发和Confluent组的支持下这是它最有前途的地方。Kafka可能是顶级技术公司中被最广泛使用的。我还写了一篇Kafka全面的介绍,在文章中我详细叙述了它所有的优点。

Apache ActiveMQ—最老的消息平台,可以追溯到2004年。使用JMS API,意味着是面向Java EE程序的。它被重写为了ActiveMQ Artemis,性能很出色,可以达到Kafka同等的水平。

Amazon SQS—AWS提供的消息服务。让你可以快速和已有程序进行集成,并且不需要搭建自己的基础设施,这可能是一个很大的好处,因为众所周知Kafka一类的系统搭建起来很棘手。Amazon也提供了两个类似的服务—SNS和MQ,后者其实就是ActiveMQ只不过被Amazon所托管。

5. 分布式应用

如果你在一个负载均衡服务器后面连接着5台服务器,这5台服务器都连接到1个数据库上,你能称这个为分布式应用吗?回忆一下我前面的定义。

如果你认为数据库只是用来共享的状态,你可以争辩说这可以划分为分布式系统– 但是你错了,你已经忽略了定义中“一起工作”的部分。

一个系统只有当节点之间的交互是为了协调动作才算是分布式的。

因此,在点对点(P2P)网络中运行后端代码的应用最好被划分为分布式应用。尽管这种分类没有什么意义,但是可以表明分类时会受到多少干扰。

已知规模– 2014年4月的时候对冰封王座游戏的下载有19300个节点的种源池。

Erlang虚拟机

Erlang是一个函数式编程语言,具有非常棒的对于并发,分布式和容错的的语义。Erlang虚拟机自身处理Erlang程序的分布。

它的模型使用很多隔离的轻量级的进程,这些进程之间通过可以进行消息传递的内建系统来相互通信。这被称作Actor模型,Erlang的OTP库可以被认为是分布式的Actor库(同时还有JVM中的Akka)。

这个模型使得它可以非常简单的实现并发– 这些进程可以分布在运行系统可用的核上。由于这种模式和网络非常相像(除了网络可以作废消息),Erlang虚拟机可以连接到同一个数据中心甚至是其他州的Erlang虚拟机。这个虚拟机群执行一个应用程序,可以通过接管的方式(安排另一个节点执行)处理机器的失败。

实际上,Erlang语言添加了分布层以提供容错。运行在单一机器上的软件总是会有宕机从而使应用不可用的风险。运行在多个节点上的软件,硬件错误处理将会变得简单。

BitTorrent

BT下载工具也是一个分布式应用的例子。

6. 分布式分类账

分布式分类账可以理解为不可更改,只能追加数据的数据库,这个数据库在分布式网络中被复制,同步和共享。

它利用事件源模式(Event Sourcing),允许你在任何时间重建分类账的历史状态

区块链

区块链是分布式分类账底层使用的技术,并且是它开始的标志。这个在分布式领域新近的伟大的创新创造了第一个真正意义上的分布式支付协议-比特币。

区块链是一个分布式分类账,它携带了在它的网络中发生的所有的交易的序列。交易被分组保存在区块上。整个区块链实际上是一个区块的链表。所谓的区块需要大量的计算,并且通过加密算法和其他的区块相关联。

简单的说,每一个区块包含一个对当前区块内容(内容是默克尔树)的特殊哈希(以n个0开头)加上前一个区块的哈希。这个哈希需要非常多的CPU运算产生,因为唯一产生它的方式就是暴力破解的方式。

矿工就是计算这些哈希的节点。矿工们会生成可以和区块内容一起创建出前面提到的哈希的随机字符串,这个过程中矿工们会相互竞争。一旦某个矿工发现了此字符串,它将会把它广播到整个网络。字符串会被每一个节点验证,从而被接受到它们的链中。

这意味着区块链是一个修改起来非常耗时,但验证没有被篡改却非常容易的系统。

修改区块的内容开销非常大,因为这需要生成一个新的哈希。记住一点,每一个后续的区块都依赖于它。如果你想修改第一个区块中的交易,你将会修改默克尔树的根。这将会修改区块的哈希,进而依次修改后续区块的哈希。这意味着你需要为修改的以及后续的每个区块暴力计算新的随机字符串。

网络总是信任和复制最长的有效链。为了欺骗系统和最终产生一个更长的区块链,你需要网络节点中一半以上的CPU的运算能力。

区块链可以被认为是一种对出现的事物达成共识的一种机制。共识并不是显示达成的,当共识达成时并没有选举或者固定的时间。相反,共识是成千上万的独立节点,按照协议规则,异步地交互的结果。

这个史无前例的创造最近变成了一个技术热点,有人预言它将会是Web 3.0创建的标志。它无疑是当下最让软件领域激动的热点,当然它也充满了非常困难和有趣的问题等着人们去解决。

比特币

前面的分布式支付协议缺少的是如何以分布式的方式实时地避免重复花费问题。研究产生了很多有趣的建议,但是比特币是第一个实际实现了的比其他有明显优势的方式。

重复花费问题表述为一个角色(例如,张三)不能在两个地方花费他的一个资源。如果张三有一元钱,他不能同时把这一元钱给李四和王五。事实表明在分布式系统中实现它非常的困难。有一些方法早于区块链,但是它们不能在现实中完全解决这个问题。

重复花费可以被比特币简单地解决,只要一次只添加一个区块到区块链。重复花费在同一个区块不可能发生,因此即使两个区块同时产生,也只有一个会被最终添加到最长的链上。

比特币依赖于获取CPU计算能力的困难度上。

在投票系统上,攻击者只需要添加节点到网络,这很容易,因为自由访问是网络设计的目标。在以CPU运算能力为基础的方式上,攻击者需要面对物理的限制:获得越来越多的强大的硬件。

这样,攻击者想要成功,就需要控制网络上大于50%的计算能力。少于50%,其他节点将会更快地创建更长的区块链。

以太坊

以太坊可以理解为可编程的基于区块链的软件平台。它有自己的加密货币(乙醚),可以作为在区块链中部署智能契约的燃料。

智能契约是存储在以太坊区块链中的一段事物代码。要运行这段代码,只要发起一个以智能契约为目标的事务。这将会使挖矿的节点执行代码和做出相应变化。代码是在以太坊的虚拟机上执行的。

Solidity是以太坊的原生编程语言,可用来写智能契约。它是一个图灵完备的编程语言,直接以以太坊区块链为接口,允许你查询状态,比如平衡或者其他智能契约结果。为了避免无限循环,执行代码需要一定量的乙醚。

由于区块链可以解释为一系列的状态变化,许多的分布式应用建立在了以太坊或者类似的平台之上。

分布式分类账更深层应用

存在证明– 一个服务,可以匿名地和安全地保存一个数字文档曾在某个时刻存在过的证据。用于保证文档的完整性,拥有者和时间戳。

去中心化的自治机构–使用区块链来对改进建议达成共识的机构。

去中心化的验证– 在区块链中保存身份信息,使你可以在任何地方使用单次登录(SSO)。

还有其他很多,分布式分类账技术打开了无尽的可能。

总结:

在文章中,我们进行了分布式的定义,对每一个类别进行了描述。需要记住的一些点有:

  • 分布式系统是复杂的
  • 选择分布式是因为规模和代价
  • 分布式的相关工作很难
  • CAP理论– 一致性和可用性之间的权衡
  • 有六个类别– 数据存储,计算,文件系统,消息系统,分类账,应用

坦率地讲,我们仅仅是讲了分布式系统最表面的东西。我并没有全面的处理和解释核心的问题,比如:共识,复制策略,事件顺序和时间,容错,在网络中广播消息和其他。

注意:

让我在最后给你提一个预先的警告:

你必须尽可能的远离分布式系统。如果你可以用其他的方式解决问题,分布式系统带来的复杂程度不值得你付出的努力。

英文原文:

https://hackernoon.com/a-thorough-introduction-to-distributed-systems-3b91562c9b3c

猜你喜欢

转载自www.cnblogs.com/yufengzhang/p/10557429.html
今日推荐