面試官:說說Mysql數據庫分庫分表,並且會有哪些問題?


之前一篇文章已經談到了數據庫集群之主從集群也就是讀寫分離,也提到了讀寫分離其實只是分擔了訪問的壓力,但是存儲的壓力沒有解決。

存儲的壓力說白了就是隨着系統的演化,需求的增加,可能表的數量會逐漸增多,比如一段時間上個新功能就得加個表。並且隨着用戶量的增多類似用戶表的行數肯定會增多,訂單表的數據肯定會隨着時間而增多,當這種數據量達到千萬甚至上億的時候,讀寫分離就已經滿足不了,讀寫性能下降嚴重。

也就是一台服務器的資源例如CPU、內存、IO、磁盤等是有限的,所以這時候分庫分表就上啦!

分庫

分庫講白了就是比如現在你有一個數據庫服務器,數據庫中有兩張表分別是用戶表和訂單表。如果要分庫的話現在你需要買兩台機子,搞兩個數據庫分別放在兩台機子上,並且一個數據庫放用戶表,一個數據庫放訂單表

這樣存儲壓力就分擔到兩個服務器上了,但是會帶來新的問題,所以東西變復雜了都會有新的問題產生。

1、聯表查詢問題 也就是join了,之前在一個數據庫里面可以用上join用一條sql語句就可以聯表查詢得到想要的結果,但是現在分為多個數據庫了,所以join用不上了。就比如現在要查注冊時間在2019年之后用戶的訂單信息,你就需要先去數據庫A中用戶表查詢注冊在2019年之后的信息,然后得到用戶id,再拿這些id去數據庫B訂單表中查找訂單信息,然后再拼接這些信息返回。所以等於得多寫一些代碼了。

2、事務問題 搞數據庫基本上都離不開事務,但是現在不同的數據庫事務就不是以前那個簡單的本地事務了,而是分布式事務了,而引入分布式事務也提高了系統的復雜性,並且有些效率不高還會影響性能例如Mysql XA。還有基於消息中間件實現分布式事務的等等這里不展開講述。

分表

我們已經做了分庫了,但是現在情況是我們的表里面的數據太多了,就一不小心你的公司的產品火了,像抖音這種,所有用戶如果就存在一張表里吃不消,所以這時候得分表。分別又分垂直分表和水平分表。

垂直分表

垂直分表的意思形象點就像坐標軸的y軸,把x軸切成了兩半,對應到我們的表就是比如我們表有10列,現在一刀切下去,分成了兩張表,其中一張表3列,另一張表7列。

這個一刀切下去讓兩個表分別有幾列不是固定的,垂直分表適合表中存在不常用並且占用了大量空間的表拆分出去。

就拿頭條的用戶信息,比如用戶表只有用戶id、昵稱、手機號、個人簡介這4個字段。但是手機號和個人簡介這種信息就屬於不太常用的,占用的空間也不小,個人簡介有些人寫了一坨。所以就把手機號和個人簡介這兩列拆分出去。

那垂直分表影響就是之前只要一個查詢的,現在需要兩次查詢才能拿到分表之前的完整用戶表信息。

水平分表

水平分表的意思形象點就像坐標軸的x軸,把y軸切成了兩半(當然不僅限於切一刀,可以切好幾份)。也拿用戶表來說比如現在用戶表有5000萬行數據,我們切5刀,分成5個表,每個表1000萬行數據。

水平分表就適合用戶表行數很多的情況下,一般單表行數超過5000萬就得分表,如果單表的數據比較復雜那可能2000萬甚至1000萬就得分了,這個得看實際情況有些表很簡單可能一億行都不用分。所以當一個表行數超過千萬級別的時候關注一下,如果沒有性能問題就可以再等等看,不要急着分表,因為分表會是帶來很多問題。

水平分表的問題比垂直分表就更煩了。

要考慮怎么切,講的高級點就叫路由

1、按id也就是范圍路由,比如id 值1999萬的放一張表,1000萬1999放一張表,一次類推。這個得試的,因為范圍分的大了,可能性能還有問題,范圍分的小了。。那表不得多死。

這種分法的好處就是容易切啊,簡單粗暴,以后新增的數據分表都不會影響到之前的數據,之前的數據都不需要移動。

2、哈希路由 就是取幾列哈希一下看看數據哪個庫,比如拿id來做哈希,1500取余8等於4,所以這條記錄就放在user_4這個表中,2011取余8等於3,所以這條記錄就放在user_3中。這種分法好處就是分的很均勻,基本上每個表的數據都差不多,但是以后新增數據又得分表了咋辦,以前的數據都得動,比較煩!

3、搞一張表來存儲路由關系 還是拿用戶表來說,就是弄一個路由表,里面存userId和表編號,表示這個userId是這張user表的的。這種方式也簡單,之后又要分表了之后改改路由表,遷移一部分數據。但是這種方法導致每次查詢都得查兩次,並且如果路由表太大了,那路由表又成為瓶頸了!

再說說查詢時候的問題。

比如你要查注冊時間最早的前100名用戶,這就等於你得在水平分的每一張表都order by 一下注冊時間並且取100個,然后再把每個表的100個結果對比一下得到最終的結果。首先操作變麻煩了,以前一個order by就搞定的事情現在變的復雜了,而且還得考慮一個因素就是時間的問題,如果你拆成了20個表,那你得執行20個order by,如果是串行執行的話,這個時間開銷也是個問題!

分庫分表的實現

具體實現也分為程序代碼封裝、數據庫中間件封裝。實現難度會比讀寫分離更大,至於兩種封裝的比較在講讀寫分離時候已經說了,這里不再贅述。

總結

說了這么多好像分庫分表一點都不好啊,沒錯會引入很多問題,所以在架構設計要遵循演化原則,任何東西都不是一蹴而就的,在不同場景適配不同的架構,架構只有合適的,沒有一個架構可以適配任何場景。

在軟件中簡單夠用就是好的,技術沒有貴賤,不是用了分布式就牛逼,越復雜的系統維護的成本和難度越高,出現問題的幾率越大。這種架構的演化往往都是被用戶所驅動的,可以說是"不得已而為之"。

基本上單機數據庫可以支撐10萬用戶量級別。所以一般情況下像數據庫吃不消就升級硬件,優化數據庫配置、優化代碼、引入redis等。只有在真的不行了才上這些更復雜的東西。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM