现在网络上关于 Cassandra 数据库的材料比较少,参阅了 Cassandra 在 2010 年之前的论文和最新的文档,计划写关于 Cassandra 数据库的剖析文章。我将会将原论文进行改写,弥补更多的内容。本文由 ChatGPT 和咱们自己的文本生成模型辅助写作。

我是 Andy.Qin,一个想发明哆啦 A 梦的 Maker,更多好文章能够到我的博客:qin.news

简介

Cassandra 是一个开源的、散布式的、无中心的、弹性可扩展的、高可用的、容错的、一起性可调的、面向行的数据库,它依据 Amazon Dynamo 的散布式规划和 Google Bigtable 的数据模型,由 Facebook 创建,在一些最盛行的网站中得到运用。

Cassandra 能够便利办理散布在许多商业服务器节点上的十分许多的结构化数据,一起供给无单点失效的高可用服务。Cassandra方针是在几百个根底节点上运转(或许散布在不同的数据中心)。在这个规模上,大巨细小的组件常常失效。Cassandra对这些失利耐久状况的办理方法促进软件体系的牢靠性和扩展性依靠这一服务。尽管在许多方面Cassandra类似于一个数据库,而且同享许多规划和相关完成战略,但Cassandra并不支撑完好的联系数据模型;相反,它为客户供给了一个支撑动态控制数据布局而且格局简略数据模型。Cassandra体系规划方针是:运转在廉价商业硬件上,高写入吞吐量处理,一起又不用以献身读取功率为价值。

Facebook 是世界上最大的交际网络渠道,高峰时期有数以万计散布在世界各地的服务器为数百万用户供给服务。Facebook 渠道在功能、牢靠性、功率以及支撑持续增长渠道所需的高扩展性等方面对操作有着严厉的要求。咱们的标准操作模式是在由几千个组件组成的根底设施上进行毛病处理;任何时分都总有一些小型但十分重要的服务器或网络组件会产生毛病。因而,软件体系需求树立处理毛病(在这种情况下毛病是一种常态而非异常)的机制。为了满意上述牢靠性和可扩展性的需求,Facebook 研发了 Cassandra。

相关研讨

散布式数据的功能、可用性和耐受性在文件体系和数据库方面现已得到了广泛的研讨。同仅支撑命名空间的 P2P 存储体系相比,散布式文件体系一般都支撑层级结构命名空间。像 Ficus 和 Coda 之类的体系以献身一起性为价值来获取高可用性。更新抵触一般运用专门的抵触处理流程来进行办理。Farsite 是一个散布式文件体系,没有运用中央服务器,经过仿制来抵达高可用性和扩展性。Google 文件体系(GFS)是另一个散布式文件体系,用来办理 Google 内部运用的托管状况。GFS 运用了一种简略的规划,以一个主服务器来存储一切的元数据,其他数据被分成块存储到各个块服务器上。可是 GFS 主服务器现在运用了 Chubby 笼统来进行容错处理。Bayou 是一个散布式联系数据库体系,答应断开衔接下的操作而且供给终究数据一起性。在这些体系中 Bayou, Coda 和 Ficus 答应断开衔接下的操作而且能够弹性处理网络中止、停电之类的问题。这些体系的抵触处理流程各有不同。例如,Coda 和 Ficus 渠道供给体系等级抵触处理方案,Bayou 供给运用等级的处理方案。一切的这些都是为了确保数据的终究一起性。同这些文件体系相同,Dynamo 即便当网络断开的时分也答应读写操作的持续,而且经过不同抵触处理机制(某些是由客户端驱动的)来处理更新抵触。传统仿制联系数据库的体系专心于确保仿制数据强一起性的问题。尽管强一起性为运用开发者供给了一个便利的编程模型,可是这些体系在扩展性和可用性上却被限制了。这些体系不能够处理网络中止的问题,因为他们一般都供给了强一起性确实保。

Dynamo 是一个 Amazon 的存储体系,用来存储和检索用户的购物车。Dynamo 的 Gossip 依据成员算法来帮助每个节点坚持其他的每个几点的信息。

Dynamo能够界说为在大多数单跳恳求路由的结构化覆盖。Dynamo 运用向量时钟计划用来检测新的抵触,但倾向于一个客户端处理抵触的机制。在 Dynamo 中的一个写操作相同需求读操作进行向量时刻戳的办理。这在体系需求处理高吞吐量的环境中十分受限。Bigtable 供给了结构和数据的散布式,可是依靠于一个散布式文件体系用来做耐久化。

Hbase 是一种依据散布式体系的联系型数据库,而 Cassandra 是一个高功能、牢靠和可扩展的列存储数据库。它们的首要差异在于数据结构和查询处理方法的不同。HBase 上的查询需求经过网络进行散布式的并行核算,而 Cassandra 则运用本地节点之间的消息传递来完成查询任务。

体系架构

Cassandra 依靠于Dynamo 散布式存储键值体系的一些技能。Dynamo体系中的每个节点都有三个首要组成部分:

  • 在分区的数据集上恳求和谐

  • 环状成员和毛病检测

  • 本地耐久化存储引擎

对分区数据集的恳求和谐是指在 Dynamo 体系中,每个节点都担任处理一部分数据,而这些数据是经过哈希函数进行分区的。当客户端发出恳求时,Dynamo 会依据恳求中的键值来确认哪个节点担任处理该恳求,并将恳求转发给相应的节点进行处理。这样,Dynamo 体系就能够经过多个节点协同作业来处理许多的客户端恳求,从而完成高吞吐量和低推迟。

Cassandra首要运用前两个集群组件,一起运用依据日志结构合并树(LSM)的存储引擎。特别地,Cassandra 依据 Dynamo 改进了:

  • 运用一起哈希的数据集分区
  • 运用版别化数据和可调一起性的多主(multi-master)仿制
  • 经过 gossip 协议进行散布式集群成员和毛病检测
  • 商用硬件的增量横向扩展

Cassandra 以这种方法规划,能够满意大规模(PB级数据)要害业务存储要求。

Cassandra 不仅吸收了 Dynamo 论文中的如何做散布式,如何做副本仿制,毛病容错等方面成功的经历,又吸取了 Google Bigtable 中的 LSM 单机引擎层面精华。

本地耐久化

Cassandra 的数据耐久化需求依靠本地文件体系。数据用一种高效读取格局存放在硬盘上。出于耐受性和可恢复性考虑,一般写操作将会涉及到提交日志写入而且更新到一个内存数据结构中。写入内存数据结构仅仅在写入提交日志成功后才会进行。咱们每台机器上都有个专门磁盘用来提交日志,因为一切写入提交日志是接连的,所以能够最大限度的运用磁盘吞吐量。当内存数据结构巨细(依据数据巨细和数量核算得出)超过一定阈值,它将转储到磁盘上。这个写操作是在每台机器装备的许多廉价磁盘中的一个上进行的。一切写入操作写入到磁盘都是有序的,而且生成了一个依据行键可进行快速检索的索引。这些索引一般是数据文件在一起耐久化的。随着时刻的推移,在磁盘上或许会存在许多这样的文件,后台会有一个合并进程将这些文件合并成一个文件。这个进程和 Bigtable 体系中的压缩进程十分相似。

一个典型的读取操作在读取磁盘上文件之前首要将查询内存数据结构。文件是以文件的新旧来进行排序的。当进行磁盘检索时,咱们或许需求检索磁盘上的多个文件的要害字。为了避免查找到不包含要害字的文件,咱们用布隆过滤器来汇总文件中的要害字,它相同也存储在每个数据文件中并常驻内存。(检索时)首要将咨询布隆过滤器来检查查找的要害字是否在给定的文件中。一个列簇中的要害字或许会包含许多列。所以当检索的列间隔键较远时还需求运用一些特殊的索引。为了避免查找时查找磁盘上的每一列,咱们保护列索引来帮组咱们直接跳到磁盘上所取列的正确块上。因为指定键的列现已被序列化并写入到磁盘,所以咱们按照每块 256K 的规模来生成索引。边界的巨细是能够配置的,可是咱们发现在实践产品负载环境下中,256K 巨细作业良好。

数据分区

一起性哈希数据分区

Cassandra 经过运用哈希函数对存储在体系中的一切数据进行分区,完成了横向可扩展性。每个分区都被仿制到多个物理节点上,一般跨过毛病域,如机架甚至数据中心。因为每个副本都能够独立地承受它所具有的每个密钥的骤变,每个密钥都有必要是版别的。在最初的 Dynamo 论文中,确认性的版别和矢量时钟被用来和谐对一个键的并发更新,与此不同的是,Cassandra 运用了一个更简略的最后写入取胜的模型,每个骤变都有时刻戳(包含删去),然后数据的最新版别是 “取胜 “值。从形式上讲,Cassandra 为每条 CQL 行运用一个 Last-Write-Wins Element-Set 无抵触仿制数据类型,或 Conflict-free replicated data type,以处理仿制集上抵触的骤变。

Cassandra 一个重要的规划特性便是持续扩展的才干。这要求动态将数据分区到集群中各个节点(即存储主机)的才干。Cassandra 整个集群上的数据分区用的是一起性哈希,可是运用了保序哈希函数来抵达这一点。在一起性哈希算法中,一个散列函数输出规模被当作一个固定的圆形空间或‘环’来对待(即最大散列值之后为最小散列值)。体系中的每一个节点被赋予一个在这一空间内表示其圆环的方位的随机值。每一个数据项经过键来标识,经过散列数据项的键来确认环上的方位,然后分配到圆环上第一个离大于该条目方位最近的节点。这个节点被视为此键的坐标。运用对此键进行特化处理而且 Cassandra 运用它来进行恳求路由。因而,每个节点只需对圆环上它与前任节点之间的区域担任。一起性哈希最首要的长处是脱离或抵达一个节点只会影响期直接毗连节点,而其他节点不受影响。根底的一起性散列算法面临一些应战。首要,每个节点圆环上随机方位的分配导致数据和负载散布的不均匀。第二,根底算法无视节点功能的不均匀性。一般处理这个问题有两个方法:一个是将一个节点分配给环中多个方位(就像 Dynamo 的做法),第二种便是对环上的负载信息进行剖析,优先路由负载小的节点以减轻负载较重的节点负担。Cassandra 采用后一种方法,因为它能够使得规划和完成易于处理,而且有助于负载均衡做出确认的挑选。

在朴素数据哈希中,一般经过将键的哈希模数除以桶数来将键分配给桶。例如,假如您想运用朴素哈希将数据分发到 100 个节点,则或许将每个节点分配到 0 到 100 之间的一个桶,将输入键模数除以 100,并将数据存储在相关的桶中。可是,在这种朴素方案中,增加一个节点或许会使简直一切映射失效。

Cassandra 则将每个节点映射到接连哈希环上的一个或多个令牌,并经过将键散列到环上然后“沿着”环向一个方向行走来界说一切权,类似于 Chord 算法。一起性哈希与朴素数据哈希的首要差异在于,当要散列到的节点(桶)数量产生改变时,一起性哈希只需移动少数键。

例如,假如咱们有一个具有均匀散布的令牌的8节点集群, 和仿制因子 (RF) 为 3,然后查找键咱们首要对该键进行哈希处理以生成令牌(这仅仅哈希的 key),然后咱们以顺时针的方法“走”环,直到咱们遇到三个不同的节点,此刻咱们现已找到了一切 该密钥的副本。此 8 节点群集示例具有 gRF=3 能够可视化如下:

Cassandra 浅析

物理节点与多个令牌

在 Cassandra 中,每个物理节点能够具有多个令牌,这些令牌在哈希环上占有多个方位。这种方法称为“虚拟节点”,它经过为每个物理节点分配多个令牌来处理不平衡问题。经过答应单个物理节点在环中占有多个方位,咱们能够使小集群看起来更大,因而即便增加单个物理节点,咱们也能够使其看起来像增加了更多节点,从而在增加甚至单个节点时从更多环街坊那里获取更多较小的数据块。

Cassandra 引进了一些术语来处理这些概念:

  • 主机 ID:单个“物理”节点的仅有标识符,一般位于一个 gEndpoint 处并包含一个或多个 gTokens。
  • 虚拟节点(或 vnode):由同一物理节点具有的哈希环上的 gToken,具有相同的 gHost ID。

令牌到端点的映射产生了令牌映射,在其间 Cassandra 盯梢哪些环方位映射到哪些物理端点。例如,鄙人图中,咱们能够经过为每个节点分配两个令牌来表示仅运用 4 个物理节点的 8 个节点集群:

Cassandra 浅析

每个令牌最多引进2 x(rf -1)令牌环上的其他街坊,这意味着节点毛病的组合有更多的组合,咱们在某些令牌环中失去了可用性。您具有的令牌越多,停电的或许性就越高。

整个群集保护操作一般会怠慢速度。例如,随着每个节点的令牌数量的增加,群集有必要增加的离散维修操作数量。

跨过令牌规模的操作的功能或许会受到影响。

请注意,在Cassandra 2.x中,仅有可用的令牌分配算法是挑选随机令牌,这意味着要坚持平衡每个节点的默许令牌数有必要很高,在256处。一起增加了无法获得的风险。这便是为什么在3.x +中增加了新确实认性令牌分配器,该分配器巧妙地挑选令牌,以使环具有最佳平衡,一起需求每个物理节点的令牌数量要少得多。

每个物理节点的多个令牌供给了以下好处:

  • 当增加新节点时,它从环中其他节点承受大约相等数量的数据,从而在整个集群中完成数据均匀散布。
  • 当一个节点被撤销时,它将数据大致均匀地丢掉给环中其他成员,再次坚持整个集群中数据的均匀散布。
  • 假如一个节点不可用,则查询负载(特别是令牌感知查询负载)会均匀地散布到许多其他节点上。

多主仿制

Cassandra 将每个数据分区仿制到集群中的许多节点,以坚持高可用性和耐久性。当产生改变时,和谐器对分区键进行散列以确认数据所属的令牌规模,然后依据Replication Strategy将骤变仿制到该数据的副本。

一切仿制战略都有仿制因子(RF)的概念,它向Cassandra指示分区应该存在多少个副本。例如,运用RF=3keyspace,数据将被写入三个不同的副本。副本总是被挑选为使得它们是不同的物理节点,这经过在需求时越过虚拟节点来完成。仿制战略还能够挑选越过存在于相同毛病域(比如机架或数据中心)中的节点,使得 Cassandra 集群能够忍受整个机架甚至节点的数据中心的毛病。

Cassandra支撑可插拔仿制战略,该战略确认哪些物理节点充当给定令牌规模的副本。数据的每个键空间都有自己的仿制战略。一切生产部署都应运用NetworkTopologyStrategy,而SimpleStrategy仿制战略仅适用于测验尚不了解群集数据中心布局的群集。

NetworkTopologyStrategy需求为群集中的每个数据中心指定仿制因子。即便您的群集只运用单个数据中心,主张运用NetworkTopologyStrategy而不是SimpleStrategy,以便在需求时更容易将新的物理或虚拟数据中心增加到群集。

还有其它十分便利的仿制战略。

数据版别

Cassandra 运用改变时刻戳版别控制来确保数据的终究一起性。详细而言,进入体系的一切改变都是运用从客户端时钟供给的时刻戳来进行的,或许在没有客户端供给的时刻戳的情况下运用从和谐器节点的时钟供给的时刻戳来进行的。更新依据前次写入成功的抵触处理规矩处理。Cassandra 的正确性取决于这些时钟,因而请确保运转正确的时刻同步进程,如 NTP。

Cassandra 将独自的骤变时刻戳运用于 CQL 分区中的每一行的每一列。行经过主键确保是仅有的,而且行中的每一列依据最后写入成功抵触处理方案来处理并发变异。这意味着对分区内不同主键的更新实践上能够在没有抵触的情况下处理!此外,CQL 调集类型(如映射和调集)运用相同的无抵触机制,这意味着映射和调集的并发更新也能够确保处理。

仿制副本同步

因为Cassandra中的副本能够独立地承受改变,因而某些副本或许具有比其他副本更新的数据。Cassandra有许多尽力而为的技能来驱动副本的收敛,包含读取途径中的Replica read repair <read-repair>和写入途径中的Hinted handoff <hints>

可是,这些技能仅仅尽力而为,为了确保终究的一起性,Cassandra完成了anti-entropy repair <repair>,其间副本在其数据集上核算分层哈希树,称为Merkle树,然后能够在副本之间进行比较,以辨认不匹配的数据。像最初的Dynamo论文相同,Cassandra支撑彻底修正,其间副本散列其整个数据集,创建Merkle树,将它们发送给互相并同步任何不匹配的规模。

与原始的 Dynamo 论文不同,Cassandra 还完成了子规模修正和增量修正。子规模修正答应 Cassandra 经过创建仅跨过部分数据规模的许多树来进步哈希树的才干(或许降低到单个分区等级)。增量修正答应 Cassandra 只修正自前次修正以来产生更改的分区。

可调整的一起性

Cassandra 经过一起性等级支撑一起性和可用性之间的每操作权衡。Cassandra 的一起性等级是Dynamo的R + W > N一起性机制的一个版别,其间操作员能够将有必要参与读取(R)和写入(W)的节点数量配置为大于仿制因子(N)。在 Cassandra 中,您能够从通用一起性等级菜单中挑选,这答应操作员在不知道仿制因子的情况下挑选RW行为。一般,当读取一起性等级包含满足的节点以确保与写入一起性等级的仲裁交集时,写入将对后续读取可见。

还答应许多不同的一起性等级。

毛病检测

Cassandra 经过运用 Gossip 来完成散布式集群成员身份和毛病检测。Gossip 是一种用于在散布式体系中传播节点信息的算法。在 Cassandra 中,每个节点都会定时与其他节点通信,以交换关于集群中其他节点的信息。这些信息包含节点的状况(如是否在线)、令牌分配情况以及其他元数据。

当一个节点与其他节点通信时,它会将自己所知道的关于集群中一切节点的信息发送给对方。接收到信息的节点会将其与自己所知道的信息进行比较,并更新自己的信息。这样,每个节点都能够经过与其他节点通信来获取关于集群中一切节点的最新信息。

假如一个节点在一段时刻内未能与其他节点通信,则该节点会被符号为不可用,而且集群中的其他节点会中止将恳求转发给该节点。这样,Cassandra 就能够快速检测到毛病并将恳求从头路由到可用的副本上,从而确保了体系的高可用性。

Gossip 是形成环成员资历的根底,但毛病检测器终究决议节点是UP还是DOWN。Cassandra 中 的每个节点都运转 Phi Accrual Failure Detector 的一个变体,其间每个节点都在不断地独立决议其对等节点是否可用。该决议首要依据接收到的心跳状况。例如,假如一个节点在一定时刻内没有看到来自节点的心跳增加,毛病检测器就会“科罪”该节点,此刻 Cassandra 将中止向其路由读取(写入一般会写入提示)。假如/当节点再次开始心跳时,Cassandra 将尝试联系并衔接,假如它能够翻开通信通道,它将符号该节点为可用。

商业上的扩展不重要,就不写了。

总结

Cassandra 的数据模型与传统的联系型数据库(RDBMS)有很大的不同,它没有固定的表结构,也没有预界说的约束和索引。Cassandra 的数据模型更加灵活和动态,能够依据业务需求随时增加或删去列,也能够支撑杂乱的数据类型,如列表、调集、映射等。可是,这种灵活性也带来了一些缺陷,例如不支撑联合查询、聚合、业务等等。在运用 Cassandra 时,需求依据运用场景进行合理的数据建模,并尽量避免产生许多稀疏或重复的数据。

Cassandra 是一种终究一起性(eventual consistency)的数据库,这意味着在某些情况下,不同节点上或许会存在不同版别的数据副本,而且需求一段时刻才干抵达一起状况。Cassandra 运用时刻戳来处理数据抵触,而且答运用户在读写操作时指定不同等级的一起性要求。例如:

  • 读操作能够指定 ONE、QUORUM、ALL 等等级,表示至少需求从一个、过半数或一切节点读取到最新版别的数据才回来成果。
  • 写操作能够指定 ANY、ONE、QUORUM、ALL 等等级,表示至少需求向一个、过半数或一切节点写入成功才回来成果。

Cassandra 的终究一起性机制与强一起性(strong consistency)的数据库有很大的差异,它能够供给更高的可用性和可扩展性,而且适合处理海量并发恳求。可是,这种机制也带来了一些缺陷像是不能确保实时读取到最新版别的数据,在某些场景下或许会导致业务逻辑出错,等等。

本文正在参加「金石计划」