回覆列表
-
1 # web網際網路
-
2 # 會點程式碼的大叔
MySQL分庫分表(其他關係型資料庫也相似),通常的方案都用主鍵mod分表的數量,來把資料路由到某一個數據庫分片上。例如分了10張表,那麼就是ID%10,得到結果0-9,代表不同的表。
但是當資料量進一步增多的時候,單庫的資料量達到了一定的級別之後,那麼就需要分更多的表,那麼這時候有哪些處理方案呢?
做資料遷移最簡單暴力,也是最麻煩的一個方案。
因為當分表(分庫)數量增多的時候,因為分片規則的變化,每個表的資料都要被重新分配到多個新的表;這種方法雖然最直接,但是帶來的問題也非常大:
資料遷移時間會比較長,需要遷移時間;
如果業務不能停的話(線上遷移),還要解決增量資料和歷史資料一致性的問題;
不做資料遷移那麼有沒有方法,當資料增長到現有分表極限的時候,加表或者加庫的時候,可以避免資料的遷移呢?說白了,我們需要增加分表演算法的複雜性,讓演算法可以相容增加分表前後的資料路由:
先說一個簡單的辦法,(為了方便講述,下面就把id當做分表字段),如果id是一個增長的全域性序列,每個表存500萬的資料,那麼可以id=1-500萬存到table_1,id=500萬零1-1000萬存到table_2,理論上這種方法是可以無限擴容的,但是問題也顯而易見,就是每個階段的資料insert會集中在一個表/庫上,雖然能避免資料遷移的問題,但是資料熱點的問題沒有解決。
如果id是一個增長的全域性序列,當前有十張表,那麼分表的演算法為:id%10,根據0-9路由到10個表中;當表擴到20張的時候,擴容那一刻取max_id,那麼未來分庫的演算法也就變成了:if(id<max_id){id%10} else {id%20};有些分表的演算法本身就帶時間戳,可以基於id中的時間戳來實現,比如Twitter-Snowflake演算法,這個演算法是一個64位的Long值,前42位就是一個精確到毫秒的時間戳,那麼我們的分庫演算法也就可以以某個時間點來判斷:
if(id中的時間<增加分表那一刻的時間){id%10} else {id%20};
首先你已經有了10個表,那麼現在分表肯定需要重新組織這10個表的資料,所以我們可以這樣做,首先建立好你的新分表,比如50個新的分表,然後用程式依次將這10個表的資料按照新規則插入到新的分表裡面,完成之後,將應用程式裡面的資料表名稱改成新資料表,從而完成整個操作。
但是這裡有一個問題,因為我們的資料隨時都在增加或者修改、刪除,如果在業務繁忙的時候來進行的話,很容易導致資料丟失或者資料不完整的情況,所以,儘可能將這個分表操作放在晚上或者業務不繁忙的時候,甚至關閉整個系統一段時間都可以,如果選擇晚上的話,怎麼處理好新增的資料和修改的資料呢?可以考慮臨時增加幾個資料表觸發器,然後在分表完成之後,根據這些觸發器來進行修改資料的修復。
不過在做專案的時候,我們還是儘可能將這個設計好,因為重新分表的成本非常高。