關係型數據庫,但千萬級表關聯數據庫基本上不太可能做到秒出;考慮過Sharding,但數據量大,
各種成本都很高;熱數據存儲到ElasticSearch,但無法跨索引關聯,導致不得不做寬表,
因爲權限,酒店信息會變,所以每次要刷全量數據,不適用於大表更新,
維護成本也很高;Redis鍵值對存儲無法做到實時彙總;
1. 現有一個需求需要快速訪問 2個字段 至少佔 128KB 的 一條記錄 , 累計十多億數據更新,如何保證數據更新過程中生產應用高可用
2. 每天有將近百萬次數據查詢請求
3. 讓用戶無論在app端還是pc端查詢數據提供秒出的效果
不斷擴展使用場景的,是ClickHouse
ClickHouse是一款用於大數據實時分析的列式數據庫管理系統,而非數據庫。通過向量化執行以及對CPU底層指令集(SIMD)的使用,它可以對海量數據進行並行處理,從而加快數據的處理速度。
主要優點有:
- 爲了高效的使用CPU,數據不僅僅按列存儲,同時還按向量進行處理;
- 數據壓縮空間大,減少IO;處理單查詢高吞吐量每臺服務器每秒最多數十億行;
- 索引非B樹結構,不需要滿足最左原則;只要過濾條件在索引列中包含即可;即使在使用的數據不在索引中,由於各種並行處理機制ClickHouse全表掃描的速度也很快;
- 寫入速度非常快,50-200M/s,對於大量的數據更新非常適用。
在某些情況下,需要使用複製配置分佈式羣集,但沒有足夠的服務器將每個複製副本放置在單獨的節點上。最好在同一個節點上以特殊方式配置多個副本,這樣即使在節點出現故障時也可以繼續執行查詢。這種複製配置可以在不同的分佈式系統中找到,通常稱爲“循環”或“環”複製。在本文中,我們將討論如何在ClickHouse中設置循環複製。如果您對本主題不熟悉,我們建議您從一篇介紹性文章“ClickHouse數據分發”開始。
概念
假設有3個服務器和1個表。目標是將數據分發到3個碎片中並複製兩次。這需要在每個節點上有兩個不同的碎片。
羣集配置
讓我們從定義3個碎片和2個副本的簡單集羣配置開始。由於我們只有3個節點可以使用,我們將以“圓形”的方式設置副本主機,這意味着我們將使用第一個和第二個節點作爲第一個碎片,使用第二個和第三個節點作爲第二個碎片,使用第三個和第一個節點作爲第三個碎片。就像這樣:
- 1st shard, 1st replica, hostname: cluster_node_1
- 1st shard, 2nd replica, hostname: cluster_node_2
- 2nd shard, 1st replica, hostname: cluster_node_2
- 2nd shard, 2nd replica, hostname: cluster_node_3
- 3rd shard, 1st replica, hostname: cluster_node_3
- 3rd shard, 2nd replica, hostname: cluster_node_1
配置文件如下:
<shard> <replica> <host>cluster_node_1</host> </replica> <replica> <host>cluster_node_2</host> </replica> </shard> <shard> <replica> <host>cluster_node_2</host> </replica> <replica> <host>cluster_node_3</host> </replica> </shard> <shard> <replica> <host>cluster_node_3</host> </replica> <replica> <host>cluster_node_1</host> </replica> </shard>
現在您可以看到,我們有以下存儲架構:
- cluster_node_1 stores 1st shard, 1st replica and 3rd shard, 2nd replica
- cluster_node_2 stores 1st shard, 2nd replica and 2nd shard, 1st replica
- cluster_node_3 stores 2nd shard, 2nd replica and 3rd shard, 1st replica
這顯然不起作用,因爲碎片具有相同的表名,當它們位於同一服務器上時,ClickHouse無法區分一個碎片/副本。這裏的訣竅是把每個碎片放到一個單獨的數據庫中!ClickHouse允許爲每個shard定義“default_database”,然後在查詢時使用它,以便將特定表的查詢路由到正確的數據庫。
關於在ClickHouse中使用“Circle”拓撲的另一個重要注意事項是,您應該將每個特定shard的內部複製選項設置爲TRUE。定義如下:
<shard> <internal_replication>true</internal_replication> <replica> <default_database>testcluster_shard_1</default_database> <host>cluster_node_1</host> </replica> <replica> <default_database>testcluster_shard_1</default_database> <host>cluster_node_2</host> </replica> </shard>
現在讓我們嘗試定義與此配置相對應的shard表。
數據庫架構
如上所述,爲了在同一節點上彼此分離碎片,需要特定於碎片的數據庫。
- 第1個節點架構
- testcluster_shard_1
- testcluster_shard_3
- 第2個節點架構
- testcluster_shard_2
- testcluster_shard_1
- 第3個節點架構
- testcluster_shard_3
- testcluster_shard_2
複製表架構
現在讓我們爲碎片設置複製表。ReplicatedMergeTree表定義需要兩個重要參數:
Zookeeper中的表碎片路徑
副本標記
Zookeeper路徑對於每個碎片都應該是唯一的,副本標記在每個特定碎片中都應該是唯一的:
第1個節點:
CREATE TABLE testcluster_shard_1.tc_shard
…
Engine=ReplicatedMergeTree(‘/clickhouse/tables/tc_shard_1/events’, ‘replica_1’, …)
CREATE TABLE testcluster_shard_3.tc_shard
…
Engine=ReplicatedMergeTree(‘/clickhouse/tables/tc_shard_3/events’, ‘replica_2’, …)
第2個節點
CREATE TABLE testcluster_shard_2.tc_shard
…
Engine=ReplicatedMergeTree(‘/clickhouse/tables/tc_shard_2/events’, ‘replica_1’, …)
CREATE TABLE testcluster_shard_1.tc_shard
…
Engine=ReplicatedMergeTree(‘/clickhouse/tables/tc_shard_1/events’, ‘replica_2’, …)
第3個節點
CREATE TABLE testcluster_shard_3.tc_shard
…
Engine=ReplicatedMergeTree(‘/clickhouse/tables/tc_shard_3/events’, ‘replica_1’, …)
CREATE TABLE testcluster_shard_2.tc_shard
…
Engine=ReplicatedMergeTree(‘/clickhouse/tables/tc_shard_2/events’, ‘replica_2’, …)
分佈式表架構
剩下的就是分佈式表。爲了讓ClickHouse爲本地shard表選擇合適的默認數據庫,需要使用空數據庫創建分佈式表。這就觸發了默認值的使用。
CREATE TABLE tc_distributed
…
ENGINE = Distributed( ‘testcluster’, ‘’, tc_shard, rand() )
當查詢到分佈式表時,ClickHouse會自動爲每個本地tc_shard表添加相應的默認數據庫。
將“load_balancing”設置設置爲“按順序”是有意義的,否則,ClickHouse可能會偶爾選擇第二個副本執行查詢,從而導致從同一羣集節點查詢的兩個碎片不是最佳的。
如果其中一個節點關閉,則仍有足夠的數據運行查詢:
結論
如上所示,可以在ClickHouse中設置循環或環形複製拓撲,但這並不簡單,需要不明顯的配置和額外的數據庫來分離碎片和副本。除了複雜的配置之外,由於每個羣集節點的雙重插入負載,這種設置與單獨的副本節點相比性能更差。雖然對副本重複使用相同的節點似乎很有吸引力,但在考慮循環複製部署時,需要考慮性能和配置問題。