摘要
上一篇文章已經說根據school_id進行分表。通常我們的分表策略有兩種方式
- 取模分表
- 範圍分表
取模分表
所謂的取模分表就是對分表key取模,通過預估數據量確定分幾張表那麼則模以幾。
在我們設計系統之前,可以先預估一下大概這幾年的數據量,如:8000萬。每張表我們可以容納2000萬,也我們可以設計4張表進行存儲。對指定的路由key(如:school_id)對分表總數進行取模,上圖中,id=13的任務,對4進行取模,也就是會得到1,那此訂單會放到1表中。id=26的訂單,取模得到爲2,就會放到2表中。
優點
任務數據可以均勻的放到那4張表中,這樣此任務進行操作時,就不會有熱點問題。
學習任務有個特點就是時間屬性,一般用戶操作任務數據,都會集中到這段時間的任務。如果這段時間產生的任務都在同一張任務表中,那就會形成熱點,那張表的壓力會比較大。
缺點
將來的數據擴容會很難。
隨着業務的發展時間的推移,學習任務量很大,超出了8000萬的量,那我們就需要增加分表數。如果我們增加4個表。一旦我們增加了分表的總數,取模的基數就會變成8,以前id=13的任務按照此方案就會到5表中查詢,但之前的此任務數據在1表的,這樣就導致了數據查不到。就是因爲取模的基數產生了變化。
遇到這個情況,我們小夥伴想到的方案就是做數據遷移,把之前的8000萬數據,重新做一個hash方案,放到新的規劃分表中。也就是我們要做數據遷移。
範圍分表
範圍分表方案也就是以範圍進行拆分數據。
範圍方案比較簡單,就是把一定範圍內的任務,存放到一個表中;如上圖school_id=13放到0表中,school_id=23456的放到2表中。設計這個方案時就是前期把表的範圍設計好。通過school_id進行路由存放。
優點
此方案有利於將來的擴容,不需要做數據遷移。即時再增加4張表,之前的4張表的範圍不需要改變,school_id=13的還是在0表,school_id=23456的還是在2表,新增的4張表他們的範圍肯定是 大於 40000之後的範圍劃分的。
缺點
有熱點問題,因爲school_id的值會一直遞增變大,那這段時間的任務是不是會一直在某一張表中,如school_id=1 ~ 10000萬之間,這段時間產生的訂單是不是都會集中到此張表中,這個就導致1表過熱,壓力過大,而其他的表沒有什麼壓力。
分組取模分表
取模分表:擴容不方便
範圍分表:有熱點問題
通過取模分表方式可以既方便擴容又一定程度上緩解熱點問題
看下數據存儲流程
先根據範圍確定是在那個分組,如school_id=12345,根據範圍確定在group_0中,再取模確定組內那張表,如school_id=12345,按4取模確定存儲在task_1表中。
這樣我們擴容時只需要添加對應的group,同時組內的數據均勻分佈在不同的表中,一定程度上緩解熱點問題。
應用
在我們的業務場景中,我們通過評估最終選取了取模分組。因爲通過school_id分表即使根據範圍分組依然無法避免擴容問題。因爲school_id保持不變,學校對應的用戶(學生id)每年都會新增,通過增加school_id的範圍依然無法讓老學校的新學生任務數據落到新表中。
確定了分表方式後需要預估分表數,此處需要注意的是由於採用的取模分組數據擴容不方便,所以需要假設期望一年、兩年、三年數據不擴容需要分多少張表。通過對生產環境數據統計,我們預估單個學校活躍用戶量500人,每個人月任務量40個,mysql單表數據容量2000萬。這樣計算出單個學校每年任務數=5004012=240000。單個mysql表可以支撐的學校數如下:
支撐年份 | 單表支撐學校數 |
---|---|
1 | 83 |
2 | 48 |
3 | 23 |
所以我們計算出預估分表數:
活躍學校數 | 支撐年份 | 分表數 |
---|---|---|
500 | 1 | 6 |
2 | 12 | |
3 | 18 | |
1000 | 1 | 12 |
2 | 24 | |
3 | 36 | |
1500 | 1 | 18 |
2 | 36 | |
3 | 54 | |
2000 | 1 | 24 |
2 | 48 | |
3 | 72 |