今天无意间一个客户问到CH和ES对比的问题。通常来说,ES并不是一个应该和CH进行横向比较的产品,ES是用综合数据库,一个大数据系统,一个搜索引擎,而CH是一个列式存储数据库的管理系统,两者最主要的使用场景并不特别重合。但因为ES出色的检索性能和丰富的数据分析能力,在数据分析产品预算有限的情况下,会有不少客户选择直接将ES用在OLAP分析的场景,而不是再额外部署一个OLAP系统,因此,自然免不了要被拿出来和CH作比较。
比较就比较吧,虽然在OLAP分析领域以列式存储库为主,ES并不是为这个场景而生的(You know, for search), 但综合各方面的能力之后,既然有很多用户选择使用ES作为OLAP分析工具,那我们就应该给大家以合适的指引。
特别是当互联网上出现如下这些描述不当的文章可能给人以误解时,我们有必要去做一些澄清。
文章原文我放在这,携程ClickHouse日志分析实践,分享实践是好的,但做产品比较以及下定论这种事,还是要严谨,要慎重。
这里我也不做一一的纠正,也不去做ES和CH的比较。我只是针对其中的一些表述,帮经常使用ES的同学来进行一些解惑
ClickHouse相对ES占用更少的内存。 ES为了提高查询效率会将很多数据放在内存中,如:segment的索引数据、filter cache、field data cache、indexing buffer等;ES内存的使用量与索引量、数据量、写入量、查询量等成正比。删除(下线)索引、迁移索引或者扩容是应对ES内存问题的常用手段。但是删除(下线)索引导致用户希望保存更长时间数据的需求无法满足,而服务器扩容导致又了成本上升。 ClickHouse的内存消耗主要包括内存型的engine,数据索引,加载到内存中待计算的数据,搜索的结果等。在ClickHouse中日志的数据量和保存时间主要和磁盘有关。
我们可以看一下这里的描述,似乎侧面的意思同样的数据,ES的内存使用效率会更低?其实并不是。
就好比方说,比较BMW的混动7系和常规动力的丰田陆巡的油耗,得出结论BMW在省油方面做得比丰田强,看似结论成立,但实际上如果不考虑场景和用法,并没有多大的指导意义
另外,这里说的内存到底是指的JVM使用的内存,还是把整个系统的内存都算到ES上面呢?如果大家了解过最新版本上的Off-Heap的特性,其实新版本的ES在内存使用上已经有很非常巨大的改进:
结合7版本最新的内存断路器,在最新版本上,已经很少听到用户反馈说 “ES中一个大查询导致OOM的问题”
因此,这里非常重要的一个点,要把ES升级到最新的版本
熟悉ES的同学应该知道,ES提供了大量的选项可以控制生成数据的大小的,并且不同版本的ES性能和效率上也有不同,这里并没有给出ES具体的版本,也没有给出日志和mapping,所以很容易让人产生误导
这里,我做了个测试,我用这样的一个数据集来测试:
原始数据1000多万行,1.4GB。
数据样本如下:
{"geonameid": 2986043, "name": "Pic de Font Blanca", "latitude": 42.64991, "longitude": 1.53335, "country_code": "AD", "population": 0}
{"geonameid": 2994701, "name": "Roc Mélé", "latitude": 42.58765, "longitude": 1.74028, "country_code": "AD", "population": 0}
{"geonameid": 3007683, "name": "Pic des Langounelles", "latitude": 42.61203, "longitude": 1.47364, "country_code": "AD", "population": 0}
{"geonameid": 3017832, "name": "Pic de les Abelletes", "latitude": 42.52535, "longitude": 1.73343, "country_code": "AD", "population": 0}
{"geonameid": 3017833, "name": "Estany de les Abelletes", "latitude": 42.52915, "longitude": 1.73362, "country_code": "AD", "population": 0}
{"geonameid": 3023203, "name": "Port Vieux de la Coume d’Ose", "latitude": 42.62568, "longitude": 1.61823, "country_code": "AD", "population": 0}
{"geonameid": 3029315, "name": "Port de la Cabanette", "latitude": 42.6, "longitude": 1.73333, "country_code": "AD", "population": 0}
{"geonameid": 3034945, "name": "Port Dret", "latitude": 42.60172, "longitude": 1.45562, "country_code": "AD", "population": 0}
{"geonameid": 3038814, "name": "Costa de Xurius", "latitude": 42.50692, "longitude": 1.47569, "country_code": "AD", "population": 0}
{"geonameid": 3038815, "name": "Font de la Xona", "latitude": 42.55003, "longitude": 1.44986, "country_code": "AD", "population": 0}
这里需要指明的是,这个数据样本因为是geo name,因此每一个字段的值都不可能重复的,这个数据样本对于列式存储的来说,基本没有什么优化空间(因为列值全部不一样)。
使用如下mapping来构建ES的索引,0副本1分片:
{
"settings": {
"index.number_of_replicas": 0,
"index.number_of_shards": 1
},
"mappings": {
"dynamic": "strict",
"properties": {
"geonameid": {
"type": "long"
},
"name": {
"type": "text"
},
"latitude": {
"type": "double"
},
"longitude": {
"type": "double"
},
"country_code": {
"type": "text"
},
"population": {
"type": "long"
}
}
}
}
最终生成的索引数据在1.6GB左右浮动,数据膨胀比例大概是1.2 (1.6G/1.4G),文件分布为:
以上是不做任何场景建模优化的数据。
如果我们只是做OLAP的数据统计分析,不做字段内的搜索,我们可以按照列式存储的场景来优化mapping:
"enabled": false
, 不需要获取原值,只要排序和统计结果{
"settings": {
"index.number_of_replicas": 0,
"index.number_of_shards": 1
},
"mappings": {
"dynamic": "strict",
"_source": {
"enabled": false
},
"properties": {
"geonameid": {
"type": "keyword",
"index": false
},
"name": {
"type": "keyword",
"index": false
},
"latitude": {
"type": "double",
"index": false
},
"longitude": {
"type": "double",
"index": false
},
"country_code": {
"type": "keyword",
"index": false
},
"population": {
"type": "long",
"index": false
}
}
}
}最终生成的索引文件比较为:"index": false
, 不需要字段内检索,只要排序和统计结果fdt
, The stored fields for documents, 变小了 tim
,tim
,倒排索引,变小了注意,因为cfs
文件的存在(一个 "虚拟/组合 "文件,由所有其他索引文件组成,用于预防耗尽文件句柄,而特意合并的大文件) ,很难直观比较不同索引文件的变化,以下是针对cfs文件的介绍:
话归正题,现在的存储值由1.6G变为了1G,优化过后,膨胀比变为了0.7,因此,ES,并非那么的没有效率,只是看是否针对应用场景正确的配置了数据模型
我们在存储成本优先的情况下,甚至可以配置"index.codec": "best_compression"
, 获得更高的压缩比:
我们再来看看常规的日志,这是一个ES自身的GC日志,这里就有不少的重复值,比如5935,safepoint,gc
等
index: false
配置一下,可以看到索引大小缩小为3.3mb,几乎是原始数据的1/4因此,如果我们愿意,我们可以有不同的方式来平衡存储成本和查询性能
通过上面提到的方式,我们几乎只存储原始数据的情况下,可以大幅压缩生成索引的大小(原数据的1/4)。特别是面对一些不是特别频繁做查询和分析的场景,我们先把日志采集到ES,留待将来分析,在将来需要时,动态提取字段,再进行分析。
通过这种方式,我们可以:
以下是即将发布的新的runtime
类型:
另外一个和存储大小,成本有关的特性是ES上的新的Searchable Snapshot,通过该功能,我们可以:
我非常的好奇这里的查询场景,ClickHouse经过优化后耗时29.5s,这已经是一个比较不能接受的值了。但上面说,ES直接查不出来,这里,我看到了挺多的问题。因为本身Netflow的日志格式并不复杂,在运维场景下,即便数据量很大,也不应该查不出来
首先,第一个问题是不合理的ES使用: ES使用的是40核256G的服务器,一台服务器部署一个ES实例,单服务器数据量3T左右
,熟悉ES的同学都知道,JVM的内存是有限制的,31G再往上就效率非常低了,在这个例子里面,如果这么大的一台服务器,只给JVM分配了31G内存,然后剩下的内存空载在那不让ES使用,想查得快也很难,通常这样配置的服务器,我们会在上面安装4个ES的节点。在这样的配置上说ES的成本高,性能低,是非常不合理的。
可以看到的公开压测数据如下:(注意,这里没有针对列式存储场景的优化,同样生成倒排索引)
其次,还是ES版本问题,ES的新版本本身就比老版本在一些指标、日志场景上快了几倍到上百倍不等,在一个“错误”的配置上去,再使用老版本的ES去比较CH的话,得出来的结论可能没那么有意义
其实现在各个大数据系统,没有范式革命的产品,有的就是在资源、性能、成本、规模上的互有取舍。有时,我们不一定强调快,能在更大的数据集上运行查询也是一个能力,通过ES最新的async search功能,结合searchable snapshot,ES集群可以对数十PB存在在对象存储上的数据进行检索,单次运行默认可以查询5天之久,因此,单纯比较某些场景查得快不一定能满足所有的需求,比如全量的数据审计。
这里不说太多,可能还是因为版本太低的原因
没有了解过新版本上的ILM和data stream功能的可以了解下,ES的新版本一直在持续优化数据治理的能力,并简化操作。通过ILM,我们可以自动化的实现数据的迁移,而通过data stream,我们可以更轻松的管理数据流,而不是一个个的索引
这篇文章并非打算引战ES和CH社区。全文我几乎没有比较过ES和CH,这里,重申一下。
这里的重点是:
因此,在做产品或者架构比较的时候,应该把ES看做是一个平台,而不是单一用途的产品,这样会有助于降低成本,提升投资回报率
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。