以前一篇文章已經談到了數據庫集羣之主從集羣也就是讀寫分離,也提到了讀寫分離其實只是分擔了訪問的壓力,可是存儲的壓力沒有解決。redis
存儲的壓力說白了就是隨着系統的演化,需求的增長,可能表的數量會逐漸增多,好比一段時間上個新功能就得加個表。而且隨着用戶量的增多相似用戶表的行數確定會增多,訂單表的數據確定會隨着時間而增多,當這種數據量達到千萬甚至上億的時候,讀寫分離就已經知足不了,讀寫性能降低嚴重。sql
也就是一臺服務器的資源例如CPU、內存、IO、磁盤等是有限的,因此這時候分庫分表就上啦!數據庫
分庫講白了就是好比如今你有一個數據庫服務器,數據庫中有兩張表分別是用戶表和訂單表。若是要分庫的話如今你須要買兩臺機子,搞兩個數據庫分別放在兩臺機子上,而且一個數據庫放用戶表,一個數據庫放訂單表 服務器
這樣存儲壓力就分擔到兩個服務器上了,可是會帶來新的問題,因此東西變複雜了都會有新的問題產生。架構
一、聯表查詢問題 也就是join了,以前在一個數據庫裏面能夠用上join用一條sql語句就能夠聯表查詢獲得想要的結果,可是如今分爲多個數據庫了,因此join用不上了。就好比如今要查註冊時間在2019年以後用戶的訂單信息,你就須要先去數據庫A中用戶表查詢註冊在2019年以後的信息,而後獲得用戶id,再拿這些id去數據庫B訂單表中查找訂單信息,而後再拼接這些信息返回。因此等於得多寫一些代碼了。分佈式
二、事務問題 搞數據庫基本上都離不開事務,可是如今不一樣的數據庫事務就不是之前那個簡單的本地事務了,而是分佈式事務了,而引入分佈式事務也提升了系統的複雜性,而且有些效率不高還會影響性能例如Mysql XA。還有基於消息中間件實現分佈式事務的等等這裏不展開講述。性能
咱們已經作了分庫了,可是如今狀況是咱們的表裏面的數據太多了,就一不當心你的公司的產品火了,像抖音這種,全部用戶若是就存在一張表裏吃不消,因此這時候得分表。分別又分垂直分表和水平分表。優化
垂直分表的意思形象點就像座標軸的y軸,把x軸切成了兩半,對應到咱們的表就是好比咱們表有10列,如今一刀切下去,分紅了兩張表,其中一張表3列,另外一張表7列。架構設計
這個一刀切下去讓兩個表分別有幾列不是固定的,垂直分表適合表中存在不經常使用而且佔用了大量空間的表拆分出去。設計
就拿頭條的用戶信息,好比用戶表只有用戶id、暱稱、手機號、我的簡介這4個字段。可是手機號和我的簡介這種信息就屬於不太經常使用的,佔用的空間也不小,我的簡介有些人寫了一坨。因此就把手機號和我的簡介這兩列拆分出去。
那垂直分表影響就是以前只要一個查詢的,如今須要兩次查詢才能拿到分表以前的完整用戶表信息。
水平分表的意思形象點就像座標軸的x軸,把y軸切成了兩半(固然不只限於切一刀,能夠切好幾份)。也拿用戶表來講好比如今用戶表有5000萬行數據,咱們切5刀,分紅5個表,每一個表1000萬行數據。
水平分表就適合用戶錶行數不少的狀況下,通常單錶行數超過5000萬就得分表,若是單表的數據比較複雜那可能2000萬甚至1000萬就得分了,這個得看實際狀況有些表很簡單可能一億行都不用分。因此當一個錶行數超過千萬級別的時候關注一下,若是沒有性能問題就能夠再等等看,不要急着分表,由於分表會是帶來不少問題。
水平分表的問題比垂直分表就更煩了。
要考慮怎麼切,講的高級點就叫路由
一、按id也就是範圍路由,好比id 值1~999萬的放一張表,1000萬~1999放一張表,一次類推。這個得試的,由於範圍分的大了,可能性能還有問題,範圍分的小了。。那表不得多死。
這種分法的好處就是容易切啊,簡單粗暴,之後新增的數據分表都不會影響到以前的數據,以前的數據都不須要移動。
二、哈希路由 就是取幾列哈希一下看看數據哪一個庫,好比拿id來作哈希,1500取餘8等於4,因此這條記錄就放在user_4這個表中,2011取餘8等於3,因此這條記錄就放在user_3中。這種分法好處就是分的很均勻,基本上每一個表的數據都差很少,可是之後新增數據又得分表了咋辦,之前的數據都得動,比較煩!
三、搞一張表來存儲路由關係 仍是拿用戶表來講,就是弄一個路由表,裏面存userId和表編號,表示這個userId是這張user表的的。這種方式也簡單,以後又要分表了以後改改路由表,遷移一部分數據。可是這種方法致使每次查詢都得查兩次,而且若是路由表太大了,那路由表又成爲瓶頸了!
再說說查詢時候的問題。
好比你要查註冊時間最先的前100名用戶,這就等於你得在水平分的每一張表都order by 一下注冊時間而且取100個,而後再把每一個表的100個結果對比一下獲得最終的結果。首先操做變麻煩了,之前一個order by就搞定的事情如今變的複雜了,並且還得考慮一個因素就是時間的問題,若是你拆成了20個表,那你得執行20個order by,若是是串行執行的話,這個時間開銷也是個問題!
具體實現也分爲程序代碼封裝、數據庫中間件封裝。實現難度會比讀寫分離更大,至於兩種封裝的比較在講讀寫分離時候已經說了,這裏再也不贅述。
說了這麼多好像分庫分表一點都很差啊,沒錯會引入不少問題,因此在架構設計要遵循演化原則,任何東西都不是一蹴而就的,在不一樣場景適配不一樣的架構,架構只有合適的,沒有一個架構能夠適配任何場景。
在軟件中簡單夠用就是好的,技術沒有貴賤,不是用了分佈式就牛逼,越複雜的系統維護的成本和難度越高,出現問題的概率越大。這種架構的演化每每都是被用戶所驅動的,能夠說是"不得已而爲之"。
基本上單機數據庫能夠支撐10萬用戶量級別。因此通常狀況下像數據庫吃不消就升級硬件,優化數據庫配置、優化代碼、引入redis等。只有在真的不行了才上這些更復雜的東西。
若有錯誤歡迎指正! 我的公衆號:yes的練級攻略