Cassandra + JSON?答案就是Stargate Documents API

2020年11月23日 阅读数:5
这篇文章主要向大家介绍Cassandra + JSON?答案就是Stargate Documents API,主要内容包括基础应用、实用技巧、原理机制等方面,希望对大家有所帮助。

JSON已经被开发者在不少场景中频繁使用,可是其实将Cassandra用于JSON或其余面向文档的用例并不容易。前端

 

为了让开发者在使用原生的JSON的同时还能享受Cassandra带来的可靠性和伸缩性,咱们开发了Stargate Cassandra Documents API——它使得绝大多数的Cassandra发行版本都能经过一个REST API使用JSON。git


 

若是你像我同样,当你开始编写一些新应用程序时,你可能会发现你本身在使用JSON。也许你正在使用Node.js或Python或任何其余动态编程语言(dynamic programming language),这些语言原生的数据格式正巧与JSON相似;或者你正使用从REST API中拉取的数据。 程序员

不管是哪一种状况,愈来愈多的状况是全部的新应用程序都会在某个点与JSON汇合。大多数时候这不是个问题,这只是咱们现在建构软件的方式而已。然而有一个问题——Cassandra其实不是特别擅长处理JSON……github

若是深刻了解一下,你会知道问题并不在于JSON这种数据格式自己,虽然Cassandra并无让JSON变得更易于使用;问题在于大多数程序员在建构程序时使用JSON的方式。数据库

迭代开发意味着计划常常会改变。好比用户注册表格须要一些新的条目,前端开发人员就率先加入了这些条目。当咱们使用这个API时,就会有一些额外的数据被返回。欢迎来到这个松耦合(loosely coupled)的世界,全部的一切都是开心和有趣的——直到个人应用程序须要把这些数据发送到数据库。编程

其实早期的Cassandra版本要作到这件事很容易,可是随着这个项目逐渐成熟,像是对企业友好的类SQL查询语言以及更好的索引等功能被加入以后,意味着咱们须要Cassandra数据库要有一个固定的模式(schema)。逐渐地,将Cassandra用于相似JSON的事情或其余面向文档的用例变得愈来愈困难。后端

 

进入Stargate(意为“星际之门”)——若是你只需知道一件关于Stargate团队的事情,那应该就是:咱们的我的使命是让Cassandra变得对于每一个开发人员来讲都易于使用。想办法让Javascript的开发者在使用原生的JSON的同时还能享受Cassandra带来的可靠性和伸缩性——这是一个咱们不能错过的挑战。数组

也正是这个想法催生了Stargate Documents API——它使得绝大多数的Cassandra发行版本(Cassandra 3.11, Cassandra 4.0, and DataStax Enterprise 6.8)都能经过一个REST API使用JSON。数据结构

 

01 Stargate Documents API的特色和设计并发

当咱们刚开始构建这个API的框架时,咱们意识到Cassandra彻底不像是一个文档数据库。

表达一行一行的数据是很是直观简单的,可是表达树状结构的JSON数据就没那么容易了。另外若是还想作到将JSON数据映射到Stargate管理的数据库表,并保证读取和写入的速度还保持在至关快的水准,这就更是复杂了。

基于这些,为了可以达成目标,咱们详细计划了三个主要的设计考量:基于Cassandra的文档建模、高效处理读写请求,以及合理处理删除操做。

接下来,这篇文章将介绍咱们是如何构想每个设计以及解决遇到的一些小问题的。

 

02 基于文档切分(Document Shredding)在Cassandra中进行文档建模

咱们要决定的第一件事就是管理基于文档集合(document collection)的数据库表的模式(schema)。在与几位Cassandra专家进行了有建设性的讨论后,咱们决定当用户建立一个文档,就会用下面的语句建立一个相应的数据库表:

create table <name> (
  key text,
  p0 text,
  … p[N] text,
  bool_value boolean,
  txt_value text,
  dbl_value double,
  leaf text
)

 

到这里,咱们得要解决长度无上限的数据模型带来的问题。由于全部有[N]或更少深度的JSON文档均可以被加入到这个表中,JSON中的每个值将会在表中存储为一行。因此若是我想表示一个叫作“x”的含有JSON的文档:

{"a": { "b": 1 }, "c": 2}

 

这个文档将会被“切分”成像这样的行:

  

对于包含数组(array)的数据,好比:

{"a": { "b": 1 }, "c": [{"d": 2}]}

 

就会被拆分红这样的两行:

 

数组元素在存储时,会在一列中被方括号括起来。

 

03 高效处理读写请求

下一个出现的问题是:想要更新一个文档,天然而然就要先从数据库中读取已有的文档,看看要对其作些什么改变,而后再写入更新的数据。 

对大多数数据存储来讲,这个“写前读(read-before-write)”的过程是臭名昭著的影响性能和一致性的问题的根源。所以,咱们决心要不惜一切避免任何“写前读”的操做。

有一个具体的实现细节颇有意思——当你向文档写入一些数据时,这个写入操做其实只是一个包含了一些插入操做和删除操做的简单的批处理。在某些状况下,这会致使文档在数据库中对应的行针对同一个JSON数据域,可能会显示出两种不一样的状态。

而后,当这些行都被读取出来以后,Stargate的Cassandra Documents API就会选取写入时间戳比较新的数据,从而调和冲突的信息(这和Cassandra自己的原理很相似)。

这让咱们的写入操做变得很快,同时没必要在读取操做方面牺牲太多——由于前面所说的这种须要冲突调和的状况并很少见,即便出现,也会很快被解决。对于咱们基础的读写操做,这也奠基了很是重要的核心原则:

  • 每个向一个单独的文档所作的写入操做,都是一个单独的、含有多个语句的批处理。

  • 每个向一个单独的文档所作的读取操做,都是一个单独的SELECT语句。 

读操做和写操做都准备就绪了,那删除操做呢?

 

04 合理处理删除

因为Cassandra数据库自己的分布式属性,在Cassandra中作删除操做其实与插入操做很相似。不过删除操做所作的,是在特定的写入时间经过写入“tombstone(墓碑)”来标志一行数据的死亡。

入土为安吧……等等,事情其实还没结束——

Cassandra会周期性地作压实(compaction)操做(这个频率取决于你的压实策略和/或集群负载),从而删除墓碑并释放压力。因此避免让Cassandra过载的惟一方法就是确保删除操做的频率足够的低。

因为数组的存在,删除操做给Stargate的Cassandra Documents API带来了一个问题。如今让咱们来谈谈这点。

想象一下,若是你有一个行,其中的某个单元是一个长度为十万个元素的数组。而后若是你进行一个更新操做(经过HTTP中的PUT方法)并决定给这个单元赋值为一个新的数组。结果就是整个十万行的数据都要被删除,也就是说整整十万个墓碑要被写入系统。 

这么多墓碑在一次操做中被写入,其数量至关之大。若是你再多这么操做几回,Cassandra极可能会变得很是之慢。因此,咱们还须要对每一个表的数据结构再作一次大的调整。

 

咱们前面提到过,存在数据库中的数组访问路径(array path)是带方括号的。好比数组序列为0的元素会被存储为[0]。这将意味着像下面这样删除100,000个元素:

DELETE FROM <name> where p0 in ('[0]', '[1]', '[2]', …, '[99999]')

这就致使了100,000个墓碑将被写入。

 

相比这么作,咱们决定向全部的数组元素的开头都充填多个0——也就是说索引序号为0的元素会被记做[000000],而索引序号为99999的元素会被表示记做[099999]。经过这种方式,咱们能够将删除语句改为这样:

DELETE FROM <name> where p0 >= '[000000]' and p0 <= '[999999]'

相比100,000个单元的墓碑,这种方式会使得只有一个所谓的“区间”墓碑(range tombstone)会被写入(提示:在Cassandra中,大于号和小于号能够依照字典顺序做用于字符串类型的数据)。这也将数组长度限制放宽至一百万个元素,这可真是至关巧妙!

 

下方的时间序列图显示了在你以每周一次的频率作压实操做的前提下,旧方法和新方法的效果对比:

 

05 简单了解此API的性能

⚠️在开始这个部分以前,咱们想先提一下:虽然基准测试是很是好的工具,但并不是能绝对说明一个系统在天然条件和真实负载下的表现。另外,咱们也还没在同一硬件上,将拥有此API加成的Cassandra与其它文档数据库进行对比……是的,尚未。好吧,让咱们如今就来看看它的性能!

为了测试咱们的Cassandra Documents API是否足够的快,咱们用一个单独的Cassandra存储节点和一个单独的Stargate节点进行了一次基准测试(Stargate是包含了Cassandra Documents API的API)。

而后咱们进行了两个不一样的基准测试,一个用HTTP GET重复地在一个文档中随机获取路径,另外一个用HTTP POST重复地建立新的文档。这两个操做都分别进行了100,000次,下面的图中展现了此次测试的结果。

 

简单来讲,因为如今并无能够用于对比的基准数据,此次基准测试中分为这样三种状况:一次只有一个用户、稍微多一些并发操做(一次10个用户)、更多的并发操做(一次100个用户)。

 

需注意,此处咱们在后端只有一个节点,更多的并发操做会引发性能的退化(degradation in performance)。若是想要承载更高程度的并发请求,你应该使用多个节点。

下面的是读操做的测试结果:

下面的是写操做的测试结果:

 

从上面的结果中,咱们能够看到在咱们设置的必定程度上的并发操做下,Stargate的Cassandra Documents API表现至关不错。

 

06 结束语

咱们但愿你享受这篇对于Stargate Cassandra Documents API的快速介绍。若是你对使用这个API有兴趣,不妨点击文末“阅读原文”前往Stargate.io查看更多相关信息,看看如何将这个API用在你本身的Cassandra系统中。

 

来加入咱们的Discord Community,你能够在此获取Stargate的最新动态,而且最早使用Stargate的新功能

https://discord.com/invite/5gY8GDB

 

若是你有任何问题或是想要提交任何代码,来看看咱们的GitHub仓库吧

https://github.com/stargate/stargate

 

Stargate的Cassandra Documents API正在被积极开发中,咱们盼望着很快带给你有关更多提高改进的新消息!