文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

ES不香吗,为啥还要ClickHouse?

2024-12-03 02:09

关注

[[410030]]

图片来自包图网

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

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

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

架构和设计的对比

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

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

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

如上图所示:

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

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

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

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

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

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

查询对比实战

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

  1. https://github.com/gangtao/esvsch 

这个测试的架构如下:

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

①ES stack

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

部署代码如下:

  1. version: '3.7' 
  2.  
  3. services: 
  4.   elasticsearch: 
  5.     image: docker.elastic.co/elasticsearch/elasticsearch:7.4.0 
  6.     container_name: elasticsearch 
  7.     environment: 
  8.       - xpack.security.enabled=false 
  9.       - discovery.type=single-node 
  10.     ulimits: 
  11.       memlock: 
  12.         soft: -1 
  13.         hard: -1 
  14.       nofile: 
  15.         soft: 65536 
  16.         hard: 65536 
  17.     cap_add: 
  18.       - IPC_LOCK 
  19.     volumes: 
  20.       - elasticsearch-data:/usr/share/elasticsearch/data 
  21.     ports: 
  22.       - 9200:9200 
  23.       - 9300:9300 
  24.     deploy: 
  25.       resources: 
  26.         limits: 
  27.           cpus: '4' 
  28.           memory: 4096M 
  29.         reservations: 
  30.           memory: 4096M 
  31.  
  32.   kibana: 
  33.     container_name: kibana 
  34.     image: docker.elastic.co/kibana/kibana:7.4.0 
  35.     environment: 
  36.       - ELASTICSEARCH_HOSTS=http://elasticsearch:9200 
  37.     ports: 
  38.       - 5601:5601 
  39.     depends_on: 
  40.       - elasticsearch 
  41.  
  42. volumes: 
  43.   elasticsearch-data: 
  44.     driver: local 

②Clickhouse stack

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

部署代码如下:

  1. version: "3.7" 
  2. services: 
  3.   clickhouse: 
  4.     container_name: clickhouse 
  5.     image: yandex/clickhouse-server 
  6.     volumes: 
  7.       - ./data/config:/var/lib/clickhouse 
  8.     ports: 
  9.       - "8123:8123" 
  10.       - "9000:9000" 
  11.       - "9009:9009" 
  12.       - "9004:9004" 
  13.     ulimits: 
  14.       nproc: 65535 
  15.       nofile: 
  16.         soft: 262144 
  17.         hard: 262144 
  18.     healthcheck: 
  19.       test: ["CMD""wget""--spider""-q""localhost:8123/ping"
  20.       interval: 30s 
  21.       timeout: 5s 
  22.       retries: 3 
  23.     deploy: 
  24.       resources: 
  25.         limits: 
  26.           cpus: '4' 
  27.           memory: 4096M 
  28.         reservations: 
  29.           memory: 4096M 
  30.  
  31.   tabixui: 
  32.     container_name: tabixui 
  33.     image: spoonest/clickhouse-tabix-web-client 
  34.     environment: 
  35.       - CH_NAME=dev 
  36.       - CH_HOST=127.0.0.1:8123 
  37.       - CH_LOGIN=default 
  38.     ports: 
  39.       - "18080:80" 
  40.     depends_on: 
  41.       - clickhouse 
  42.     deploy: 
  43.       resources: 
  44.         limits: 
  45.           cpus: '0.1' 
  46.           memory: 128M 
  47.         reservations: 
  48.           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 的索引没有固定模式,所以不需要事先创建索引。

创建表的代码如下:

  1. CREATE TABLE default.syslog( 
  2.     application String, 
  3.     hostname String, 
  4.     message String, 
  5.     mid String, 
  6.     pid String, 
  7.     priority Int16, 
  8.     raw String, 
  9.     timestamp DateTime('UTC'), 
  10.     version Int16 
  11. ) ENGINE = MergeTree() 
  12.     PARTITION BY toYYYYMMDD(timestamp
  13.     ORDER BY timestamp 
  14.     TTL timestamp + toIntervalMonth(1); 

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

  1. [sources.in
  2.   type = "generator" 
  3.   format = "syslog" 
  4.   interval = 0.01 
  5.   count = 100000 
  6.  
  7. [transforms.clone_message] 
  8.   type = "add_fields" 
  9.   inputs = ["in"
  10.   fields.raw = "{{ message }}" 
  11.  
  12. [transforms.parser] 
  13.   # General 
  14.   type = "regex_parser" 
  15.   inputs = ["clone_message"
  16.   field = "message" # optional, default 
  17.   patterns = ['^<(?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.*)$'
  18.  
  19. [transforms.coercer] 
  20.   type = "coercer" 
  21.   inputs = ["parser"
  22.   types.timestamp = "timestamp" 
  23.   types.version = "int" 
  24.   types.priority = "int" 
  25.  
  26. [sinks.out_console] 
  27.   # General 
  28.   type = "console" 
  29.   inputs = ["coercer"]  
  30.   target = "stdout"  
  31.  
  32.   # Encoding 
  33.   encoding.codec = "json"  
  34.  
  35.  
  36. [sinks.out_clickhouse] 
  37.   host = "http://host.docker.internal:8123" 
  38.   inputs = ["coercer"
  39.   table = "syslog" 
  40.   type = "clickhouse" 
  41.  
  42.   encoding.only_fields = ["application""hostname""message""mid""pid""priority""raw""timestamp""version"
  43.   encoding.timestamp_format = "unix" 
  44.  
  45. [sinks.out_es] 
  46.   # General 
  47.   type = "elasticsearch" 
  48.   inputs = ["coercer"
  49.   compression = "none"  
  50.   endpoint = "http://host.docker.internal:9200"  
  51.   index = "syslog-%F" 
  52.  
  53.   # Encoding 
  54.  
  55.   # Healthcheck 
  56.   healthcheck.enabled = true 

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

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

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

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

返回所有的记录:

  1. # ES 
  2.   "query":{ 
  3.     "match_all":{} 
  4.   } 
  5.  
  6. # Clickhouse  
  7. "SELECT * FROM syslog" 

匹配单个字段:

  1. # ES 
  2.   "query":{ 
  3.     "match":{ 
  4.       "hostname":"for.org" 
  5.     } 
  6.   } 
  7.  
  8. # Clickhouse  
  9. "SELECT * FROM syslog WHERE hostname='for.org'" 

匹配多个字段:

  1. # ES 
  2.   "query":{ 
  3.     "multi_match":{ 
  4.       "query":"up.com ahmadajmi"
  5.         "fields":[ 
  6.           "hostname"
  7.           "application" 
  8.         ] 
  9.     } 
  10.   } 
  11.  
  12. # Clickhouse、 
  13. "SELECT * FROM syslog WHERE hostname='for.org' OR application='ahmadajmi'" 

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

  1. # ES 
  2.   "query":{ 
  3.     "term":{ 
  4.       "message":"pretty" 
  5.     } 
  6.   } 
  7.  
  8. # Clickhouse 
  9. "SELECT * FROM syslog WHERE lowerUTF8(raw) LIKE '%pretty%'" 

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

  1. # ES 
  2.   "query":{ 
  3.     "range":{ 
  4.       "version":{ 
  5.         "gte":2 
  6.       } 
  7.     } 
  8.   } 
  9.  
  10. # Clickhouse 
  11. "SELECT * FROM syslog WHERE version >= 2" 

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

  1. # ES 
  2.   "query":{ 
  3.     "exists":{ 
  4.       "field":"application" 
  5.     } 
  6.   } 
  7.  
  8. # Clickhouse 
  9. "SELECT * FROM syslog WHERE application is not NULL" 

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

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

  1. # ES 
  2.   "query":{ 
  3.     "regexp":{ 
  4.       "hostname":{ 
  5.         "value":"up.*"
  6.           "flags":"ALL"
  7.             "max_determinized_states":10000, 
  8.               "rewrite":"constant_score" 
  9.       } 
  10.     } 
  11.   } 
  12.  
  13. # Clickhouse 
  14. "SELECT * FROM syslog WHERE match(hostname, 'up.*')" 

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

  1. # ES 
  2.   "aggs":{ 
  3.     "version_count":{ 
  4.       "value_count":{ 
  5.         "field":"version" 
  6.       } 
  7.     } 
  8.   } 
  9.  
  10. # Clickhouse 
  11. "SELECT count(version) FROM syslog" 

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

  1. # ES 
  2.   "aggs":{ 
  3.     "my-agg-name":{ 
  4.       "cardinality":{ 
  5.         "field":"priority" 
  6.       } 
  7.     } 
  8.   } 
  9.  
  10. # Clickhouse 
  11. "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

 

来源:知乎内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯