1.简介
在本教程中,我们将了解分布式系统的基础。本文将介绍它们的基本特性以及它们所带来的挑战以及常见的解决方案。
我们还将简要介绍一些跨多个类别的流行分布式系统采用的方法。
2.基本概念
在了解不同系统的分布式体系结构之前,让我们首先清除一些基础知识。
尽管动机在很大程度上影响了分布式体系结构,但仍有一些基本原理和挑战适用于所有这些。
2.1。什么是分布式系统
因此,让我们从正式定义一个分布式系统开始。分布式系统由可能跨越地理边界的多个组件组成,这些组件通过消息传递来传达和协调其动作。对于该系统外部的参与者,它看起来好像是单个连贯系统:
现在,我们可能经常听到有关分散式系统的信息,并将它们与分布式系统混淆。因此,必须区别对待。分散系统是分布式系统,其中没有特定的组件拥有决策权。尽管每个组成部分都拥有决策的一部分,但它们都不具有完整的信息。因此,任何决定的结果都取决于所有组成部分之间的某种共识。
与分布式系统密切相关的另一个术语是并行系统。虽然这两个术语均指扩大计算能力,但它们实现它们的方式却有所不同。在并行计算中,我们在一台计算机上使用多个处理器来同时执行多个任务(可能使用共享内存)。但是,在分布式计算中,我们使用没有共享内存且与消息传递进行通信的多个自治机器。
2.2。分布式系统的好处
尽管分布式系统的设计和构建肯定更加复杂,但它可以带来它们带来的好处。
让我们快速了解一些关键优势:
- 可扩展性:垂直扩展通常受硬件限制的限制,例如,我们只能有这么多的处理器内核。但是,从理论上讲,我们可以使用相对便宜的商品机器实现无限的水平缩放。
- 可靠性:由于分布式系统由多台计算机组成,并且数据在多个节点上复制,因此它对于系统部分故障通常更具弹性。因此,即使容量降低,整个系统仍将继续运行。
- 性能:分布式计算的典型应用程序通过将工作负载分解为可以同时在多台计算机上运行的较小部分来进行工作。因此,这极大地提高了许多复杂工作负载的性能,例如矩阵乘法。
2.3。分布式系统中的挑战
如果我们认为我们能够在没有任何挑战的情况下获得分布式系统的所有好处,那么我们离现实还差得远!
让我们了解一下分布式系统给我们带来的一些关键挑战:
- 一致性与可用性:由于分布式系统按定义具有分区容限,因此必须在CAP定理的约束下在一致性还是可用性之间进行选择。对于通用计算平台而言,这并非易事。
- 数据分发:分布式系统中的数据或工作负载需要分区才能将其发送到多个节点。这引起了对复杂算法进行有效划分并随后组合它们的需求。
- 协调:由于分布式系统中的数据或工作负载也跨多个节点进行复制以实现容错功能,因此协调它们非常棘手。参与节点需要复杂的协议来达成决策。
通常在企业应用程序中,我们需要在一个事务下进行多个操作。例如,我们可能需要作为单个工作单元对数据进行多次更新。虽然在数据共置时这变得不那么重要,但是当我们在节点集群上分配数据时,它变得相当复杂。许多系统确实使用诸如Paxos和Raft之类的复杂协议在分布式环境中提供诸如语义之类的事务。
3.建筑与类别
尽管近来对分布式系统的兴趣重新兴起,但基本原理并不新鲜。相当长一段时间以来,分布式系统已经看到了许多体系结构模式来解决与数据相关的特定用例的泛型。
在本节中,我们将讨论分布式系统的一些架构模式以及它们可以服务的不同类别的用例。
3.1。分布式系统架构
分布式系统的系统架构取决于用例和我们对它的期望。但是,在大多数情况下,我们可以找到一些常规模式。
实际上,这些是该体系结构采用的核心分发模型:
- 主从:在此模型中,分布式系统的一个节点扮演主角色。在此,主节点具有有关系统的完整信息并控制决策。其余节点充当临时节点并执行主节点分配给它们的任务。此外,出于容错目的,主节点可以具有冗余备用数据库。
- 对等:在此模型中,在分布式系统的节点之间没有指定单个主服务器。所有节点均平等地承担主节点的责任。因此,我们也将其称为多主模型或无主模型。以增加复杂性和通信开销为代价,此模型提供了更好的系统弹性。
虽然这两种体系结构都有各自的优缺点,但不必只选择一种。实际上,许多分布式系统都创建了将两个模型的元素结合在一起的体系结构。
对等模型可以提供数据分发,而主从模型可以在同一体系结构中提供数据复制。
3.2。分布式系统类别
设计分布式系统可能有多种理由。例如,我们需要在机器学习模型中大规模执行诸如矩阵乘法之类的计算。这些不可能容纳在一台机器上。
同样,处理大型文件并将其处理并存储在单台计算机上的系统可能是不可能的,或者至少效率很低。
因此,根据用例,我们可以将分布式系统大致分为以下几类。但是,这绝对不是分布式系统可能用例的详尽列表:
- 资料储存库
- 讯息传递
- 计算机运算
- 分类帐
- 文件系统
- 应用领域
传统上,相当长一段时间以来,关系数据库是数据存储的默认选择。但是,随着最近数据量,种类和速度的增长,关系数据库开始达不到预期。这就是NoSQL数据库及其分布式体系结构开始被证明更有用的地方。
同样,传统的消息传递系统也无法与现代数据规模的挑战保持隔离。因此,对可以提供性能,可伸缩性以及可能的耐用性的分布式消息传递系统的需求开始上升。如今,该领域中有几种选项可以提供多种语义,例如发布-订阅和点对点。
在本教程中,我们将讨论一些流行的分布式数据库和消息传递系统。重点将主要放在通用体系结构上,以及它们如何解决分布式系统的一些关键挑战,例如分区和协调。
4. Apache Cassandra
Cassandra是采用分布式宽列存储模型的开源,分布式键值系统。它具有完整的多主数据复制功能,可提供高可用性和低延迟。它具有线性扩展能力,没有单点故障。
Cassandra支持高可用性和可伸缩性,因此是最终一致的数据库。从本质上讲,这意味着对数据的所有更新最终将到达所有副本。但是,相同数据的不同版本可以暂时存在。但是,Cassandra还以一致性级别列表的形式提供可调的一致性,供读取和写入操作选择。
4.1。资料分配
Cassandra通过在集群中的节点之间平均划分所有数据来提供水平扩展。在集群上分布数据的一种简单方法是使用分布式哈希表。但是,如果群集中的节点数发生更改,它们通常会遭受重新哈希处理。这是一致哈希证明更好的地方,因此由Cassandra使用。
一致性哈希是一种分布式哈希方案,与群集中的节点数无关。它具有抽象环的概念,该环代表哈希值的总范围,也称为令牌:
Cassandra将群集中的每个节点映射到此令牌环上的一个或多个令牌,以便总令牌范围均匀地分布在群集中。因此,每个节点在此环中都拥有一系列令牌,具体取决于我们在令牌中放置令牌的位置。
为了确定密钥的所有权,Cassandra首先通过哈希密钥来生成令牌。它使用分区程序作为哈希函数,Murmur3Partitioner是默认的分区程序。一旦它在环上找到了密钥的令牌,它就会沿顺时针方向移动环以识别拥有令牌并因此拥有密钥的最近节点。
现在,Cassandra还可以跨多个物理节点复制每个分区,以提供容错能力。它支持可插拔复制策略(如Siple策略和网络拓扑策略),以确定哪些节点充当给定令牌范围的副本。对于简单策略,它只是一直走下去,直到找到由复制因子(RF)定义的不同节点的数量。
4.2。协调
由于Cassandra集群是多主机集群,因此集群中的每个节点都可以独立接受读取和写入操作。接收到请求的节点充当应用程序的代理。我们称代理节点为协调器,并负责使用分区器识别拥有密钥的节点。
因此,每个节点都需要知道集群中哪些节点处于活动状态或死亡状态,以最佳地路由操作。 Cassandra使用Gossip协议在群集中传播基本的群集引导信息:
闲话是一种对等通信协议,其中每个节点定期与其他几个节点交换状态信息。他们交换有关自己以及他们知道的其他节点的信息。此外,它使用矢量时钟对信息进行版本控制,以便八卦可以忽略群集状态的旧版本。
多主机体系结构的另一个问题是多个副本可以同时接受相同的密钥更改请求。因此,必须有一种机制可以协调副本集上的并发更新。
Cassandra使用Last-Write-Wins模型来解决此问题。为简化起见,在这里,每个突变都带有时间戳记,而最新版本总是胜出。
5. MongoDB
MongoDB是一个开源的,通用的,基于文档的分布式数据库,将数据存储为文档的集合。文档是由字段和值对组成的简单数据结构。此外,它还提供用于复杂数据建模的嵌入式文档和数组。
我们可以将MongoDB分片部署为副本集。副本集的主要成员处理所有请求。在自动故障转移期间,分片通常仍然无法处理请求。默认情况下,这使MongoDB高度一致。但是,为了获得高可用性,客户端可以选择从二级复制副本中读取,在该副本中,数据最终只会保持一致。
5.1。资料分配
MongoDB使用分片键在多个分片中分布集合中的文档。我们可以从文档中的一个或多个字段创建分片键。显然,分片密钥的选择暗含了分片集群的性能,效率和可伸缩性。
MongoDB使用分片键将数据划分为多个块。它试图在集群中的所有分片上实现块的均匀分布:
MongoDB支持两种分片策略,即哈希分片和范围分片。使用散列分片,它可以计算分片键值的散列,并为每个块分配一定范围的散列值。使用远程分片,MongoDB根据分片键值将数据划分为多个范围,并为每个块分配一个范围。
平衡分片之间的块分布也很重要。 MongoDB中的默认块大小为64 MB。当数据块超过指定的大小限制或文档数超过配置的限制时,MongoDB会根据分片键值拆分数据块。此外,MongoDB运行平衡器过程,该过程自动在碎片之间迁移块以实现均匀分配。
为了提高数据的局部性,MongoDB提供了区域的概念。当分片跨越多个数据中心时,这特别有用。在分片群集中,我们可以基于分片键创建区域。此外,我们可以将每个区域与集群中的一个或多个分片相关联。因此,MongoDB将仅将区域覆盖的块迁移到与该区域关联的碎片。
5.2。协调
MongoDB使用分片作为在多台计算机之间分配数据的方法。因此,MongoDB的分片集群可水平扩展。分片包含数据的子集,每个分片都可以作为副本集部署。集群还包括mongos,查询路由器和用于存储元数据和配置设置的配置服务器:
副本集在MongoDB中提供自动故障转移和数据冗余。正如我们在上面看到的,副本集是一组维护相同数据集的mongod实例。主数据库通过将所有写入操作记录在其称为oplog的操作日志中来处理所有写入操作。然后,辅助服务器异步复制主服务器的操作日志。
当主要节点在配置的时间内未与辅助节点进行通信时,合格的辅助节点可以通过选举来提名自己为新的主要节点。除了主要的和次要的,我们还可以有其他mongod实例(称为仲裁器),它参与选举但不保存数据。群集尝试完成新主数据库的选择。
这确实为MongoDB中的数据丢失留出了空间,但是我们可以通过选择适当的写入关注点来将其最小化。写关注是我们从MongoDB请求的确认级别。对“多数”的关注是指我们要求确认该写操作已传播到计算出的大多数含数据投票成员。
6. Redis
Redis是一个开源数据结构存储,我们可以将其用作数据库,缓存甚至消息代理。它支持各种类型的数据结构,例如字符串,列表,映射等。它主要是具有可选持久性的内存键值存储。
Redis使用主从结构(从站是主站的精确副本)提供高可用性。主节点接受来自客户端的写请求。它还进一步将写入异步复制到从属节点。但是,客户端可以使用WAIT命令请求同步复制。因此,Redis优先考虑可用性和性能,而不是强一致性。
6.1。资料分配
Redis将数据划分为多个实例,以受益于水平缩放。它提供了几种替代的数据分区机制,包括范围分区和哈希分区。现在,范围分区很简单,但是使用起来不是很有效。相反,散列分区被证明效率更高。
哈希分区的基本前提很简单。我们可以获取密钥,并使用任何标准的哈希函数(例如CRC32)来生成密钥的哈希,而哈希只是一个数字。然后,我们对散列执行模运算,以获得可以在其上映射此键的实例。显然,这有一定的局限性,即一致的哈希性能更好。
现在,可以在Redis的软件堆栈的不同部分进行分区。从客户端开始,一些Redis客户端实现客户端分区。然后,我们进行了基于代理的分区,其中像Twemproxy这样的代理处理了分区:
在这里,Redis Sentinel通过在实例或分片内提供自动故障转移来提供高可用性。最后,我们还可以使用查询路由,其中集群中的任何随机实例都可以通过将请求路由到正确的节点来处理请求。
Redis Cluster允许自动分区和高可用性,因此是实现此目标的首选方法。它混合使用查询路由和客户端分区。 Redis集群使用分片的形式,其中每个键都是哈希槽的一部分。 Redis群集中有16384个哈希槽,每个节点负责其中的一个子集。
6.2。协调
Redis Cluster是Redis的分布式实现,具有高性能目标,线性可伸缩性,高可用性和可接受的写入安全性。它遵循一个主动-被动体系结构,该体系结构由多个主机和从机组成:
Redis集群中的节点负责保存数据,将密钥映射到正确的节点,检测集群中的其他节点,并在需要时提升从属节点进行主控。为了完成所有这些任务, Redis群集中的每个节点都通过TCP总线和称为Redis群集总线的二进制协议进行连接。此外,节点使用八卦协议传播有关群集的信息。
由于Redis Cluster使用异步复制,因此需要提供合理的写安全性以防止出现故障。 Redis Cluster使用上一个故障转移胜出隐式合并功能。这意味着最后选举的主数据集最终将替换所有其他副本。当在分区期间可能丢失写操作时,这会留下一小段时间。但是, Redis会尽最大努力保留客户端连接到大多数master时执行的写操作。
Redis Cluster不会将命令代理到正确的节点。相反,它们将客户端重定向到服务于键空间给定部分的正确节点。客户端可以自由地向所有群集节点发送请求,并在需要时进行重定向。但是,最终,客户端会收到有关群集的最新信息,并可以直接联系正确的节点。
7. Apache Kafka
Kafka是一个开放源代码平台,旨在提供统一的,高吞吐量,低延迟的系统来处理实时数据馈送。它使我们能够发布和订阅事件流,持久而可靠地存储事件流,并在事件发生或追溯时处理事件流。
为了增强耐用性和可用性,Kafka通过自动故障转移跨多个节点复制数据。仅当所有in-sync-replicas使用完该事件后,该事件才被视为已提交。而且,只有承诺的使用者才能接收消息。因此, Kafka的设计具有高度的一致性和可用性,可以使用许多配置。
7.1。资料分配
Kafka组织并持久存储主题中的事件。生产者是将事件发布到主题的应用程序,消费者是从主题中订阅事件的应用程序。我们可以将每个主题划分为一个或多个分区,并将它们分布在不同的节点上以实现可伸缩性。这也允许多个使用者并行地从一个主题读取数据:
从生产者的角度来看,这里的分区很简单,一个提交日志以追加模式工作。分区中的每个事件都有一个称为偏移的标识符,该标识符唯一地标识事件在提交日志中的位置。此外,Kafka将主题中的事件保留一段可配置的时间。
生产者可以控制将事件发布到哪个分区。它可以是可用分区之间的随机负载平衡,也可以使用某些语义分区功能。我们可以定义一个分区键,Kafka可以使用该键将事件散列到固定的分区。这导致事件在分区中的局部性,这可能对消费者很重要。
消费者可以选择从任何偏移点读取事件。 Kafka中的使用者组在逻辑上将多个使用者分组,以负载均衡某个主题分区的消耗。 Kafka仅将主题分区分配给使用者组中的一个使用者。当组中使用者的数量发生变化时,Kafka会自动尝试重新平衡使用者之间的分区分配。
7.2。协调
Kafka群集通常由多个服务器组成,这些服务器可以跨越多个数据中心或云区域。它们使用高性能的TCP网络协议相互通信,并与客户端通信。我们将保存数据作为主题分区的服务器称为代理。每个经纪人拥有几个分区。
此外,Kafka使用ZooKeeper来存储元数据,例如分区的位置和主题的配置:
如我们所见,Kafka还跨可配置数量的代理复制每个主题分区的日志。所有对主题的写入和读取都通过分区的负责人。领导者协调以使用新数据更新副本。万一领导者发生故障,其中一个副本将通过自动故障转移来接管领导者的角色。
如果Kafka可以维持与ZooKeeper的会话并且不会落后于领导者,那么它会将副本定义为同步副本(ISR)。直到所有in-sync-replicas都收到write,才认为对Kafka的写已落实。此外,只有同步副本集中的成员才有资格被选举为领导者。因此,Kafka可以忍受除一个同步副本之外的所有故障,而不会丢失已提交的数据。
根据我们配置和使用Kafka客户端的方式,我们可以实现不同的消息传递语义。例如,最多一次,至少一次或恰好一次。在生产者端,我们可以通过配置生产者的acks
属性和代理的min.insync.replica
属性来实现不同的交付语义。同样,在消费者方面,我们可以使用enable.auto.commit
配置来控制传递语义。
8. CAP定理的一个注记
埃里克·布鲁尔(Eric Brewer)提出了CAP定理,以根据它可以保证的属性定义对分布式系统的约束。基本上,这意味着分布式系统不能同时提供以下三个保证中的两个以上:
- 一致性:每次读取都会收到最近的写入或错误
- 可用性:每次读取都会收到非错误响应,即使它不是最近的写入也是如此
- 分区容限:即使部分网络出现故障,系统仍可继续运行
在上面,我们可以看到CAP定理如何被用作对分布式系统进行分类的指导性星!但是,这种分类通常过于简单,可能会被误导,并且在某种程度上也不必要。
现在,在分布式系统中几乎不可能完全消除网络分区的可能性。因此,基本上,CAP定理的含义可以归结为在一致性或可用性之间进行权衡。因此,一个声称是分布式的系统和CA必须对其运行所在的网络抱有坚定的信念。
但是,正如我们在前面讨论的几个分布式系统的上下文中所看到的那样,这确实不是一个容易的选择。因此,大多数这些系统在配置中提供了很多控制,因此我们可以选择行为作为标准要求。因此,将这些系统简单地分类为CP或AP几乎是不公平甚至不正确的。
9.结论
在本教程中,我们介绍了分布式系统的基础知识,并了解了主要的好处和挑战。此外,我们对跨数据存储和消息传递系统的一些流行的分布式系统进行了广泛的评估。
我们强调了它们如何在分布式体系结构中实现数据分发和协调。
0 评论