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

ES不好吃吗?为什么需要ClickHouse?

时间:2023-03-12 07:54:02 科技观察

Elasticsearch是一个实时的分布式搜索分析引擎,其底层构建在Lucene之上。简单的说就是通过扩展Lucene的搜索能力,实现分布式功能。图片来自宝途网ES通常会与另外两个开源组件Logstash(日志收集)和Kibana(仪表盘)一起提供端到端的日志/搜索分析功能,通常简称为ELK。Clickhouse是俄罗斯搜索巨头Yandex开发的面向列的关系数据库。ClickHouse是近两年OLAP领域最火的,并于2016年开源。ES是最流行的大数据日志和搜索解决方案,但近年来其地位受到挑战。许多公司已经开始将他们的日志解决方案从ES迁移到Clickhouse,包括:携程、快手等公司。架构和设计对比ES底层是Lucenc,主要解决搜索的问题。搜索是大数据领域需要解决的一个普遍问题,即如何在海量数据中根据条件找到需要的数据。搜索的核心技术是倒排索引和布隆过滤器。ES通过分布式技术,利用分片和复制机制,直接解决了集群下的搜索性能和高可用问题。ElasticSearch是为分布式设计的,具有很好的可扩展性。在典型的分布式配置中,每个节点(node)都可以配置为不同的角色。如上图所示:ClientNode,负责API和数据访问的节点,不存储/处理数据。DataNode,负责数据的存储和索引。MasterNode,管理节点,负责Cluster中节点的协调,不存储数据。ClickHouse是一个基于MPP架构的分布式ROLAP(关系型OLAP)分析引擎。每个节点平等负责,负责部分数据处理(不共享任何东西)。ClickHouse是一个真正的列式数据库管理系统(DBMS)。在ClickHouse中,数据始终按列存储,包括用于执行过程的向量(向量块或列)。使查询更快最简单有效的方法是减少数据扫描范围和数据传输的大小,而列式存储和数据压缩可以帮助实现以上两点。Clickhouse还利用日志合并树、稀疏索引和CPU功能(如SIMD单指令多数据),充分发挥硬件优势,实现高效计算。Clickhouse使用Zookeeper来协调分布式节点。为了支持搜索,Clickhouse还支持布隆过滤器。查询对比实战为了比较ES和Clickhouse在基本查询能力上的区别,写了一些代码来验证:https://github.com/gangtao/esvsch本次测试的架构如下:架构主要由四部分组成:①ES栈ES栈由一个单节点Elastic容器和一个Kibana容器组成。Elastic是测试的目标之一,Kibana作为验证和辅助工具。部署代码如下:version:'3.7'services:elasticsearch:image:docker.elastic.co/elasticsearch/elasticsearch:7.4.0container_name:elasticsearchenvironment:-xpack.security.enabled=false-discovery.type=single-nodeulimits:memlock:soft:-1hard:-1nofile:soft:65536hard:65536cap_add:-IPC_LOCKvolumes:-elasticsearch-data:/usr/share/elasticsearch/dataports:-9200:9200-9300:9300deploy:resources:limits:cpus:'4'内存:4096Mreservations:内存:4096Mkibana:container_name:kibanaimage:docker.elastic.co/kibana/kibana:7.4.0environment:-ELASTICSEARCH_HOSTS=http://elasticsearch:9200ports:-5601:5601depends_on:-elasticsearchvolumes:elasticver:data:drilocal②ClickhousestackClickhousestack有一个单节点的Clickhouse服务容器和一个TabixUI作为Clickhouse的客户端。部署代码如下:version:"3.7"services:clickhouse:container_name:clickhouseimage:yandex/clickhouse-servervolumes:-./data/config:/var/lib/clickhouseports:-"8123:8123"-"9000:9000"-"9009:9009"-"9004:9004"ulimits:nproc:65535nofile:soft:262144hard:262144healthcheck:test:["CMD","wget","--spider","-q","localhost:8123/ping"]间隔:30stimeout:5sretries:3deploy:resources:limits:cpus:'4'memory:4096Mreservations:memory:4096Mtabixui:container_name:tabixuiimage:spoonest/clickhouse-tabix-web-clientenvironment:-CH_NAME=dev-CH_HOST=127.0.0.1:8123-CH_LOGIN=defaultports:-"18080:80"depends_on:-clickhousedeploy:resources:limits:cpus:'0.1'memory:128Mreservations:memory:128M③数据导入栈数据导入部分使用vector开发vector.dev,这个工具类似于fluentd,都可以实现数据管道式的灵活数据导入。④测试控件堆栈测试控件我使用了Jupyter、ES和Clickhouse的PythonSDK来测试查询。用Dockercompose启动ES和Clickhouse的栈后,我们需要导入数据。我们使用Vector的generator功能生成syslog,同时导入ES和Clickhouse。在此之前,我们需要在Clickhouse上创建表。ES的索引没有固定模式,所以不需要提前创建索引。创建表的代码如下:1);Create创建完表后,我们就可以启动vector,向两个栈中写入数据了。vector的数据流水线的定义如下:[sources.in]type="generator"format="syslog"interval=0.01count=100000[transforms.clone_message]type="add_fields"inputs=["in"]fields.raw="{{message}}"[transforms.parser]#Generaltype="regex_parser"inputs=["clone_message"]field="message"#optional,defaultpatterns=['^<(?P\d*)>(?P<版本>\d)(?P<时间戳>\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z)(?P<主机名>\w+\.\w+)(?P<应用程序>\w+)(?P\d+)(?PID\d+)-(?P.*)$'][transforms.coercer]type="coercer"inputs=["parser"]types.timestamp="timestamp"types.version="int"types.priority="int"[sinks.out_console]#Generaltype="console"inputs=["coercer"]target="stdout"#Encodingencoding.codec="json"[sinks.out_clickhouse]host="http://host.docker.int内部:8123“inputs=[”coercer”]table=”syslog”type=”clickhouse”encoding.only_fields=[”application”,”hostname”,”message”,”mid”,”pid”,”priority”,"raw","timestamp","version"]encoding.timestamp_format="unix"[sinks.out_es]#Generaltype="elasticsearch"inputs=["coercer"]compression="none"endpoint="http://host.docker.internal:9200"index="syslog-%F"#Encoding#Healthcheckhealthcheck.enabled=true这里简单介绍一下这个pipeline:source.in:生成syslog模拟数据,生成10w个entry,生成intervals和transformsin0.01秒.clone_message:复制原始消息,这样提取的信息可以保留原始消息transforms.parser:使用正则表达式提取application、hostname、message、mid、pid、priority、timestamp、version这些字段:数据类型转换sinks.out_console:将生成的数据打印到控制台,方便开发调试sinks.out_clickhouse:将生成的数据发送到Clickhousesinks.out_es:生成Data发送给ES。运行Docker命令执行管道:dockerrun\-v$(mkfile_path)/vector.toml:/etc/vector/vector.toml:ro\-p18383:8383\timberio/vector:nightly-alpine导入数据后,我们针对下面的查询进行比较。ES使用自己的查询语言进行查询,Clickhouse支持SQL。我简单地测试了一些常见的查询,并比较了它们的功能和性能。返回所有记录:#ES{"query":{"match_all":{}}}#Clickhouse"SELECT*FROMsyslog"匹配单个字段:#ES{"query":{"match":{"hostname":"for.org"}}}#Clickhouse"SELECT*FROMsyslogWHEREhostname='for.org'"匹配多个字段:#ES{"query":{"multi_match":{"query":"up.comahmadajmi","fields":["hostname","application"]}}}#Clickhouse,"SELECT*FROMsyslogWHEREhostname='for.org'ORapplication='ahmadajmi'"单词查找,查找包含特定单词的字段:#ES{"query":{"term":{"message":"pretty"}}}#Clickhouse"SELECT*FROMsyslogWHERElowerUTF8(raw)LIKE'%pretty%'"范围查询,查找版本大于2的记录:#ES{"query":{"range":{"version":{"gte":2}}}}#Clickhouse"SELECT*FROMsyslogWHEREversion>=2"查找某个字段的记录:#ES{"query":{"exists":{“字段”:“应用程序”}}}#Clickhouse“SELECT*FROMsyslogWHEREapplicationisnotNULL"ES是一个文档类型的数据库,每个文档的模式不固定,所以可能会出现某个字段不存在的情况;而Clickhouse对应的是一个正则表达式查询一个空值的字段,和查询匹配某个正则表达式数据:#ES{"query":{"regexp":{"hostname":{"value":"up.*","flags":"ALL","max_determinized_states":10000"rewrite":"constant_score"}}}}#Clickhouse"SELECT*FROMsyslogWHEREmatch(hostname,'up.*')"聚合计数,统计某个字段出现的次数:#ES{"aggs":{"version_count":{"value_count":{"field":"version"}}}}#Clickhouse"SELECTcount(version)FROMsyslog"聚合唯一值并找到所有唯一字段的数量:#ES{"aggs":{"my-agg-name":{"cardinality":{"field":"priority"}}}}#Clickhouse"SELECTcount(distinct(priority))FROMsyslog"我使用PythonSDK运行上述查询10次两个Stack中的每一个,然后统计查询的性能结果We绘制所有查询的响应时间分布:总查询时间对比如下:通过测试数据可以看出,Clickhouse在大部分查询性能上明显优于Elastic。在正则查询(Regexquery)、单词查询(Termquery)等常见的搜索场景中,也不逊色。在聚合场景中,Clickhouse表现异常出色,充分发挥了猎村引擎的优势。请注意,我的测试没有任何优化,也没有为Clickhouse打开布隆过滤器。由此可见,Clickhouse确实是一个非常优秀的数据库,可以在某些搜索场景中使用。当然ES也支持非常丰富的查询功能。这里只有一些很基础的查询,有些查询可能不会用SQL表达。总结本文通过测试一些基本的查询,比较了Clickhouse和Elasticsearch的功能和性能。测试结果表明,Clickhouse在这些基础场景下的表现非常出色,性能优于ES,这也解释了为什么很多公司要从ES转向Clickhouse。作者:刚涛编辑:陶家龙来源:zhuanlan.zhihu.com/p/353296392