最近看到一篇由Alexander Zaitsev撰寫的,關于ClickHouse性能對比的文章(文末會有報告的原文位址),覺得很有意思,是以拿來與大家分享一下。它有趣的地方在于,這是一篇針對性能對标的,性能對标測評。這算不算螳螂捕蟬,黃雀在後呢?
這篇文章的對标場景,來自于ScyllaDB的一篇測評報告,而在這篇報告中,ScyllaDB曆數了從2001年至今,NoSql資料庫性能達到的幾個關鍵裡程碑。而如今他們宣稱,ScyllaDB能夠在5000億的資料量,以 10億行/每秒 的性能處理資料。
ScyllaDB的測試方案
在ScyllaDB的測試方案中,他們模拟了物聯網的使用場景:
測試資料
資料來自于家庭安裝的溫度傳感器,這些溫度傳感器每隔 1 分鐘讀數一次。
是以,1百萬個傳感器,1年下來的資料量将會是:
1,000,000 24 60 * 365 = 5256 億
硬體配置
在伺服器硬體方面,他們采用了packet.com的雲服務,使用了83個 n2.xlarge.x86 執行個體作為database節點,以及24個 c2.medium.x86 執行個體作為輔助的worker節點。
這真可謂是超豪華陣容,節點配置分别如下:
database | work | |
---|---|---|
類型 | n2.xlarge.x86 | c2.medium.x86 |
CPU | 28 Physical Cores @ 2.2 GHz | 24 Physical Cores @ 2.2 GHz |
Memory | 384 GB of DDR4 ECC RAM | 64 GB of ECC RAM |
Storage | 3.8TB of NVMe Flash | 960 GB of SSD |
Network | 4 × 10GBPS | 2 × 10GBPS |
測試目标
解答這麼幾個問題:
- 從時間跨度為3個月的資料中,分别找到溫度最高和最低的那一天,以及這些讀數來自于哪個傳感器;
- 從整年的資料中,分别找到溫度最高和最低的那一天,以及這些讀數來自于哪個傳感器;
- 在測試資料中,事先埋入了一些壞的測點,在查詢中排除這些壞的測點(像不像大海撈針)。
ClickHouse的黑科技
Alexander在看到這篇文章之後,覺得它們的測試方案太不經濟了,如果使用ClickHouse的黑魔法,能夠在達到同樣業務需求的背景下,擁有更好的成本效益。一不做二不休,Alexander決定使用一台NUC迷你主機作為ClickHouse的測試硬體。
喪心病狂的硬體對比如下:
ClickHouse | ScyllaDB | |
---|---|---|
模式 | 單節點 | 叢集 |
伺服器 | 1 台 Intel NUC | 83台 n2.xlarge.x86 database節點, 24台 c2.medium.x86 worker 節點 |
4 cores (Intel i7-6770HQ) | 2900 cores = 83 x 28 cores (Intel Xeon Gold 5120) + 24 x 24 cores (AMD EPYC 7401p) | |
32 GB | 33408 GB = 83 x 384 GB + 24 x 64 GB | |
1 TB NVMe SSD | 338 TB = 83 x 3.8TB NVMe SSD + 24 x 960GB SSD |
在ClickHouse的對比方案中,它與對手的配置差距總是如此之大。
然而,即便在記憶體相差1000倍的情況下,ClickHouse仍然比對手擁有10~100倍的性能。
# 耳聽為虛眼見為實
ClickHouse真的有這麼誇張的性能嗎? 光道聽途說可不行, 咱必須得親自試試,可是我身邊也沒迷你主機啊,隻能拿筆記本 + 虛拟機湊活
虛拟機系統Centos 7, 配置4 cores, 32G:
uname -a
Linux ch6.nauu.com 3.10.0-1062.el7.x86_64 #1 SMP Wed Aug 7 18:08:02 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
[root@ch6 ~]#
[root@ch6 ~]# free -g
total used free shared buff/cache available
Mem: 31 0 30 0 0 30
Swap: 1 0 1
[root@ch6 ~]# grep 'core id' /proc/cpuinfo | sort -u | wc -l
4
ClickHouse版本19.17.4
按照Alexander的例子,首先需要建立一張儲存傳感器資料的測試表:
CREATE TABLE sensors_data (
sensor_id Int32 Codec(DoubleDelta, LZ4),
time DateTime Codec(DoubleDelta, LZ4),
date ALIAS toDate(time),
temperature Decimal(5,2) Codec(T64, LZ4)
) Engine = MergeTree
PARTITION BY toYYYYMM(time)
ORDER BY (sensor_id, time);
在這張資料表的定義中,可謂是做到了極緻的優化。包括:
- 針對每一個列字段,都單獨聲明了它的encode編碼算法和compresss壓縮算法,這是ClickHouse的一個新特性。簡而言之,如果是時間序列的資料,推薦使用DoubleDelta和LZ4的組合;而在資料模式不明确的情況下,可以使用T64和LZ4的組合。關于算法的這一塊的介紹,以後有時間可以專門寫一篇說明;
- date類型使用了 ALIAS 計算字段,降低了存儲開銷;
- 分區Key和主鍵Key,很好的比對了業務的查詢條件。如此一來,在後續的查詢中,就能夠充分利用MergeTree的分區索引和一級索引。
有了資料表之後,就可以開始模拟測試資料了,Alexander使用了numbers_mt函數,模拟了5256億溫度資料:
INSERT INTO sensors_data (sensor_id, time, temperature) \
WITH \
toDateTime(toDate('2019-01-01')) as start_time, \
1000000 as num_sensors, \
365 as num_days, \
24*60 as num_minutes, \
num_days * num_minutes as total_minutes \
SELECT \
intDiv(number, num_minutes) % num_sensors as sensor_id, \
start_time + (intDiv(number, num_minutes*num_sensors) as day)*24*60*60 + (number % num_minutes as minute)*60 time, \
60 + 20*sin(cityHash64(sensor_id)) \
+ 15*sin(2*pi()/num_days*day) \
+ 10*sin(2*pi()/num_minutes*minute)*(1 + rand(1)%100/2000) \
+ if(sensor_id = 473869 and \
time between '2019-08-27 13:00:00' and '2019-08-27 13:05:00', -50 + rand(2)%100, 0) \
as temperature \
FROM numbers_mt(525600000000) \
SETTINGS max_block_size=1048576;
接下來幹什麼呢?接下來可以去睡覺了。由于是單線程寫入,我粗略計算了一下,大概隻要40~50個小時,資料就能全部寫進去了 !!!
在這段等待的時間,我們繼續往下分析。當資料寫完之後,這張 sensors_data 資料表并不能直接作為查詢表使用,還需要進一步為它建立物化視圖:
CREATE MATERIALIZED VIEW sensors_data_daily( \
sensor_id Int32 Codec(DoubleDelta, LZ4), \
date Datetime Codec(DoubleDelta, LZ4), \
temp_min SimpleAggregateFunction(min, Decimal(5,2)), \
temp_max SimpleAggregateFunction(max, Decimal(5,2)) \
) Engine = AggregatingMergeTree \
PARTITION BY toYYYYMM(date) \
ORDER BY (sensor_id, date) \
POPULATE \
AS \
SELECT sensor_id, date, \
min(temperature) as temp_min, \
max(temperature) as temp_max \
FROM sensors_data \
GROUP BY sensor_id, date;
物化視圖會自動同步sensors_data的資料。
由于使用了AggregatingMergeTree表引擎,資料在AggregatingMergeTree合并分區的過程中,會以分區目錄為機關,按照 sensor_id和date預先聚合。
是以,這裡其實是玩了一個ClickHouse的常用技巧,那就是利用物化視圖進行了預聚合的優化。使用物化視圖和MergeTree組合使用,是ClickHouse的殺手锏之一。
在這個例子中,有點類似資料立方體的意思,通過預聚合, 将聚合結果預先存在表内,在之後查詢的過程中,可以從結果直接傳回。與此同時,預先聚合還能有效的減少資料行,在這個例子中,最終能将視圖内的資料行減少1400倍之多。
正如ScyllaDB的文章中所說,他們的測試并不是一場 apples to apples 的比較。同樣的,我想Alexander拿ClickHouse做的這場比較,也不是針尖對麥芒的。它們兩者之間有着太多的不同,它們使用了不同的資料模型、不同的架構等等。
但是通過這個案例的對比,大家可以認識到ClickHouse确實是經濟和性能的完美平衡。如果你的業務也有類似的場景,使用ClickHouse将會是一種不錯的選擇。
由于我的資料還沒寫完。。。 關于論證的結果,隻能留在下一篇了。