Apache Cassandra的建立是为了结合Dynamo[1]和Big Table[2]论文的各个方面,并创造一种方法来简化数据的读取和写入方式,这样它就可以处理正在创建的数据量。通过保持简单,Cassandra减少了读写开销的复杂性,使其更容易扩展和分配数据。
存储附加索引(SAI)是一个新项目,为Cassandra提供二级索引,同时消除了以前的一些问题。这应该会使大规模查询Cassandra中的数据更加容易,同时也会减少每个集群的磁盘存储需求。
目前Cassandra中二级索引的方法
作为一个分布式数据库,Cassandra可以提供令人难以置信的规模,但它也需要一些经验,即如何在开始时为你的数据建模。然后,数据库索引建立在这个最初的数据模型上,以扩展你的查询,使其更有效率。然而,这种方法必须随着时间的推移而调整。为了跟上新的用例和部署模式,我们必须看看Cassandra是如何处理数据索引的,然后考虑新的方法来减少这种可用性和稳定性之间的权衡。
索引的最终目标是改善你读取数据的方式。然而,你在开始时围绕如何写数据所做的决定也会影响你围绕索引所能做的事情。如果你被优化为快速写入–就像你在Cassandra中那样–增加的复杂性会对你管理索引的方式产生负面影响,并因此影响你的性能。因此,值得一看的是,在一个Cassanda数据库集群中,数据是如何被写入一个节点的**(图1**)。
图1:Cassandra数据库集群中的数据处理
Cassandra是基于日志结构化合并(LSM)树[3]的方法,其中预计会有大量的数据插入。这是一种常见的方法,也被其他数据库如HBase、InfluxDB和RocksDB使用。通过收集写入的数据,然后在预先排序的数据运行中提供给他们,可以保持快速的写入速度,并组织数据进行分发。一个事务是这样工作的。
- 每个事务将验证数据的格式是否正确,并对照现有的模式进行检查。
- 然后,事务数据将被写入提交日志的尾部,把它放在文件指针的下一个位置上。
- 然后,数据被写入一个memtable,这是内存中模式的哈希图。
每个事务–在Cassandra术语中称为突变–在这些事情发生时被确认。这与其他数据库不同,其他数据库在一个特定的点上设置锁,然后寻求执行写入,这可能需要额外的时间来完成每个交易。
内存表是基于物理内存的–当这些内存填满时,其中的数据会在磁盘上一次性写出来,到一个叫做SSTable(分类字符串表)的文件中。一旦SSTable容纳了这些持久化数据,提交日志就会被删除,这个过程又开始了。在Cassandra中,SSTable是不可改变的。随着时间的推移,随着更多的数据被写入,一个叫做压实的后台进程会将SSTable合并并排序为新的SSTable,这些SSTable也是不可变的。
以往索引的问题
Cassandra目前围绕数据索引的方法没有很好地跟上用户需求。对于许多用户来说,实现目前的索引所涉及的权衡是如此的繁琐,以至于他们完全避免使用索引。这意味着许多目前的Cassandra用户只使用基本的数据模型和查询,以获得最佳性能,因此错过了他们数据中存在的一些潜力,如果他们能够更有效地建模和索引的话。
在Cassandra的世界里,分区键是一个唯一的键,作为主索引,用来寻找Cassandra集群中的数据位置。Cassandra使用分区键来识别哪个节点存储了所需的数据,然后识别存储该分区数据的数据文件。
在像Cassandra这样的分布式系统中,列值存在于每个数据节点上。任何查询都必须发送到集群中的每个节点,数据被搜索、收集,然后被合并。一旦结果被合并,该查询的结果就会返回给用户。在这种情况下,性能就取决于每个节点找到列值并返回该信息的速度。
Cassandra有两种二级索引的实现方式。Storage Attached Secondary Indexing(SASI)和Secondary Indexes。虽然这些实现对其特定的使用情况有效,但它们并不适合所有的情况。作为一个项目,我们不断处理的两个主要问题是写入放大和磁盘上的索引大小。了解这些痛点对于理解我们为什么需要一个新的方案非常重要。
二级索引一开始是作为使用Thrift的早期数据模型的一个便利功能。后来Thrift被Cassandra查询语言(CQL)取代,二级索引功能被 “CREATE INDEX “语法所保留。虽然这使得创建二级索引成为可能,但它也通过在事务路径中增加一个新的步骤而导致了写放大。当索引列发生突变时,这将触发一个索引操作,在一个单独的索引文件中重新索引数据。
这反过来又会极大地增加单行写操作的磁盘活动。当一个节点正在进行大量的突变时–而这正是Cassandra建立的目的–这会迅速导致磁盘的饱和,然后影响整个集群。这也使得提前规划磁盘空间变得更加困难,因为数据的增长将更难预测。
另一种方法是存储附加二级索引(SASI)。SASI最初是为了解决一个特定的查询问题,而不是二级索引的一般问题。它通过在部分数据匹配的基础上寻找行来做到这一点。通配符,或LIKE查询,或对稀疏数据如时间戳的范围查询。
SASI查看了提交给Cassandra节点的突变,数据在最初写入时将在内存中建立索引,这与memtables的使用方式很相似。这意味着每次突变都不需要磁盘活动,这对于有大量写活动的集群是一个巨大的改进。当memtables被刷新到SSTables时,数据的相应索引也被刷新。当压缩发生时,数据被重新索引,并在新的SSTables创建时被写入一个新文件。从磁盘活动的角度来看,这是一个重大改进。
SASI的问题是,这些额外的索引需要大量的磁盘存储来覆盖每一列的索引。对于那些管理Cassandra集群的人来说,这是一个非常令人头痛的问题。SASI也是由一个团队拼凑起来的东西,发布后并没有什么进一步的改进。当SASI中的错误被发现时,修复的费用也很高。
存储附加索引和二级索引
为了改善Cassandra的二级索引,需要在以前的实施中吸取的教训的基础上采取新的方法。Storage Attached Indexing(SAI)是一个新项目,它解决了写放大和索引文件大小的问题,同时也使创建和运行更复杂的查询变得更容易。
SASI在使用内存索引和用SSTables冲刷索引方面有正确的方法。因此,SAI在突变完全提交时对数据进行索引。通过优化和大量的测试,对写入性能的影响有了极大的改善。因此,与以前的二级索引方法相比,这应该提供40%的吞吐量和超过200%的写延迟。
SAI还根据数据类型使用两种不同的索引方案来处理磁盘存储量的问题。第一种是使用基于Trie[4]的文本索引,它使用倒置的索引和分成字典的术语。这提供了更好的压缩率,因此也提供了更小的索引六。对于数值,SAI使用了一种基于Lucene的块状kd-trees[5]的方法,以提高范围查询的性能,用一个单独的行ID列表来优化标记顺序查询。
仅仅看一下索引存储,在体积上与表索引的数量相比有很大的改进。为了比较二级索引、SASI和SAI,我们进行了一些基准测试,以显示针对磁盘存储的性能水平。正如你在图2中所看到的,当你扩展索引数据时,用于SASI的磁盘容量会大量增加。
图2:SAI、SASI和传统2i方法的比较
在写入放大和索引大小之外,SAI还可以在未来进一步扩展,以符合Cassandra项目在未来构建中更多模块化发展的目标。SAI现在被列为Cassandra增强进程的CEP-7[6],讨论的是如何有可能将其纳入Apache Cassandra的4.x分支中。在那之前,你可以通过一些免费的在线培训[7]了解更多关于如何使用SAI的信息。
SAI代表了两件事:首先,这是一个很好的机会,可以帮助Cassandra用户创建二级索引,并改善他们如何大规模地运行查询。其次,这也是我们DataStax如何跟进我们的计划,增加对社区的贡献并以代码为主导的一个例子。通过使Cassandra更容易使用,这使Cassandra对每个人都更好。
链接和文献
[1] www.allthingsdistributed.com/files/amazo…
[2] static.googleusercontent.com/media/resea…
[3] en.wikipedia.org/wiki/Log-st…
[4] en.wikipedia.org/wiki/Trie
[5] users.cs.duke.edu/~pankaj/pub…
[6] cwiki.apache.org/confluence/…
[7] www.datastax.com/dev/cassand…
The postCloud-native applications and data with Kubernetes and Apache Cassandra – Part 2appeared first onDevOps Conference.