數(shù)據(jù)庫hash分表后的擴容方案

postgres的hash分表不停機擴容方案
原來我們hash分表之后阵翎,數(shù)據(jù)擴容采用的是rehash院领,這樣遷移全部的數(shù)據(jù)双絮,比較麻煩浴麻。
本次擴容利用hash環(huán)原理,并在此基礎(chǔ)上做一些適應(yīng)性的改動囤攀。
首先假定哈希環(huán)的范圍為0-1023软免,總共1024的數(shù)字,這個可以根據(jù)項目情況擴大或者減小焚挠。
然后假定表"test"中有一個字段"test_col"膏萧,我們根據(jù)這一個字段進行分表,因為hash環(huán)的范圍是0-1023蝌衔,所以hash之后取模將hash的范圍固定在0-1023之間榛泛,如abs(mod(hashtext(test_col::text), 1024)),abs是為了防止數(shù)據(jù)出現(xiàn)負(fù)值胚委。

初始化分表

數(shù)據(jù)不均衡.JPG

假設(shè)我們初始化了4張表挟鸠,table_0叉信、table_1亩冬、table_2、table_3,hash取模之后的區(qū)間[0,1)的數(shù)據(jù)存在table_0硅急,[1,2)之間的存在table_1中覆享,[2,3)之間的存在table_2中,[3,1023]之間的存在table_3中营袜,但又因hash取模后的數(shù)是整數(shù)撒顿,因此0->table_0,1->table_1,2->table_2,[3,1023]->table_3荚板,很明顯出現(xiàn)了數(shù)據(jù)不均衡凤壁。

建立虛擬映射

初始化.JPG

這里我們采用取余的方式建立虛擬映射,即abs(mod(hashtext(test_col::text), 1024))%4跪另,余數(shù)是幾就插入到幾號表中拧抖,hash環(huán)上的table_0-n,table_1-n,table_2-n,table_3-n,就是虛擬映射用的表,每個實體表對應(yīng)了(1024-4)/4張?zhí)摂M表免绿,因為1024是4的整數(shù)倍唧席,所以在實際數(shù)據(jù)插入的時候是可以均勻插入的。

擴容

如上所示嘲驾,我們已經(jīng)可以利用hash環(huán)將我們的數(shù)據(jù)存在指定的分表中了淌哟,但是數(shù)據(jù)量增加的時候,還是有擴容的需求的辽故,所以重點來了徒仓,如下圖所示,我們將4張表擴容成8張表了榕暇,映射關(guān)系變更為abs(mod(hashtext(test_col::text), 1024))%8蓬衡,即原先4%4=0(12,20...彤枢,1020)狰晚,這個表中的數(shù)據(jù)遷移到表4中,原先5%4=1(13缴啡,21...壁晒,1021),中的數(shù)據(jù)遷移到表5中业栅,原先6%4=2(14秒咐,22...,1022)碘裕,中的數(shù)據(jù)遷移到表6中携取,原先7%4=3(15,23...帮孔,1023)雷滋,中的數(shù)據(jù)遷移到表7中不撑,其中有(0,8,...,1016),(1,9,...,1017),(2,10,...,1018),(3,11,...,1019)這些映射上的數(shù)據(jù)是不需要遷移的,因此只需要遷移一半的數(shù)據(jù)即可晤斩。


擴容.JPG

腳本語句

(1)初始化分表語句

## 分表語句
do language plpgsql 
$$
declare
  parts int := 4;
begin
  for i in 0..parts-1 loop 
    execute format('create table test%s (like test including all) inherits (test)', i);
    execute format('alter table test%s add constraint ck check((abs(mod(hashtext(test_col),1024))%%4)=%s)', i, i);
  end loop;
end; 
$$;
## 觸發(fā)器函數(shù)
create or replace function ins_test() returns trigger as 
$$
declare begin
  case (abs(mod(hashtext(NEW.test_col),1024))%4)
    when 0 then
      insert into test0 values (NEW.*);
    when 1 then
      insert into test1 values (NEW.*);
    when 2 then
      insert into test2 values (NEW.*);
    when 3 then
      insert into test3 values (NEW.*);
    else
      return NEW;
    end case;
    return null;
end;
$$
language plpgsql strict;
## 為空保護
create trigger test_ins_tg before insert on test for each row when (NEW.test_col is not null) execute procedure ins_test();
## 查詢時拼接
and (abs(mod(hashtext(test_col::text), 1024))%4)=(abs(mod(hashtext(#{testCol}::text), 1024))%4)

(2)擴容腳本-1

do language plpgsql 
$$
declare
  parts int := 8;
begin
  for i in 4..parts-1 loop 
    execute format('create table test%s (like test including all) inherits (test)', i);
    execute format('alter table test%s add constraint ck check((abs(mod(hashtext(test_col),1024))%%8)=%s)', i, i);
  end loop;
end; 
$$;
## 觸發(fā)器函數(shù)
create or replace function ins_test() returns trigger as 
$$
declare begin
  case (abs(mod(hashtext(NEW.test_col),1024))%8)
    when 0 then
      insert into test0 values (NEW.*);
    when 1 then
      insert into test1 values (NEW.*);
    when 2 then
      insert into test2 values (NEW.*);
    when 3 then
      insert into test3 values (NEW.*);
    when 4 then
      insert into test0 values (NEW.*);
    when 5 then
      insert into test1 values (NEW.*);
    when 6 then
      insert into test2 values (NEW.*);
    when 7 then
      insert into test3 values (NEW.*);
    else
      return NEW;
    end case;
    return null;
end;
$$
language plpgsql strict;
## 查詢時拼接
and (abs(mod(hashtext(test_col::text), 1024))%8)=(abs(mod(hashtext(#{testCol}::text), 1024))%8)

(3)擴容腳本-2
因為原先的分表中constraint定義的是%4焕檬,這里需要改成%8

alter table test0 add constraint ck check((abs(mod(hashtext(test_col),1024))%%8)=0)
alter table test0 add constraint ck check((abs(mod(hashtext(test_col),1024))%%8)=1)
alter table test0 add constraint ck check((abs(mod(hashtext(test_col),1024))%%8)=2)
alter table test0 add constraint ck check((abs(mod(hashtext(test_col),1024))%%8)=3)

(4)數(shù)據(jù)轉(zhuǎn)移
如要將表test0中的要轉(zhuǎn)移的數(shù)據(jù)查出來,然后存在新表中澳泵。

SELECT * FROM test0 where (abs(mod(hashtext(test_col::text), 1024))%8)=4

注意點

(1)這里采用的數(shù)據(jù)擴容方式是成倍擴容实愚,而1024剛好符合我們的成倍擴容方式,不會造成數(shù)據(jù)傾斜兔辅。
(2)表數(shù)量是會動態(tài)變更的腊敲,如果服務(wù)需要動態(tài)擴容的話,這個值不應(yīng)該寫死在代碼里面维苔,應(yīng)該支持動態(tài)變更兔仰。
(3)擴容的時候還做不到對整體系統(tǒng)無影響,因此只能選在夜深人靜時蕉鸳。
如果各位有更好的方法乎赴,請多多指教,謝謝潮尝。
如果各位有更好的方法榕吼,請多多指教,謝謝勉失。
如果各位有更好的方法羹蚣,請多多指教,謝謝乱凿。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末顽素,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子徒蟆,更是在濱河造成了極大的恐慌胁出,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,430評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件段审,死亡現(xiàn)場離奇詭異全蝶,居然都是意外死亡,警方通過查閱死者的電腦和手機寺枉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,406評論 3 398
  • 文/潘曉璐 我一進店門抑淫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人姥闪,你說我怎么就攤上這事始苇。” “怎么了筐喳?”我有些...
    開封第一講書人閱讀 167,834評論 0 360
  • 文/不壞的土叔 我叫張陵催式,是天一觀的道長往弓。 經(jīng)常有香客問我,道長蓄氧,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,543評論 1 296
  • 正文 為了忘掉前任槐脏,我火速辦了婚禮喉童,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘顿天。我一直安慰自己堂氯,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,547評論 6 397
  • 文/花漫 我一把揭開白布牌废。 她就那樣靜靜地躺著咽白,像睡著了一般。 火紅的嫁衣襯著肌膚如雪鸟缕。 梳的紋絲不亂的頭發(fā)上晶框,一...
    開封第一講書人閱讀 52,196評論 1 308
  • 那天,我揣著相機與錄音懂从,去河邊找鬼授段。 笑死,一個胖子當(dāng)著我的面吹牛番甩,可吹牛的內(nèi)容都是我干的侵贵。 我是一名探鬼主播,決...
    沈念sama閱讀 40,776評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼缘薛,長吁一口氣:“原來是場噩夢啊……” “哼窍育!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起宴胧,我...
    開封第一講書人閱讀 39,671評論 0 276
  • 序言:老撾萬榮一對情侶失蹤漱抓,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后恕齐,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體辽旋,經(jīng)...
    沈念sama閱讀 46,221評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,303評論 3 340
  • 正文 我和宋清朗相戀三年檐迟,在試婚紗的時候發(fā)現(xiàn)自己被綠了补胚。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,444評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡追迟,死狀恐怖溶其,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情敦间,我是刑警寧澤瓶逃,帶...
    沈念sama閱讀 36,134評論 5 350
  • 正文 年R本政府宣布束铭,位于F島的核電站,受9級特大地震影響厢绝,放射性物質(zhì)發(fā)生泄漏烟零。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,810評論 3 333
  • 文/蒙蒙 一姑丑、第九天 我趴在偏房一處隱蔽的房頂上張望嘁灯。 院中可真熱鬧,春花似錦靶病、人聲如沸会通。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,285評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽涕侈。三九已至,卻和暖如春煤辨,著一層夾襖步出監(jiān)牢的瞬間裳涛,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,399評論 1 272
  • 我被黑心中介騙來泰國打工众辨, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留调违,地道東北人。 一個月前我還...
    沈念sama閱讀 48,837評論 3 376
  • 正文 我出身青樓泻轰,卻偏偏與公主長得像技肩,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子浮声,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,455評論 2 359