您现在的位置是:亿华云 > IT科技

ES不香吗,为啥还要ClickHouse?

亿华云2025-10-03 20:18:28【IT科技】7人已围观

简介Elasticsearch 是一个实时的分布式搜索分析引擎,它的底层是构建在 Lucene 之上的。简单来说是通过扩展 Lucene 的搜索能力,使其具有分布式的功能。图片来自包图网ES 通常会和其它

 Elasticsearch 是不香一个实时的分布式搜索分析引擎,它的为啥底层是构建在 Lucene 之上的。简单来说是不香通过扩展 Lucene 的搜索能力,使其具有分布式的为啥功能。

图片来自包图网

ES 通常会和其它两个开源组件 Logstash(日志采集)和 Kibana(仪表盘)一起提供端到端的不香日志/搜索分析的功能,常常被简称为 ELK。为啥

Clickhouse 是不香俄罗斯搜索巨头 Yandex 开发的面向列式存储的关系型数据库。ClickHouse 是为啥过去两年中 OLAP 领域中最热门的,并于 2016 年开源。不香

ES 是为啥最为流行的大数据日志和搜索解决方案,但是不香近几年来,它的为啥江湖地位受到了一些挑战,许多公司已经开始把自己的不香日志解决方案从 ES 迁移到了 Clickhouse,这里就包括:携程,香港云服务器为啥快手等公司。不香

架构和设计的对比

ES 的底层是 Lucenc,主要是要解决搜索的问题。搜索是大数据领域要解决的一个常见的问题,就是在海量的数据量要如何按照条件找到需要的数据。搜索的核心技术是倒排索引和布隆过滤器。

ES 通过分布式技术,利用分片与副本机制,直接解决了集群下搜索性能与高可用的问题。

ElasticSearch 是为分布式设计的,有很好的扩展性,在一个典型的分布式配置中,每一个节点(node)可以配制成不同的角色。

如上图所示:

Client Node,源码下载负责 API 和数据的访问的节点,不存储/处理数据。 Data Node,负责数据的存储和索引。 Master Node,管理节点,负责 Cluster 中的节点的协调,不存储数据。

ClickHouse 是基于 MPP 架构的分布式 ROLAP(关系 OLAP)分析引擎。每个节点都有同等的责任,并负责部分数据处理(不共享任何内容)。

ClickHouse 是一个真正的列式数据库管理系统(DBMS)。在 ClickHouse 中,数据始终是按列存储的,包括矢量(向量或列块)执行的过程。

让查询变得更快,最简单且有效的方法是减少数据扫描范围和数据传输时的大小,云服务器而列式存储和数据压缩就可以帮助实现上述两点。

Clickhouse 同时使用了日志合并树,稀疏索引和 CPU 功能(如 SIMD 单指令多数据)充分发挥了硬件优势,可实现高效的计算。

Clickhouse 使用 Zookeeper 进行分布式节点之间的协调。

为了支持搜索,Clickhouse 同样支持布隆过滤器。

查询对比实战

为了对比 ES 和 Clickhouse 的基本查询能力的差异,我写了一些代码来验证:

https://github.com/gangtao/esvsch 

这个测试的架构如下:

架构主要有四个部分组成:

①ES stack

ES stack 有一个单节点的 Elastic 的容器和一个 Kibana 容器组成,Elastic 是被测目标之一,Kibana 作为验证和辅助工具。

部署代码如下:

version: 3.7 services:   elasticsearch:     image: docker.elastic.co/elasticsearch/elasticsearch:7.4.0     container_name: elasticsearch     environment:       - xpack.security.enabled=false       - discovery.type=single-node     ulimits:       memlock:         soft: -1         hard: -1       nofile:         soft: 65536         hard: 65536     cap_add:       - IPC_LOCK     volumes:       - elasticsearch-data:/usr/share/elasticsearch/data     ports:       - 9200:9200       - 9300:9300     deploy:       resources:         limits:           cpus: 4           memory: 4096M         reservations:           memory: 4096M   kibana:     container_name: kibana     image: docker.elastic.co/kibana/kibana:7.4.0     environment:       - ELASTICSEARCH_HOSTS=http://elasticsearch:9200     ports:       - 5601:5601     depends_on:       - elasticsearch volumes:   elasticsearch-data:     driver: local 

②Clickhouse stack

Clickhouse stack 有一个单节点的 Clickhouse 服务容器和一个 TabixUI 作为 Clickhouse 的客户端。

部署代码如下:

version: "3.7" services:   clickhouse:     container_name: clickhouse     image: yandex/clickhouse-server     volumes:       - ./data/config:/var/lib/clickhouse     ports:       - "8123:8123"       - "9000:9000"       - "9009:9009"       - "9004:9004"     ulimits:       nproc: 65535       nofile:         soft: 262144         hard: 262144     healthcheck:       test: ["CMD", "wget", "--spider", "-q", "localhost:8123/ping"]       interval: 30s       timeout: 5s       retries: 3     deploy:       resources:         limits:           cpus: 4           memory: 4096M         reservations:           memory: 4096M   tabixui:     container_name: tabixui     image: spoonest/clickhouse-tabix-web-client     environment:       - CH_NAME=dev       - CH_HOST=127.0.0.1:8123       - CH_LOGIN=default     ports:       - "18080:80"     depends_on:       - clickhouse     deploy:       resources:         limits:           cpus: 0.1           memory: 128M         reservations:           memory: 128M 

③数据导入 stack

数据导入部分使用了 Vector.dev 开发的 vector,该工具和 fluentd 类似,都可以实现数据管道式的灵活的数据导入。

④测试控制 stack

测试控制我使用了 Jupyter,使用了 ES 和 Clickhouse 的 Python SDK 来进行查询的测试。

用 Docker compose 启动 ES 和 Clickhouse 的 stack 后,我们需要导入数据,我们利用 Vector 的 generator 功能,生成 syslog,并同时导入 ES 和 Clickhouse。

在这之前,我们需要在 Clickhouse 上创建表。ES 的索引没有固定模式,所以不需要事先创建索引。

创建表的代码如下:

CREATE TABLE default.syslog(     application String,     hostname String,     message String,     mid String,     pid String,     priority Int16,     raw String,     timestamp DateTime(UTC),     version Int16 ) ENGINE = MergeTree()     PARTITION BY toYYYYMMDD(timestamp)     ORDER BY timestamp     TTL timestamp + toIntervalMonth(1); 

创建好表之后,我们就可以启动 vector,向两个 stack 写入数据了。vector 的数据流水线的定义如下:

[sources.in]   type = "generator"   format = "syslog"   interval = 0.01   count = 100000 [transforms.clone_message]   type = "add_fields"   inputs = ["in"]   fields.raw = "{ {  message }}" [transforms.parser]   # General   type = "regex_parser"   inputs = ["clone_message"]   field = "message" # optional, default   patterns = [^<(?P<priority>\d*)>(?P<version>\d) (?P<timestamp>\d{ 4}-\d{ 2}-\d{ 2}T\d{ 2}:\d{ 2}:\d{ 2}\.\d{ 3}Z) (?P<hostname>\w+\.\w+) (?P<application>\w+) (?P<pid>\d+) (?P<mid>ID\d+) - (?P<message>.*)$] [transforms.coercer]   type = "coercer"   inputs = ["parser"]   types.timestamp = "timestamp"   types.version = "int"   types.priority = "int" [sinks.out_console]   # General   type = "console"   inputs = ["coercer"]    target = "stdout"    # Encoding   encoding.codec = "json"  [sinks.out_clickhouse]   host = "http://host.docker.internal: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]   # General   type = "elasticsearch"   inputs = ["coercer"]   compression = "none"    endpoint = "http://host.docker.internal:9200"    index = "syslog-%F"   # Encoding   # Healthcheck   healthcheck.enabled = true 

这里简单介绍一下这个流水线:

source.in:生成 syslog 的模拟数据,生成 10w 条,生成间隔和 0.01 秒。 transforms.clone_message:把原始消息复制一份,这样抽取的信息同时可以保留原始消息。 transforms.parser:使用正则表达式,按照 syslog 的定义,抽取出 application,hostname,message,mid,pid,priority,timestamp,version 这几个字段。 transforms.coercer:数据类型转化。 sinks.out_console:把生成的数据打印到控制台,供开发调试。 sinks.out_clickhouse:把生成的数据发送到Clickhouse。 sinks.out_es:把生成的数据发送到 ES。

运行 Docker 命令,执行该流水线:

docker run \         -v $(mkfile_path)/vector.toml:/etc/vector/vector.toml:ro \         -p 18383:8383 \         timberio/vector:nightly-alpine 

数据导入后,我们针对一下的查询来做一个对比。ES 使用自己的查询语言来进行查询,Clickhouse 支持 SQL,我简单测试了一些常见的查询,并对它们的功能和性能做一些比较。

返回所有的记录:

# ES {    "query":{      "match_all":{ }   } } # Clickhouse  "SELECT * FROM syslog" 

匹配单个字段:

# ES {    "query":{      "match":{        "hostname":"for.org"     }   } } # Clickhouse  "SELECT * FROM syslog WHERE hostname=for.org" 

匹配多个字段:

# ES {    "query":{      "multi_match":{        "query":"up.com ahmadajmi",         "fields":[           "hostname",           "application"         ]     }   } } # Clickhouse、 "SELECT * FROM syslog WHERE hostname=for.org OR application=ahmadajmi" 

单词查找,查找包含特定单词的字段:

# ES {    "query":{      "term":{        "message":"pretty"     }   } } # Clickhouse "SELECT * FROM syslog WHERE lowerUTF8(raw) LIKE %pretty%" 

范围查询,查找版本大于 2 的记录:

# ES {    "query":{      "range":{        "version":{          "gte":2       }     }   } } # Clickhouse "SELECT * FROM syslog WHERE version >= 2" 

查找到存在某字段的记录:

# ES {    "query":{      "exists":{        "field":"application"     }   } } # Clickhouse "SELECT * FROM syslog WHERE application is not NULL" 

ES 是文档类型的数据库,每一个文档的模式不固定,所以会存在某字段不存在的情况;而 Clickhouse 对应为字段为空值。

正则表达式查询,查询匹配某个正则表达式的数据:

# ES {    "query":{      "regexp":{        "hostname":{          "value":"up.*",           "flags":"ALL",             "max_determinized_states":10000,               "rewrite":"constant_score"       }     }   } } # Clickhouse "SELECT * FROM syslog WHERE match(hostname, up.*)" 

聚合计数,统计某个字段出现的次数:

# ES {    "aggs":{      "version_count":{        "value_count":{          "field":"version"       }     }   } } # Clickhouse "SELECT count(version) FROM syslog" 

聚合不重复的值,查找所有不重复的字段的个数:

# ES {    "aggs":{      "my-agg-name":{        "cardinality":{          "field":"priority"       }     }   } } # Clickhouse "SELECT count(distinct(priority)) FROM syslog " 

我用 Python 的 SDK,对上述的查询在两个 Stack 上各跑 10 次,然后统计查询的性能结果。

我们画出出所有的查询的响应时间的分布:

总查询时间的对比如下:

通过测试数据我们可以看出 Clickhouse 在大部分的查询的性能上都明显要优于 Elastic。

在正则查询(Regex query)和单词查询(Term query)等搜索常见的场景下,也并不逊色。

在聚合场景下,Clickhouse 表现异常优秀,充分发挥了列村引擎的优势。

注意,我的测试并没有任何优化,对于 Clickhouse 也没有打开布隆过滤器。可见 Clickhouse 确实是一款非常优秀的数据库,可以用于某些搜索的场景。

当然 ES 还支持非常丰富的查询功能,这里只有一些非常基本的查询,有些查询可能存在无法用 SQL 表达的情况。

总结

本文通过对于一些基本查询的测试,对比了 Clickhouse 和 Elasticsearch 的功能和性能。

测试结果表明,Clickhouse 在这些基本场景表现非常优秀,性能优于 ES,这也解释了为什么用很多的公司应从 ES 切换到 Clickhouse 之上。

作者:Gang Tao

编辑:陶家龙

出处:zhuanlan.zhihu.com/p/353296392

很赞哦!(3993)