本文首發於我的個人博客:ClickHouse簡介
什麼是ClickHouse?
ClickHouse是一個用於聯機分析(OLAP)的列式數據庫管理系統(DBMS)。
在傳統的行式數據庫系統中,數據按如下順序存儲:
Row | WatchID | JavaEnable | Title | GoodEvent | EventTime |
---|---|---|---|---|---|
#0 | 89354350662 | 1 | Investor Relations | 1 | 2016/5/18 5:19 |
#1 | 90329509958 | 0 | Contact us | 1 | 2016/5/18 8:10 |
#2 | 89953706054 | 1 | Mission | 1 | 2016/5/18 7:38 |
#N | … | … | … | … | … |
處於同一行中的數據總是被物理的存儲在一起。
常見的行式數據庫系統有:MySQL
、Postgres
和MS SQL Server
。
在列式數據庫系統中,數據按如下的順序存儲:
Row: | #0 | #1 | #2 | #N |
---|---|---|---|---|
WatchID: | 89354350662 | 90329509958 | 89953706054 | … |
JavaEnable: | 1 | 0 | 1 | … |
Title: | Investor Relations | Contact us | Mission | … |
GoodEvent: | 1 | 1 | 1 | … |
EventTime: | 2016/5/18 5:19 | 2016/5/18 8:10 | 2016/5/18 7:38 | … |
這些示例只顯示了數據的排列順序。來自不同列的值被單獨存儲,來自同一列的數據被存儲在一起。
常見的列式數據庫有: Vertica、 Paraccel (Actian Matrix,Amazon Redshift)、 Sybase IQ、 Exasol、 Infobright、 InfiniDB、 MonetDB (VectorWise, Actian Vector)、 LucidDB、 SAP HANA、 Google Dremel、 Google PowerDrill、 Druid、 kdb+。
不同的數據存儲方式適用不同的業務場景,數據訪問的場景包括:進行了何種查詢、多久查詢一次以及各類查詢的比例;每種類型的查詢(行、列和字節)讀取多少數據;讀取數據和更新之間的關係;使用的數據集大小以及如何使用本地的數據集;是否使用事務,以及它們是如何進行隔離的;數據的複製機制與數據的完整性要求;每種類型的查詢要求的延遲與吞吐量等等。
系統負載越高,依據使用場景進行定製化就越重要,並且定製將會變的越精細。沒有一個系統能夠同時適用所有不同的業務場景。如果系統適用於廣泛的場景,在負載高的情況下,要兼顧所有的場景,那麼將不得不做出選擇。是要平衡還是要效率?
OLAP場景的關鍵特徵
-
絕大多數是讀請求
-
數據以相當大的批次(> 1000行)更新,而不是單行更新;或者根本沒有更新。
-
已添加到數據庫的數據不能修改。
-
對於讀取,從數據庫中提取相當多的行,但只提取列的一小部分。
-
寬表,即每個表包含着大量的列
-
查詢相對較少(通常每臺服務器每秒查詢數百次或更少)
-
對於簡單查詢,允許延遲大約50毫秒
-
列中的數據相對較小:數字和短字符串(例如,每個URL 60個字節)
-
處理單個查詢時需要高吞吐量(每臺服務器每秒可達數十億行)
-
事務不是必須的
-
對數據一致性要求低
-
每個查詢有一個大表。除了他以外,其他的都很小。
-
查詢結果明顯小於源數據。換句話說,數據經過過濾或聚合,因此結果適合於單個服務器的RAM中
很容易可以看出,OLAP場景與其他通常業務場景(例如,OLTP或K/V)有很大的不同, 因此想要使用OLTP或Key-Value數據庫去高效的處理分析查詢場景,並不是非常完美的適用方案。例如,使用OLAP數據庫去處理分析請求通常要優於使用MongoDB或Redis去處理分析請求。
列式數據庫更適合OLAP場景的原因
列式數據庫更適合於OLAP場景(對於大多數查詢而言,處理速度至少提高了100倍),下面詳細解釋了原因(通過圖片更有利於直觀理解):
行式
列式
看到差別了麼?下面將詳細介紹爲什麼會發生這種情況。
輸入/輸出
- 針對分析類查詢,通常只需要讀取表的一小部分列。在列式數據庫中你可以只讀取你需要的數據。例如,如果只需要讀取100列中的5列,這將幫助你最少減少20倍的I/O消耗。
- 由於數據總是打包成批量讀取的,所以壓縮是非常容易的。同時數據按列分別存儲這也更容易壓縮。這進一步降低了I/O的體積。
- 由於I/O的降低,這將幫助更多的數據被系統緩存。
例如,查詢«統計每個廣告平臺的記錄數量»需要讀取«廣告平臺ID»這一列,它在未壓縮的情況下需要1個字節進行存儲。如果大部分流量不是來自廣告平臺,那麼這一列至少可以以十倍的壓縮率被壓縮。當採用快速壓縮算法,它的解壓速度最少在十億字節(未壓縮數據)每秒。換句話說,這個查詢可以在單個服務器上以每秒大約幾十億行的速度進行處理。這實際上是當前實現的速度。
CPU
由於執行一個查詢需要處理大量的行,因此在整個向量上執行所有操作將比在每一行上執行所有操作更加高效。同時這將有助於實現一個幾乎沒有調用成本的查詢引擎。如果你不這樣做,使用任何一個機械硬盤,查詢引擎都不可避免的停止CPU進行等待。所以,在數據按列存儲並且按列執行是很有意義的。
有兩種方法可以做到這一點:
-
向量引擎:所有的操作都是爲向量而不是爲單個值編寫的。這意味着多個操作之間的不再需要頻繁的調用,並且調用的成本基本可以忽略不計。操作代碼包含一個優化的內部循環。
-
代碼生成:生成一段代碼,包含查詢中的所有操作。
這是不應該在一個通用數據庫中實現的,因爲這在運行簡單查詢時是沒有意義的。但是也有例外,例如,MemSQL使用代碼生成來減少處理SQL查詢的延遲(只是爲了比較,分析型數據庫通常需要優化的是吞吐而不是延遲)。
請注意,爲了提高CPU效率,查詢語言必須是聲明型的(SQL或MDX), 或者至少一個向量(J,K)。 查詢應該只包含隱式循環,允許進行優化。
ClickHouse的特性
真正的列式數據庫管理系統
在一個真正的列式數據庫管理系統中,除了數據本身外不應該存在其他額外的數據。這意味着爲了避免在值旁邊存儲它們的長度«number»,你必須支持固定長度數值類型。例如,10億個UInt8類型的數據在未壓縮的情況下大約消耗1GB左右的空間,如果不是這樣的話,這將對CPU的使用產生強烈影響。即使是在未壓縮的情況下,緊湊的存儲數據也是非常重要的,因爲解壓縮的速度主要取決於未壓縮數據的大小。
這是非常值得注意的,因爲在一些其他系統中也可以將不同的列分別進行存儲,但由於對其他場景進行的優化,使其無法有效的處理分析查詢。例如: HBase,BigTable,Cassandra,HyperTable。在這些系統中,你可以得到每秒數十萬的吞吐能力,但是無法得到每秒幾億行的吞吐能力。
需要說明的是,ClickHouse不單單是一個數據庫, 它是一個數據庫管理系統。因爲它允許在運行時創建表和數據庫、加載數據和運行查詢,而無需重新配置或重啓服務。
數據壓縮
在一些列式數據庫管理系統中(例如:InfiniDB CE 和 MonetDB) 並沒有使用數據壓縮。但是, 若想達到比較優異的性能,數據壓縮確實起到了至關重要的作用。
除了在磁盤空間和CPU消耗之間進行不同權衡的高效通用壓縮編解碼器之外,ClickHouse還提供針對特定類型數據的專用編解碼器,這使得ClickHouse能夠與更小的數據庫(如時間序列數據庫)競爭並超越它們。
數據的磁盤存儲
許多的列式數據庫(如 SAP HANA, Google PowerDrill)只能在內存中工作,這種方式會造成比實際更多的設備預算。
ClickHouse被設計用於工作在傳統磁盤上的系統,它提供每GB更低的存儲成本,但如果可以使用SSD和內存,它也會合理的利用這些資源。
多核心並行處理
ClickHouse會使用服務器上一切可用的資源,從而以最自然的方式並行處理大型查詢。
多服務器分佈式處理
上面提到的列式數據庫管理系統中,幾乎沒有一個支持分佈式的查詢處理。 在ClickHouse中,數據可以保存在不同的shard上,每一個shard都由一組用於容錯的replica組成,查詢可以並行地在所有shard上進行處理。這些對用戶來說是透明的
支持SQL
ClickHouse支持一種基於SQL的聲明式查詢語言,它在許多情況下與ANSI SQL標準相同。
支持的查詢GROUP BY, ORDER BY, FROM, JOIN, IN以及非相關子查詢。
相關(依賴性)子查詢和窗口函數暫不受支持,但將來會被實現。
向量引擎
爲了高效的使用CPU,數據不僅僅按列存儲,同時還按向量(列的一部分)進行處理,這樣可以更加高效地使用CPU。
實時的數據更新
ClickHouse支持在表中定義主鍵。爲了使查詢能夠快速在主鍵中進行範圍查找,數據總是以增量的方式有序的存儲在MergeTree中。因此,數據可以持續不斷地高效的寫入到表中,並且寫入的過程中不會存在任何加鎖的行爲。
索引
按照主鍵對數據進行排序,這將幫助ClickHouse在幾十毫秒以內完成對數據特定值或範圍的查找。
適合在線查詢
在線查詢意味着在沒有對數據做任何預處理的情況下以極低的延遲處理查詢並將結果加載到用戶的頁面中。
支持近似計算
ClickHouse提供各種各樣在允許犧牲數據精度的情況下對查詢進行加速的方法:
用於近似計算的各類聚合函數,如:distinct values, medians, quantiles
基於數據的部分樣本進行近似查詢。這時,僅會從磁盤檢索少部分比例的數據。
不使用全部的聚合條件,通過隨機選擇有限個數據聚合條件進行聚合。這在數據聚合條件滿足某些分佈條件下,在提供相當準確的聚合結果的同時降低了計算資源的使用。
自適應連接算法
ClickHouse支持自定義JOIN多個表,它更傾向於散列連接算法,如果有多個大表,則使用合併-連接算法
支持數據複製和數據完整性
ClickHouse使用異步的多主複製技術。當數據被寫入任何一個可用副本後,系統會在後臺將數據分發給其他副本,以保證系統在不同副本上保持相同的數據。在大多數情況下ClickHouse能在故障後自動恢復,在一些少數的複雜情況下需要手動恢復。
更多信息,參見 數據複製。
角色的訪問控制
ClickHouse使用SQL查詢實現用戶帳戶管理,並允許角色的訪問控制,類似於ANSI SQL標準和流行的關係數據庫管理系統。
限制
沒有完整的事務支持。
缺少高頻率,低延遲的修改或刪除已存在數據的能力。僅能用於批量刪除或修改數據,但這符合 GDPR。
稀疏索引使得ClickHouse不適合通過其鍵檢索單行的點查詢。
ClickHouse的性能
根據Yandex的內部測試結果,ClickHouse表現出了比同類可比較產品更優的性能。你可以在 這裏 查看具體的測試結果。
許多其他的測試也證實這一點。你可以使用互聯網搜索到它們,或者你也可以從 我們收集的部分相關連接 中查看。
單個大查詢的吞吐量
吞吐量可以使用每秒處理的行數或每秒處理的字節數來衡量。如果數據被放置在page cache中,則一個不太複雜的查詢在單個服務器上大約能夠以2-10GB/s(未壓縮)的速度進行處理(對於簡單的查詢,速度可以達到30GB/s)。如果數據沒有在page cache中的話,那麼速度將取決於你的磁盤系統和數據的壓縮率。例如,如果一個磁盤允許以400MB/s的速度讀取數據,並且數據壓縮率是3,則數據的處理速度爲1.2GB/s。這意味着,如果你是在提取一個10字節的列,那麼它的處理速度大約是1-2億行每秒。
對於分佈式處理,處理速度幾乎是線性擴展的,但這受限於聚合或排序的結果不是那麼大的情況下。
處理短查詢的延遲時間
如果一個查詢使用主鍵並且沒有太多行(幾十萬)進行處理,並且沒有查詢太多的列,那麼在數據被page cache緩存的情況下,它的延遲應該小於50毫秒(在最佳的情況下應該小於10毫秒)。 否則,延遲取決於數據的查找次數。如果你當前使用的是HDD,在數據沒有加載的情況下,查詢所需要的延遲可以通過以下公式計算得知: 查找時間(10 ms) * 查詢的列的數量 * 查詢的數據塊的數量。
處理大量短查詢的吞吐量
在相同的情況下,ClickHouse可以在單個服務器上每秒處理數百個查詢(在最佳的情況下最多可以處理數千個)。但是由於這不適用於分析型場景。因此我們建議每秒最多查詢100次。
數據的寫入性能
我們建議每次寫入不少於1000行的批量寫入,或每秒不超過一個寫入請求。當使用tab-separated格式將一份數據寫入到MergeTree表中時,寫入速度大約爲50到200MB/s。如果您寫入的數據每行爲1Kb,那麼寫入的速度爲50,000到200,000行每秒。如果您的行更小,那麼寫入速度將更高。爲了提高寫入性能,您可以使用多個INSERT進行並行寫入,這將帶來線性的性能提升。