乐趣区

关于clickhouse:记一次-ClickHouse-性能测试

前言

在工作场景中,咱们会采集工厂设施数据用于智能管制,数据的存储用了 InfluxDB,随着数据规模越来越大,InfluxDB 的性能越来越差,故思考引入 ClickHouse 分担 InfluxDB 大数据分析的压力,再加上咱们业务上也用到了 MySQL,所以本文就来比照下 MySQL、InfluxDB、ClickHouse 在千万数据量下的写入耗时、聚合查问耗时、磁盘占用等各方面性能指标。

论断后行

最终的论断是,间接应用 ClickHouse 官网提供的 6600w 数据集来做比照测试,在 MySQL、InfluxDB、ClickHouse 同样调配 4c16g 资源的状况下,ClickHouse 无论是导入速度、磁盘占用、查问性能都齐全碾压 MySQL 和 InfluxDB,具体比照指标如以下表格:

MySQL InfluxDB ClickHouse
导入耗时 大略耗时 70 分钟 大略耗时 35 分钟 75 秒
磁盘空间 12.35 G 5.9 G 2.66 G
全表 count 24366 ms 11674 ms 100 ms
全表 max/min 27023 ms 26829 ms 186 ms
全表平均值 24841 ms 12043 ms 123 ms
全表方差 24600 ms OOM 113 ms
简单查问 1 30260 ms OOM 385 ms
简单查问 2 470 ms 200 ms 8 ms

为了确保测试后果绝对精确,以上每条 sql 起码执行 5 次,而后取两头值。其中 InfluxDB 体现比设想中的要差,甚至还不如 MySQL,可能是数据样本和测试用例不太适宜 InfluxDB 场景导致的,如果大家对测试后果有疑难,能够 git clone [https://github.com/stone0090/clickhouse-test.git](https://github.com/stone0090/clickhouse-test.git) 我的项目,残缺验证以上比照全过程。

数据库简介

MySQL

MySQL 是一个关系型数据库管理系统,由瑞典 MySQL AB 公司开发,属于 Oracle 旗下产品,是最风行的关系型数据库管理系统之一。它所应用的 SQL 语言是用于拜访数据库的最罕用标准化语言。它采纳了双受权政策,分为社区版和商业版,因为其体积小、速度快、总体领有成本低,尤其是开放源码这一特点,个别中小型和大型网站的开发都抉择 MySQL 作为网站数据库。《高性能 MySQL》一书中开篇明义讲到的最外围的一句话是“MySQL 并不完满,然而却足够灵便”,它是架构中的万金油,庞杂非繁多的我的项目中总会有它的用武之地。

InfluxDB

InfluxDB 是一个由 InfluxData 公司开发的开源时序型数据库,专一于海量时序数据的高性能读、高性能写、高效存储与实时剖析,在 DB-Engines Ranking 时序型数据库排行榜上位列榜首,广泛应用于 DevOps 监控、IoT 监控、实时剖析等场景。
传统数据库通常记录数据的以后值,时序型数据库则记录所有的历史数据,在解决以后时序数据时又要一直接管新的时序数据,同时时序数据的查问也总是以工夫为根底查问条件,并专一于解决以下海量数据场景的问题:

  • 时序数据的写入:如何反对千万级 / 秒数据的写入;
  • 时序数据的读取:如何反对千万级 / 秒数据的聚合和查问;
  • 老本敏感:海量数据存储带来的是老本问题,如何更低成本地存储这些数据。

ClickHouse

ClickHouse 是 Yandex(俄罗斯最大的搜索引擎)开源的一个用于实时数据分析的基于列存储的数据库,其解决数据的速度比传统办法快 100-1000 倍。ClickHouse 的性能超过了目前市场上可比的面向列的 DBMS,每秒钟每台服务器每秒解决数亿至十亿多行和数十千兆字节的数据。它是一个用于联机剖析(OLAP)的列式数据库管理系统(DBMS),简略介绍一下 OLTP 和 OLAP。

  • OLTP:是传统的关系型数据库,次要操作增删改查,强调事务一致性,比方银行零碎、电商零碎。
  • OLAP:是仓库型数据库,次要是读取数据,做简单数据分析,偏重技术决策反对,提供直观简略的后果。

那 ClickHouse OLAP 实用场景有:1)读多于写;2)大宽表,读大量行然而少量列,后果集较小;3)数据批量写入,且数据不更新或少更新;4)无需事务,数据一致性要求低;5)灵便多变,不适宜事后建模。

环境筹备

在阿里云买一台 16c64g 的服务器,操作系统 centos 7.8,应用 sealos 一键装置 k8s,应用 helm 一键装置 mysql(5.7)、influxdb(1.8)、clickhouse(22.3),每个利用各调配 4c16g 的资源。

# 下载 sealos
$ wget https://github.com/labring/sealos/releases/download/v4.0.0/sealos_4.0.0_linux_amd64.tar.gz \
&& tar zxvf sealos_4.0.0_linux_amd64.tar.gz sealos && chmod +x sealos && mv sealos /usr/bin

# 初始化一个单节点 Kubernetes
$ sealos run labring/kubernetes:v1.24.0 labring/calico:v3.22.1 --masters [xxx.xxx.xxx.xxx] -p [your-ecs-password]

# 去掉 master 的污点,容许装置利用到 master 和 control-plane
$ kubectl taint nodes --all node-role.kubernetes.io/master-
$ kubectl taint nodes --all node-role.kubernetes.io/control-plane-

# 获取 mysql、influxdb、clickhouse 一键装置 Helm-Charts
$ wget https://github.com/stone0090/clickhouse-test/archive/refs/tags/v1.0.0.tar.gz
$ tar -zxvf v1.0.0.tar.gz

# 装置 Kubernetes 包管理工具 Helm,以及 mysql、influxdb、clickhouse 3 大数据库
$ sealos run labring/helm:v3.8.2
$ helm install mysql clickhouse-test-1.0.0/helm-charts/mysql/
$ helm install influxdb clickhouse-test-1.0.0/helm-charts/influxdb/
$ helm install clickhouse clickhouse-test-1.0.0/helm-charts/clickhouse/

数据导入

间接应用 ClickHouse 官网提供的测试数据 https://clickhouse.com/docs/zh/getting-started/example-datasets/opensky,此数据集中的数据是从残缺的 OpenSky 数据集中派生和清理而来的,以阐明 COVID-19 新冠肺炎大风行期间空中交通的倒退状况。它涵盖了自 2019 年 1 月 1 日以来该网络超过 2500 名成员看到的所有航班,总数据量有 6600w。

# 在服务器 /home/flightlist 目录执行以下命令,该目录会被挂载到 mysql-pod、influxdb-pod、clickhouse-pod 内
$ wget -O- https://zenodo.org/record/5092942 | grep -oP 'https://zenodo.org/record/5092942/files/flightlist_\d+_\d+\.csv\.gz' | xargs wget

# 批量解压 flightlist.gz 数据
$ for file in flightlist_*.csv.gz; do gzip -d "$file"; done

# 将 csv 解决成 influxdb 导入所需的 txt 格局(此过程大略耗时 1 小时)$ python clickhouse-test-1.0.0/influxdb_csv2txt.py

MySQL

# 进入 mysql pod
$ kubectl exec -it [influxdb-podname] -- bash

# 连上 mysql 建库、建表
$ mysql -uroot -p123456
$ use test;
$ CREATE TABLE `opensky` (`callsign` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,`number` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,`icao24` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,`registration` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,`typecode` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,`origin` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,`destination` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,`firstseen` datetime DEFAULT NULL,`lastseen` datetime DEFAULT NULL,`day` datetime DEFAULT NULL,`latitude_1` double DEFAULT NULL,`longitude_1` double DEFAULT NULL,`altitude_1` double DEFAULT NULL,`latitude_2` double DEFAULT NULL,`longitude_2` double DEFAULT NULL,`altitude_2` double DEFAULT NULL,KEY `idx_callsign` (`callsign`),KEY `idx_origin` (`origin`),KEY `idx_destination` (`destination`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

# 导入数据(大略耗时 70 分钟)$ load data local infile 'flightlist_20190101_20190131.csv' into table opensky character set utf8mb4 fields terminated by ',' lines terminated by '\n' ignore 1 lines;
# 省略其余 29 条导入命令:load data local infile 'flightlist_*_*.csv' into table opensky character set utf8mb4 fields terminated by ',' lines terminated by '\n' ignore 1 lines;

# 检查数据是否导入胜利
$ select count(*) from test.opensky;

InfluxDB

# 进入 influxdb pod
$ kubectl exec -it [influxdb-podname] -- bash

# 导入数据(大略耗时 30 分钟)$ influx -username 'admin' -password 'admin123456' -import -path=/tmp/flightlist/flightlist_20190101_20190131.txt -precision=ns;
# 省略其余 29 条导入命令:influx -username 'admin' -password 'admin123456' -import -path=/tmp/flightlist/flightlist_*_*.txt -precision=ns;

# 检查数据是否导入胜利
$ influx -username 'admin' -password 'admin123456'
$ select count(latitude_1) from test.autogen.opensky;

ClickHouse

# 进入 clickhouse pod
$ kubectl exec -it [clickhouse-podname] -- bash

# 连上 clickhouse 建库、建表
$ clickhouse-client
$ create database test;
$ use test;
$ CREATE TABLE opensky(callsign String,number String,icao24 String,registration String,typecode String,origin String,destination String,firstseen DateTime,lastseen DateTime,day DateTime,latitude_1 Float64,longitude_1 Float64,altitude_1 Float64,latitude_2 Float64,longitude_2 Float64,altitude_2 Float64) ENGINE = MergeTree ORDER BY (origin, destination, callsign);
$ exit

# 导入数据(大略耗时 75 秒)$ cd /tmp/flightlist
$ for file in flightlist_*.csv; do cat "$file" | clickhouse-client --date_time_input_format best_effort --query "INSERT INTO test.opensky FORMAT CSVWithNames"; done

# 检查数据是否导入胜利
$ clickhouse-client
$ SELECT count() FROM test.opensky;

测试场景

MySQL

$ mysql -uroot -p123456
$ use test;
-- 开启性能剖析
set profiling = 1;
-- 查问磁盘空间
select table_rows as ` 总行数 `, (data_length + index_length)/1024/1024/1024 as ` 磁盘占用 (G)` from information_schema.`TABLES` where table_name = 'opensky';
-- 全表 count
select count(latitude_1) from opensky;
-- 全表 max/min
select max(longitude_1),min(altitude_1) from opensky;
-- 全表平均值
select avg(latitude_2) from opensky;
-- 全表方差
select var_pop(longitude_2) from opensky;
-- 简单查问 1:全表多个字段聚合查问
select count(latitude_1),max(longitude_1),min(altitude_1),avg(latitude_2) from opensky;
-- 简单查问 2:从莫斯科三个次要机场腾飞的航班数量
SELECT origin, count(1) AS c FROM opensky WHERE origin IN ('UUEE', 'UUDD', 'UUWW') GROUP BY origin;
-- 输入剖析后果
show profiles;

InfluxDB

$ influx -username 'admin' -password 'admin123456'
$ use test;
-- 耗时统计,queryReqDurationNs 是累计查问工夫,2 次工作的工夫相减就是耗时
select queryReq,queryReqDurationNs/1000/1000,queryRespBytes from _internal."monitor".httpd order by time desc limit 10;
-- 查问磁盘空间
select sum(diskBytes) / 1024 / 1024 /1024 from _internal."monitor"."shard" where time > now() - 10s group by "database";
-- 全表 count
select count(latitude_1) from opensky;
-- 全表 max/min
select max(longitude_1),min(altitude_1) from opensky;
-- 全表平均值
select mean(latitude_2) from opensky;
-- 全表方差
select stddev(longitude_2) from opensky;
-- 简单查问 1:全表多个字段聚合查问
select count(latitude_1),max(longitude_1),min(altitude_1),mean(latitude_2) from opensky;
-- 简单查问 2:从莫斯科三个次要机场腾飞的航班数量
SELECT count(latitude_1) AS c FROM opensky WHERE origin =~/^UUEE|UUDD|UUWW$/ GROUP BY origin;

ClickHouse

$ clickhouse-client
$ use test;
-- 耗时统计
select event_time_microseconds,query_duration_ms,read_rows,result_rows,memory_usage,query from system.query_log where query like '%opensky%' and query_duration_ms <> 0 and query not like '%event_time_microseconds%' order by event_time_microseconds desc limit 5;
-- 查问磁盘空间
SELECT formatReadableSize(total_bytes) FROM system.tables WHERE name = 'opensky';
-- 全表 count
select count(latitude_1) from opensky;
-- 全表 max/min
select max(longitude_1),min(altitude_1) from opensky;
-- 全表平均值
select avg(latitude_2) from opensky;
-- 全表方差
select var_pop(longitude_2) from opensky;
-- 简单查问 1:全表多个字段聚合查问
select count(latitude_1),max(longitude_1),min(altitude_1),avg(latitude_2) from opensky;
-- 简单查问 2:从莫斯科三个次要机场腾飞的航班数量
SELECT origin, count() AS c FROM opensky WHERE origin IN ('UUEE', 'UUDD', 'UUWW') GROUP BY origin;

ClickHouse 为什么快

1、列式存储

数据是按列存储,数据即是索引;查问只拜访波及的列,升高零碎 I /O;每一列都由一个线程来解决,高效利用 CPU 资源;还为向量化执行做好了铺垫。

2、数据压缩

数据压缩的实质是依照肯定的步长对数据进行匹配扫描,当发现反复数据的时候就进行编码转换。
因为是列式存储,所以数据特色很类似,所以数据中的反复项多,则压缩率越高,则数据体量越小,则磁盘 I / O 压力越小,则网络中传输越快。

3、向量化执行引擎

SIMD(Single Instruction Multiple Data)即单条指令操作多条数据,它是通过数据并行以进步性能的一种形式,能够简略了解为在寄存器层面对程序中的数据做并行处理,Clickhouse 在可能晋升计算效率的中央大量应用了 SIMD,通过应用 SIMD,基本上能带来几倍的性能晋升。

4、多线程和分布式

分布式畛域存在一条定律,计算挪动比数据挪动更加划算,这也是其外围所在,将数据的计算间接发放到数据所在的服务器,多机并行处理,再把最终的后果会集在一起;另外 ClickHouse 也通过线程级别并行的形式为效率进一步提速,极致去利用服务器的资源。

5、多样的表引擎

MergeTree 存储构造对写入的数据做排序而后进行有序存储,有序存储次要有两大劣势:

  • 列存文件在按块做压缩时,排序键中的列值是间断或者反复的,使得列存块的数据能够取得极致的压缩比;
  • 存储有序自身能够减速查问的索引构造,依据排序键中列的等值条件或者 rang 条件,咱们能够疾速找到指标所在的近似地位区间,并且这种索引构造是不会产生额定的存储开销。

MergeTree 是 ClickHouse 表引擎中最外围的引擎,其余引擎均以 MergeTree 引擎为根底,并在数据合并过程中实现了不同的个性,从而形成了 MergeTree 表引擎家族。

ClickHouse 的优缺点

长处:极致的查问剖析性能,较低的存储老本,高吞吐的数据写入,多样化的表引擎,齐备的 DBMS 性能;
毛病:不反对事务,不反对真正的删除 / 更新,分布式能力较弱;不反对高并发,官网倡议 QPS 为 100;非标准的 SQL,join 的实现比拟非凡,且性能不好;频繁小批量数据操作会影响查问性能;
目前还没有一个 OLAP 引擎可能满足各种场景的需要,其本质起因是,没有一个零碎能同时在查问效率、时效性、可维护性三个方面做到完满,只能说 ClickHouse 是为了极致查问性能做了一些取舍。
ClickHouse 优缺点都很显著,是否采纳还是要取决于和理论业务场景的符合度,适宜本人的架构才是最好架构。

参考援用

  • 识堂 | 笔记分享探讨社区,让常识谈话
  • InfluxDB 优化配置项_sqtce 的技术博客_51CTO 博客
  • influxDB 系列(二)– 查看数据库的大小 – 立志做一个好的程序员 – 博客园
  • Clickhouse 技术分享_大数据_scalad_InfoQ 写作社区
退出移动版