閱讀972 返回首頁    go 阿裏雲 go 技術社區[雲棲]


大規模數據存儲集群數據存放的設計,分布式shardid的生成 - 如何指定範圍隨機數, 分組隨機數

標簽

PostgreSQL , 分組ID生成 , 生成哈希映射 , sharding , shard


背景

在一些分布式數據庫係統中,通常會有多個數據節點,用戶的數據分布策略通常有一致性哈希、按列哈希、隨機分布等。

除了隨機分布,其他的分布方法數據和數據節點是一對一的關係。

上當節點數變得特別特別多的時候,數據如果依舊按照全局進行哈希分布,可能會帶來一個問題,例如節點數到達1萬個,一張1億的表,會分布到1萬個節點中,那麼多個表進行JOIN時,會涉及到1萬個節點的運算,這裏麵可能還涉及節點和節點之間的交互,網絡會話也會特別的多。

實際上並不是每張表都需要分布到1萬個(所有節點)的。如何解決節點數過多的問題呢?如何讓數據落到某些節點,而不是所有節點。這樣可以使得集群更加龐大。

例如HDFS,通過NAME NODE來記錄每個BLOCK在什麼機器上。

NAME NODE的問題是,當集群特別大的時候,NAME NODE會成為瓶頸,不利於擴展。

還有一些方法可以解決大集群的問題,例如多級數據節點、分組數據節點。

大集群的分組設計舉例

計算節點分組

例如有1萬台主機,對應一萬個數據庫單元,劃分為一些分組,例如每100個主機(數據庫實例),一共100個分組。

當然,不一定要求每個分組的主機數一致。

給每個數據庫實例一個唯一編號。

1、例子1,如果每個分組的主機數固定,通過這種方法,可以得到某個分組內的一個隨機ID。

(適合這樣的場景,我已經知道某個表應該在哪個分組內,然後這個表在這個分組內是隨機存放的,那麼通過這種方法,可以得到一個組內隨機的主機ID)

create or replace function get_gp_rid1(gid int, gsz int) returns int as $$                                      
  select gsz*gid + (ceil(random()*gsz))::int;  
$$ language sql strict;  

隨機概率如下

postgres=# select id, count(*) from (select  get_gp_rid1(0,10) id from generate_series(1,10000) ) t group by 1 order by 1;  
 id | count   
----+-------  
  1 |   949  
  2 |   965  
  3 |  1012  
  4 |  1064  
  5 |  1029  
  6 |   970  
  7 |   964  
  8 |  1035  
  9 |  1018  
 10 |   994  
(10 rows)  
  
postgres=# select id, count(*) from (select  get_gp_rid1(1,10) id from generate_series(1,10000) ) t group by 1 order by 1;  
 id | count   
----+-------  
 11 |   993  
 12 |  1023  
 13 |   986  
 14 |   981  
 15 |   978  
 16 |   994  
 17 |  1002  
 18 |  1019  
 19 |   976  
 20 |  1048  
(10 rows)  
  
postgres=# select id, count(*) from (select  get_gp_rid1(2,10) id from generate_series(1,10000) ) t group by 1 order by 1;  
 id | count   
----+-------  
 21 |  1009  
 22 |   985  
 23 |   988  
 24 |  1040  
 25 |   988  
 26 |  1065  
 27 |   986  
 28 |   957  
 29 |   993  
 30 |   989  
(10 rows)  
  
postgres=# select id, count(*) from (select  get_gp_rid1(2,10) id from generate_series(1,10000000) ) t group by 1 order by 1;  
 id |  count    
----+---------  
 21 |  999704  
 22 |  999015  
 23 | 1001106  
 24 |  999979  
 25 |  999599  
 26 |  999417  
 27 | 1000242  
 28 | 1000675  
 29 |  999423  
 30 | 1000840  
(10 rows)  
Time: 4629.229 ms  

2、例子2,對於組的機器數不一致,但是主機ID連續的場景,可以使用這種方法得到一個組內的隨機ID。

create or replace function get_gp_rid2(f int, c int) returns int as $$                                      
  select f - 1 + (ceil(random()*(c-f+1)))::int;  
$$ language sql strict;  

隨機分布均勻

postgres=# select id, count(*) from (select  get_gp_rid2(2,10) id from generate_series(1,10000000) ) t group by 1 order by 1;  
 id |  count    
----+---------  
  2 | 1111981  
  3 | 1112798  
  4 | 1110522  
  5 | 1111070  
  6 | 1111159  
  7 | 1109720  
  8 | 1109822  
  9 | 1111450  
 10 | 1111478  
(9 rows)  
Time: 4631.884 ms  

3、例子3,組的機器數不一致,同時主機ID不連續,可以通過這種方法得到一個組內的隨機ID。

create or replace function get_gp_rid3(id int[]) returns int as $$                                      
  select id[ceil(array_length(id,1)*random())];  
$$ language sql strict;  

數據分布均勻

postgres=# select id,count(*) from (select get_gp_rid3(array[1,2,3,4,5,7,8,9,100,199]) id from generate_series(1,1000000)) t group by 1 order by 1;  
 id  | count    
-----+--------  
   1 | 100898  
   2 |  99818  
   3 |  99434  
   4 | 100085  
   5 | 100461  
   7 | 100361  
   8 |  99725  
   9 | 100002  
 100 |  99646  
 199 |  99570  
(10 rows)  

表和分組的映射關係

表和分組的映射關係,可以使用類似name node的方法。

因為分組數可能發生變化,不推薦使用一致性算法類的MAPPING方法,確保表不需要隨著分組的變化而變化。

分組內數據分布設計

1 完全隨機分布

如果數據在分組內完全隨機分布,那麼就可以像前麵寫的幾個函數那樣,獲得分組內主機的隨機ID。

2 虛擬BLOCK分布

首先需要將數據存放規劃為虛擬BLOCK聚集的方式(例如100000條記錄一個BLOCK,舉例而已)。每個BLOCK有對應的編號。

每個BLOCK落在不同的數據庫實例(主機)中,這個映射關係依舊建議使用類似name node的方法。

因為分組內的主機(數據庫實例)數可能發生變化,不推薦使用一致性算法類的MAPPING方法,確保表不需要隨著分組內主機(數據庫實例)數的變化而變化。

數據記錄和虛擬BLOCK的關係

1、哈希,例如按某列進行哈希,根據哈希值決定記錄寫入哪個BLOCK。

建議使用一致性哈希分布,確保在擴展或收縮BLOCK數量時,數據的移動最小。

《一致性哈希在分布式數據庫中的應用探索》

2、範圍,適合自增、時間、序列等類型,例如每100000一個block,等等。

3、固定哈希,這種方式比較暴力,例如一開始就設計好一個固定的哈希數,如65536。

固定哈希的擴容不太方便,擴容時移動的數據可能較多。建議按2的N或者N的N次方哈希和擴容。這樣的話,擴展隻是分裂BLOCK,也蠻簡單的。

虛擬BLOCK的遷移

采用NAME NODE記錄了BLOCK和分組內主機的映射關係,因此MOVE block也變得很簡單,隻要移動,並更新NAME NODE。

小結

要管理特別大的集群,數據分布隻是其中很小的一個部分。

但是數據分布是一個非常重要的緩解,分布規則沒有涉及好,可能導致將來擴展、遷移、性能、穩定性等帶來不便。

分組是一個將大化小的方法,因為往往一個業務、或者一個表,不需要離散到所有主機。離散到過多的主機上可能會導致連接、數據重分布,數據JOIN等一些問題。

通常的做法是將需要JOIN,或者同類業務的數據,盡量分布到同樣的主機分組中。確保在進行數據分析時,數據的移動較小。

最後更新:2017-07-14 09:04:05

  上一篇:go  影響或控製PostgreSQL垃圾回收的參數或因素
  下一篇:go  Kaggle首席技術官發布——(Kaggle)NIPS 2017對抗學習挑戰賽起步指南