当前位置: 首页 > 科技观察

基于ES的开源分布式SQL数据库CrateDB适用于哪些场景?

时间:2023-03-16 15:01:25 科技观察

今天的分享主要有以下几个方面:CrateDB简介CrateDB在携程的实践CrateDB在携程的优化总结一、CrateDB简介1.CrateDBBCrateDB是一个基于ElasticSearch的分布式数据库。不同的是提供了ANSISQL查询访问接口。ElasticSearch在6.X版本之后也开始提供SQL查询,但是相比于ElasticSearch,CrateDB可以支持多个索引之间的关联查询。对于某些聚合函数,它返回准确的查询结果,而ElasticSearch返回的是近似值。2、CrateDB的特点适合海量时序数据存储CrateDB适合海量时序数据存储,需要经常变动的数据在CrateDB存储中效果较差。由于CrateDB是基于ElasticSearch的,频繁的删除和修改操作会极大地损害其性能。高可靠、可扩展CrateDB在设计上继承了ElasticSearch高可靠的优点。集群更便于扩展,对于一些点查询或者中等复杂度的查询可以实时返回结果。支持DynamicSc??hemaCrateDB支持DynamicSc??hema,最新版本可以支持json数据格式,让数据写入更方便。我认为CrateDB的初衷是使用SQL来查询和访问基于ElasticSearch存储的数据。基于这个概念,我们可以看到它的大体分层(如上图所示),从外部访问到最终存储自下而上,最外层提供PostgresSQL兼容访问协议和RESTAPI访问协议,然后解析语句,然后执行它来获取每个节点上存储的数据。3.海量数据存储对比由于类似的技术很多,这里只对比几个比较典型的技术,CrateDB、ElasticSearch和MongoDB,都可以归为Nosql。下面将从7个维度对三者进行比较。1)Schema支持类型三种数据库都支持DynamicSc??hema。但是在真实的生产环境中,我们推荐使用StructSchema,因为DynamicSc??hema可能会导致各种问题。仅代表个人观点,不适用所有场景。2)是否支持SQL访问SQL诞生40多年,已经成为一种非常成熟的语言,具有很强的表达能力。同时,SQL具有通用性,被大家普遍接受。CrateDB基于SQL的通用性不断发展,支持ANSISQL,使用PostgreSQL协议。起初,ElasticSearch只支持json-like格式的查询语法,后来开始提供一些针对单索引的SQL语句支持功能,并不断丰富。据我所知,MongoDB不直接支持SQL。如果写SQL语句,需要借助第三方插件才能被MongoDB识别,这会在一定程度上影响查询性能。3)可扩展性从可扩展性的角度来看,CrateDB和ElasticSearch使用gossip协议组成集群。简单地说,节点是等价的。在ElasticSearch集群中,节点可以分为Master、Coordinator和承载数据的Data。一个节点可以同时扮演三个不同的角色,所以他们是平等的。MongoDB不同。如果用它来搭建分布式集群,至少有三个不同的Host,分别是ConfigServer、Mongos、Data。为了实现高可靠性,一个分片需要划分为对应的Master或者Slave。综上所述,从扩展性的角度来看,ElasticSearch和CrateDB更胜一筹。4)对关联分析的支持程度CrateDB支持交叉索引之间的关联分析,而ElasticSearch使用了一些灵活的方法来支持这种关联查询,这意味着在写入数据时需要做相应的改变。MongoDB在4.X版本不支持关联查询,之后的版本没有及时关注。如果描述有误,请指正。5)聚合精度CrateDB和MongoDB返回精确值,而ElasticSearch返回近似值。虽然返回近似值的执行速度很快,但其计算的准确性会受到一定程度的影响。6)性能在查询性能方面,CrateDB和ElasticSearch都可以很好的返回查询结果,上图中列出的耗时为100毫秒。对于比较简单的查询,100毫秒算是高消耗了,其实可以在更短的时间内返回结果。在我们自己的质量环境中实际耗时,后面会提到。7)运维引入新技术后,带来的运维复杂度非常关键。CrateDB和ElasticSearch的运维复杂度低于MongoDB。4.CrateDB系统架构和节点类型如上所述,CrateDB和ElasticSearch中的节点是对等的。以ElasticSearch为例,在一个由五个节点组成的ElasticSearch集群中,至少有两个不同的角色。Master角色需要负责两方面的工作,即管理节点和管理索引。节点加入集群,集群中创建了多少个不同的索引,这些索引的分片分布在哪些机器上,都由Master管理。数据节点我们创建索引后,数据最终会落到具体的ElasticSearch节点上,最终承载数据的就是数据节点。上图的右半部分显示了在生产环境中部署CrateDB或ElasticSearch集群。顶部负载平衡部分是可选的。除了上面提到的两种节点类型之外,还有一种节点类型叫做Coordinator,它既不承载具体的数据,也不起到Master的作用,只是接受外部请求,并将外部请求路由到数据节点上,在Coordinator节点上做具体的查询,然后在Coordinator节点上做一些总结,最后回到应用。另外,在ElasticSearch中可能还有一种叫做Ingest的节点类型,这里就不细说了。综上所述,CrateDB表类似于ElasticSearch索引。ElasticSearch索引由多个不同的分片组成,每个分片可能落在某个数据节点上。为了实现高可靠,一个分片又被分为primaryshard和replicashard,即图中列出的Primary和Secondary。5.CrateDB具体操作1)建表这个操作和用PostgreSQL或MySQL建表没有太大区别。创建一个员工表(如上所示),包括姓名、年龄、性别和地址。这张表根据名字进行哈希,哈希结果分为4个不同的分片,然后是索引级别的一些配置,其配置项多达几十项。主要注意以下几点:如果一个shard的副本数只有primaryshard,则副本数为0,如果除了primaryshard还有其他replicashard,增加相应的副本数即可。refresh_intervalElasticSearch将数据从内存刷新到磁盘,连续刷新会降低性能。为了保证更多的数据留在内存中,减少刷新次数,我们可以调整刷新间隔,具体调整取决于数据的新鲜度要求。数据刷新后才能查询。translog.sync_intervalElasticSearch采用writeaheadlog的方式,也就是说有大量的translog。Translog也将数据从内存写入磁盘。有一个同步间隔。如果增加这个间隔,写入速度可能会加快,但也可能会导致容错问题。2)乐观并发控制CrateDB是一个基于ElasticSearch的数据库,它在ElasticSearch的基础上进行了一次进化,称为乐观并发控制。当我们向某个表写入数据时,有两个隐藏列,一个是sequence_number,也就是该列的版本号,另一个是primary_term。两者结合可以实现某个版本的数据只更新一次。避免频繁更新。以上图中的语句为例,更新sequence_number等于0,当这条语句执行成功后,它的sequence_number会自动跳转到1,并且每次更新这个值都会增加。如果两个不同的进程或者两个不同的外部访问尝试更新同一条语句,只有一个会执行成功,实现了乐观并发控制。3)PartitionedTableCrateDB不同于ElasticSearch,它引入了PartitionedTable的概念,即所谓分区表。上面说了一张表有多个分片承载数据,即ElasticSearch的一个索引有多个不同的分片,对应CrateDB中的partitions,CrateDB中的partitions可以对应ElasticSearch中的aliases。如果我们要查询或写入表的数据量是数十亿或数百亿,将这些表放在同一个索引中可能会降低查询和写入速度。我们其实可以把数据分成多个不同的分区。在我们的实际制作中,有这样一种情况,可能有一些坐过飞机的用户想查看自己的飞行足迹。如果将用户的所有历史数据都放在同一个索引中,查询后显示在前端,速度会有所提高。可能会慢一些,因为操作对界面的要求更高。例如,要求在50毫秒内返回结果。如果数据没有分区,查询会很慢。这里的慢是99%线的情况。在这种情况下,我们需要满足性能指标。解决方法之一是将其拆分为多个不同的分区。进入每一个uid后,我们只需要到对应的分区表中查询即可。分区时需要注意的一点是,如果已经为表创建了组件,则分区的字段必须全部属于组件字段列表,因为这个组件可以由一列或多列组成,也可以是一个复合组件。分区的字段必须在组件的字段列表中。二、CrateDB在携程的实践1、实时聚合分析上图是我们使用CrateDB后的对比。图中只对比了CrateDB和Presto。我们当时的场景如下。我们有很多表,每张表都有几千万条数据,有的甚至上亿条数据,需要对数据进行复杂的聚合。本来我们是用Presto来查询的,因为是看板,刷新间隔比较长。为了解决这个问题,我们尝试了一些方法,后来发现使用CrateDB效果更好。右边是性能对比,好处非常明显。1)具体分析场景国内产品/业务/收入数据分析;主要监控共同产出收入(多维度);进行拆分下钻分析;进行sum、between、groupby、casewhen、leftjoin、unionall等操作。在性能对比方面,使用CrateDB后,我们基本上可以在1~2秒内返回结果。2.海量数据存储和实时查询在我们实际生产中,实时数据聚合和分析的调用非常多。首先,我们将数据放入Redis。每次收到一个fetch请求,我们都会开发相应的代码,对fetch到的数据进行相应的分析,处理后返回给调用者。虽然这个需求并不复杂,但是因为我们没有办法注入数据分析逻辑,所以只能做代码工作。引入CrateDB后,我们就可以使用SQL来实现分析工作了。剩下的那些不能完全通过SQL分析解决的部分,我们可以结合一些Groovy脚本来完成。基于这个理念,我们开发了一个模板,我们在模板中写入SQL,指定从哪个表取数据,如何分析,取数据后决定是否进行自定义的后续处理,并执行相应的A最后返回结果的Groovy脚本。这套流程大大节省了开发周期,提高了开发效率。除了开发周期比较,存储方面的比较也很重要。例如,将数据放入Redis需要200g内存,但使用CrateDB存储可能只需要50g。这不仅减少了数据量,也意味着成本大大降低。在携程,有一个基于RocksDB的存储。它开发了Redis兼容协议,可以将数据存储在磁盘上,并通过Redis接口进行访问。我们将数据保存到磁盘中,并从平均值、95%线和99%线比较了性能。均线仍在可承受范围内。当然,CrateDB不可能比Redis快。从上图可以看出,除了99.9%这一行,差距有点大,其他都在可以接受的范围内。在数据导入耗时方面,我们使用Spark将数据导入CrateDB,两者差距不是特别大。三、携程对CrateDB的优化1、落地时的调优当我们在整体技术方案中引入CrateDB时,还是需要做一些调优的。1)磁盘空间优化为了避免大量磁盘空间的消耗,需要对索引级别进行优化。此外,还可以进行聚合优化,关闭列存。2)更新操作优化为了提高更新操作的性能,我们建议先插入,再删除已有数据。为了达到目的,可以加上相应的版本号,每次只取最新版本的数据。在线更新的需求需要转换,这也意味着CrateDB支持的场景是有限的。对于要求严格、更新频繁的场景,CrateDB不是一个好的选择。3)查询优化上面提到,采用分区多分片的方式优化表结构的存储,使得每次查询只需要查询尽可能少的分区或分片。消耗时间更短。4)过期数据删除优化2.Spark数据导入当数据导入CrateDB时,我们可能会使用Spark进行操作。在这里,我将与您分享这个过程的细节。这里我们以分区为例。如果有超过十亿或上亿的用户ID和一些相关数据,有一种比较简单的方法,将它们平均分布到每个分区中。我们对uid(一串字符)进行相应的MD5。MD5后,取前两位或后两位,得到256个分片。256个shard显然太多了,可以除以一个因子来减少shard的个数,这样可以平均分布数据,让shard上承载的数据量差不多。这样做的挑战在于,在编写Spark程序时,如何让每个分区的数据都落入同一个分片中。大家可能会想到repartition函数,但是repetition是对某个字段进行hash,并不能保证数据落在同一个partition中,那么我们就需要制定partition。上图右侧写了一些伪代码。我们在spark中定义一个repartition,然后重新加载它,以显示可能有多少不同的片段。假设我们只是取前两位或者后两位,然后除以4得到64个分片,那么我们把传过来的数和64取模对应一个具体的分区位置。Spark中有partitionBy,partitionBy只支持rdd算子。DataFrame中没有partitionBy操作符,所以我们需要先将DataFrame或DataSet转换为rdd,通过形成key键值对的方式进行partitionBy操作。之后需要将对应的rdd转换回DataFrame,这样就可以得到一个分布非常均匀的DataFrame,然后写入CrateDB中,达到快速的写入速度。3.自动化运维的尝试我使用Rancher、OpenEBS、NginxIngress在K8S上实现了一个CrateDB集群,这使得我们可以在云环境甚至私有云上部署CrateDB另一方面,它还可以提高硬件利用率,这也是我的初衷。4.CrateDBadminUICrateDB安装完成后会打开如上图所示的操作界面。我们可以直接写查询语句,方便的观察整个集群的状态。四、小结1、CrateDB的适用场景。单点查询写入少,查询多时序数据存储,全文查询2.CrateDB的缺点Upsert性能低,只支持NRT查询。需要实现高阶SQL函数,不支持事务。Q&AQ1:CrateDB解决了ES字段类型不可修改、写入性能低、硬件资源消耗高的痛点?A1:首先,CrateDB支持修改字段类型。该字段类型的修改与PostgreSQL中相同。可以把varchar改成text,但是直接把varchar类型改成timestamp可能会有问题。这时候,你就得重写或者做转换了。其次,在写性能高低的场景下,如果只是单纯的insert,它的性能还是很高的。如果是upsert,或者delete和insert混用,这种模式混用会降低写入性能。有一些问题需要相应地解决。有两种解决方法。第一种是先插入新数据,再删除旧数据。第二种方法,如果新数据比较小,可以写到另外一张临时表中,将临时表关联到新表上,然后进行相应的update。Q2:与Elasticsearch和MongoDB相比,CrateDB的备份和恢复能力如何?A2:CrateDB和Elasticsearch具有相同的备份和恢复功能,但可能比MongoDB更直观、更容易。这是我个人的理解。在恢复方面,如果你要求所有的数据都吐出到磁盘再返回,那么所有的数据应该是没有丢失的。Q3:CrateDB运行一段时间后性能会明显下降。除了重启还有什么解决办法吗?A3:CrateDB在实际运维中确实遇到了一些问题,但我没有遇到过明显的性能下降。如果有的话,您可以进行索引级重建而不是完全重启集群,因为集群重启的成本更高。Q4:CrateDB的日志分析能力如何?它有继承ES的ELK的能力吗?A4:在与Logstash、Kibana的搭配层面,ES的能力更强。从整个生态来看,CrateDB还是不能和Elasticsearch相提并论,因为Elasticsearch已经发展了很长时间,再加上Logstash和Kibana的加持,在数据可视化和分析展示方面确实很强,但是CrateDB可以与Elasticsearch进行比较。其他几个开源产品一起使用,比如ApacheSuperset,但是肯定没有Kibana原生定制强大。Q5:如果CrateDB部署在k8s上,数据存储应该怎么存储,分布式存储,本地存储,还是集中式存储?A5:如前所述,需要结合OpenEBS或Rancher使用。它是分布式处理。您的节点必须连接到相应的存储机器。即使Docker挂了,数据也不会丢失。Q6:你们公司是在TP还是AP场景使用CrateDB比较多?A6:我们使用的是AP场景,实时数据聚合返回结果。当然,每次查询命中的数据集并不是特别大。我们要查询的数据集可能非常大,但实际上是由查询条件决定的。点击量还是比较少的,可能也就几十万吧。Q7:CrateDB的标杆产品是什么,与hadoop等大数据生态有什么互补?A7:CrateDB和Hadoop不是竞争,应该是不同层次的,因为Hadoop是做数据离线存储的,而CrateDB是做数据分析的。如果要找竞品的话,我个人认为TimescaleDB是一个强有力的竞争者,因为他们都自称是时序数据库,也提供ANSISQL查询标准。从目前的情况来看,TimescaleDB可能会获得更多的用户群。