<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          阿里二面:為什么要分庫分表?

          共 4851字,需瀏覽 10分鐘

           ·

          2022-03-18 01:53

          大家好,我是龍臺,又跟大家見面了。

          前言

          在高并發(fā)系統(tǒng)當(dāng)中,分庫分表是必不可少的技術(shù)手段之一,同時也是BAT等大廠面試時,經(jīng)常考的熱門考題。

          你知道我們?yōu)槭裁匆龇謳旆直韱幔?/p>

          這個問題要從兩條線說起:垂直方向水平方向

          1 垂直方向

          垂直方向主要針對的是業(yè)務(wù),下面聊聊業(yè)務(wù)的發(fā)展跟分庫分表有什么關(guān)系。

          1.1 單庫

          在系統(tǒng)初期,業(yè)務(wù)功能相對來說比較簡單,系統(tǒng)模塊較少。

          為了快速滿足迭代需求,減少一些不必要的依賴。更重要的是減少系統(tǒng)的復(fù)雜度,保證開發(fā)速度,我們通常會使用單庫來保存數(shù)據(jù)。

          系統(tǒng)初期的數(shù)據(jù)庫架構(gòu)如下:此時,使用的數(shù)據(jù)庫方案是:一個數(shù)據(jù)庫包含多張業(yè)務(wù)表。用戶讀數(shù)據(jù)請求和寫數(shù)據(jù)請求,都是操作的同一個數(shù)據(jù)庫。

          1.2 分表

          系統(tǒng)上線之后,隨著業(yè)務(wù)的發(fā)展,不斷的添加新功能。導(dǎo)致單表中的字段越來越多,開始變得有點(diǎn)不太好維護(hù)了。

          一個用戶表就包含了幾十甚至上百個字段,管理起來有點(diǎn)混亂。

          這時候該怎么辦呢?

          答:分表

          用戶表拆分為:用戶基本信息表用戶擴(kuò)展表

          用戶基本信息表中存的是用戶最主要的信息,比如:用戶名、密碼、別名、手機(jī)號、郵箱、年齡、性別等核心數(shù)據(jù)。

          這些信息跟用戶息息相關(guān),查詢的頻次非常高。

          而用戶擴(kuò)展表中存的是用戶的擴(kuò)展信息,比如:所屬單位、戶口所在地、所在城市等等,非核心數(shù)據(jù)。

          這些信息只有在特定的業(yè)務(wù)場景才需要查詢,而絕大數(shù)業(yè)務(wù)場景是不需要的。

          所以通過分表把核心數(shù)據(jù)和非核心數(shù)據(jù)分開,讓表的結(jié)構(gòu)更清晰,職責(zé)更單一,更便于維護(hù)。

          除了按實(shí)際業(yè)務(wù)分表之外,我們還有一個常用的分表原則是:把調(diào)用頻次高的放在一張表,調(diào)用頻次低的放在另一張表。

          有個非常經(jīng)典的例子就是:訂單表和訂單詳情表。

          1.3 分庫

          不知不覺,系統(tǒng)已經(jīng)上線了一年多的時間了。經(jīng)歷了N個迭代的需求開發(fā),功能已經(jīng)非常完善。

          系統(tǒng)功能完善,意味著系統(tǒng)各種關(guān)聯(lián)關(guān)系,錯綜復(fù)雜。

          此時,如果不趕快梳理業(yè)務(wù)邏輯,后面會帶來很多隱藏問題,會把自己坑死。

          這就需要按業(yè)務(wù)功能,劃分不同領(lǐng)域了。把相同領(lǐng)域的表放到同一個數(shù)據(jù)庫,不同領(lǐng)域的表,放在另外的數(shù)據(jù)庫。

          具體拆分過程如下:

          將用戶、產(chǎn)品、物流、訂單相關(guān)的表,從原來一個數(shù)據(jù)庫中,拆分成單獨(dú)的用戶庫、產(chǎn)品庫、物流庫和訂單庫,一共四個數(shù)據(jù)庫。

          在這里為了看起來更直觀,每個庫我只畫了一張表,實(shí)際場景可能有多張表。

          這樣按領(lǐng)域拆分之后,每個領(lǐng)域只用關(guān)注自己相關(guān)的表,職責(zé)更單一了,一下子變得更好維護(hù)了。

          1.4 分庫分表

          有時候按業(yè)務(wù),只分庫,或者只分表是不夠的。比如:有些財務(wù)系統(tǒng),需要按月份和年份匯總,所有用戶的資金。

          這就需要做:分庫分表了。

          每年都有個單獨(dú)的數(shù)據(jù)庫,每個數(shù)據(jù)庫中,都有12張表,每張表存儲一個月的用戶資金數(shù)據(jù)。這樣分庫分表之后,就能非常高效的查詢出某個用戶每個月,或者每年的資金了。

          此外,還有些比較特殊的需求,比如需要按照地域分庫,比如:華中、華北、華南等區(qū),每個區(qū)都有一個單獨(dú)的數(shù)據(jù)庫。

          甚至有些游戲平臺,按接入的游戲廠商來做分庫分表。

          2 水平方向

          水分方向主要針對的是數(shù)據(jù),下面聊聊數(shù)據(jù)跟分庫分表又有什么關(guān)系。

          2.1 單庫

          在系統(tǒng)初期,由于用戶非常少,所以系統(tǒng)并發(fā)量很小。并且存在表中的數(shù)據(jù)量也非常少。

          這時的數(shù)據(jù)庫架構(gòu)如下:此時,使用的數(shù)據(jù)庫方案同樣是:一個master數(shù)據(jù)庫包含多張業(yè)務(wù)表

          用戶讀數(shù)據(jù)請求和寫數(shù)據(jù)請求,都是操作的同一個數(shù)據(jù)庫,該方案比較適合于并發(fā)量很低的業(yè)務(wù)場景。

          2.2 主從讀寫分離

          系統(tǒng)上線一段時間后,用戶數(shù)量增加了。

          此時,你會發(fā)現(xiàn)用戶的請求當(dāng)中,讀數(shù)據(jù)的請求占據(jù)了大部分,真正寫數(shù)據(jù)的請求占比很少。

          眾所周知,數(shù)據(jù)庫連接是有限的,它是非常寶貴的資源。而每次數(shù)據(jù)庫的讀或?qū)懻埱螅夹枰加弥辽僖粋€數(shù)據(jù)庫連接。

          如果寫數(shù)據(jù)請求需要的數(shù)據(jù)庫連接,被讀數(shù)據(jù)請求占用完了,不就寫不了數(shù)據(jù)了?

          這樣問題就嚴(yán)重了。

          為了解決該問題,我們需要把讀庫寫庫分開。

          于是,就出現(xiàn)了主從讀寫分離架構(gòu):考慮剛開始用戶量還沒那么大,選擇的是一主一從的架構(gòu),也就是常說的一個master一個slave。

          所有的寫數(shù)據(jù)請求,都指向主庫。一旦主庫寫完數(shù)據(jù)之后,立馬異步同步給從庫。這樣所有的讀數(shù)據(jù)請求,就能及時從從庫中獲取到數(shù)據(jù)了(除非網(wǎng)絡(luò)有延遲)。

          讀寫分離方案可以解決上面提到的單節(jié)點(diǎn)問題,相對于單庫的方案,能夠更好的保證系統(tǒng)的穩(wěn)定性。

          因?yàn)槿绻鲙鞉炝耍梢陨墢膸鞛橹鲙欤瑢⑺凶x寫請求都指向新主庫,系統(tǒng)又能正常運(yùn)行了。

          讀寫分離方案其實(shí)也是分庫的一種,它相對于為數(shù)據(jù)做了備份,它已經(jīng)成為了系統(tǒng)初期的首先方案。

          但這里有個問題就是:如果用戶量確實(shí)有些大,如果master掛了,升級slave為master,將所有讀寫請求都指向新master。

          但此時,如果這個新master根本扛不住所有的讀寫請求,該怎么辦?

          這就需要一主多從的架構(gòu)了:

          上圖中我列的是一主兩從,如果master掛了,可以選擇從庫1或從庫2中的一個,升級為新master。假如我們在這里升級從庫1為新master,則原來的從庫2就變成了新master的的slave了。

          調(diào)整之后的架構(gòu)圖如下:這樣就能解決上面的問題了。

          除此之外,如果查詢請求量再增大,我們還可以將架構(gòu)升級為一主三從、一主四從...一主N從等。

          2.3 分庫

          上面的讀寫分離方案確實(shí)可以解決讀請求大于寫請求時,導(dǎo)致master節(jié)點(diǎn)扛不住的問題。但如果某個領(lǐng)域,比如:用戶庫。如果注冊用戶的請求量非常大,即寫請求本身的請求量就很大,一個master庫根本無法承受住這么大的壓力。

          這時該怎么辦呢?

          答:建立多個用戶庫。

          用戶庫的拆分過程如下:在這里我將用戶庫拆分成了三個庫(真實(shí)場景不一定是這樣的),每個庫的表結(jié)構(gòu)是一模一樣的,只有存儲的數(shù)據(jù)不一樣。


          2.4 分表

          用戶請求量上來了,帶來的勢必是數(shù)據(jù)量的成本上升。即使做了分庫,但有可能單個庫,比如:用戶庫,出現(xiàn)了5000萬的數(shù)據(jù)。

          根據(jù)經(jīng)驗(yàn)值,單表的數(shù)據(jù)量應(yīng)該盡量控制在1000萬以內(nèi),性能是最佳的。如果有幾千萬級的數(shù)據(jù)量,用單表來存,性能會變得很差。

          如果數(shù)據(jù)量太大了,需要建立的索引也會很大,從小到大檢索一次數(shù)據(jù),會非常耗時,而且非常消耗cpu資源。

          這時該怎么辦呢?

          答:分表,這樣可以控制每張表的數(shù)據(jù)量,和索引大小。

          表拆分過程如下:

          我在這里將用戶庫中的用戶表,拆分成了四張表(真實(shí)場景不一定是這樣的),每張表的表結(jié)構(gòu)是一模一樣的,只是存儲的數(shù)據(jù)不一樣。

          如果以后用戶數(shù)據(jù)量越來越大,只需再多分幾張用戶表即可。

          2.5 分庫分表

          當(dāng)系統(tǒng)發(fā)展到一定的階段,用戶并發(fā)量大,而且需要存儲的數(shù)據(jù)量也很多。這時該怎么辦呢?

          答:需要做分庫分表

          如下圖所示:圖中將用戶庫拆分成了三個庫,每個庫都包含了四張用戶表。

          如果有用戶請求過來的時候,先根據(jù)用戶id路由到其中一個用戶庫,然后再定位到某張表。

          路由的算法挺多的:

          • 根據(jù)id取模,比如:id=7,有4張表,則7%4=3,模為3,路由到用戶表3。
          • 給id指定一個區(qū)間范圍,比如:id的值是0-10萬,則數(shù)據(jù)存在用戶表0,id的值是10-20萬,則數(shù)據(jù)存在用戶表1。
          • 一致性hash算法

          這篇文章就不過多介紹了,后面會有文章專門介紹這些路由算法的。

          3 真實(shí)案例

          接下來,廢話不多說,給大家分享三個我參與過的分庫分表項(xiàng)目經(jīng)歷,給有需要的朋友一個參考。

          3.1 分庫

          我之前待過一家公司,我們團(tuán)隊(duì)是做游戲運(yùn)營的,我們公司提供平臺,游戲廠商接入我們平臺,推廣他們的游戲。

          游戲玩家通過我們平臺登錄,成功之后跳轉(zhuǎn)到游戲廠商的指定游戲頁面,該玩家就能正常玩游戲了,還可以充值游戲幣。

          這就需要建立我們的賬號體系和游戲廠商的賬號的映射關(guān)系,游戲玩家通過登錄我們平臺的游戲賬號,成功之后轉(zhuǎn)換成游戲廠商自己平臺的賬號。

          這里有兩個問題:

          1. 每個游戲廠商的接入方式可能都不一樣,賬號體系映射關(guān)系也有差異。
          2. 用戶都從我們平臺登錄,成功之后跳轉(zhuǎn)到游戲廠商的游戲頁面。當(dāng)時有N個游戲廠商接入了,活躍的游戲玩家比較多,登錄接口的并發(fā)量不容小覷。

          為了解決這兩個問題,我們當(dāng)時采用的方案是:分庫。即針對每一個游戲都單獨(dú)建一個數(shù)據(jù)庫,數(shù)據(jù)庫中的表結(jié)構(gòu)允許存在差異。我們當(dāng)時沒有進(jìn)一步分表,是因?yàn)楫?dāng)時考慮每種游戲的用戶量,還沒到大到離譜的地步。不像王者榮耀這種現(xiàn)象級的游戲,有上億的玩家。

          其中有個比較關(guān)鍵的地方是:登錄接口中需要傳入游戲id字段,通過該字段,系統(tǒng)就知道要操作哪個庫,因?yàn)閹烀芯桶擞螒騣d的信息。

          3.2 分表

          還是在那家游戲平臺公司,我們還有另外一個業(yè)務(wù)就是:金鉆會員

          說白了就是打造了一套跟游戲相關(guān)的會員體系,為了保持用戶的活躍度,開通會員有很多福利,比如:送游戲幣、充值有折扣、積分兌換、抽獎、專屬客服等等。

          在這套會員體系當(dāng)中,有個非常重要的功能就是:積分

          用戶有很多種途徑可以獲取積分,比如:簽到、充值、玩游戲、抽獎、推廣、參加活動等等。

          積分用什么用途呢?

          1. 退換實(shí)物禮物
          2. 兌換游戲幣
          3. 抽獎

          說了這么多,其實(shí)就是想說,一個用戶一天當(dāng)中,獲取積分或消費(fèi)積分都可能有很多次,那么,一個用戶一天就可能會產(chǎn)生幾十條記錄。

          如果用戶多了的話,積分相關(guān)的數(shù)據(jù)量其實(shí)挺驚人的。

          我們當(dāng)時考慮了,水平方向的數(shù)據(jù)量可能會很大,但是用戶并發(fā)量并不大,不像登錄接口那樣。

          所以采用的方案是:分表

          當(dāng)時使用一個積分?jǐn)?shù)據(jù)庫就夠了,但是分了128張表。然后根據(jù)用戶id,進(jìn)行hash除以128取模。

          需要特別注意的是,分表的數(shù)量最好是2的冪次方,方便以后擴(kuò)容。

          3.3 分庫分表

          后來我去了一家從事餐飲軟件開發(fā)的公司。這個公司有個特點(diǎn)是在每天的中午和晚上的就餐高峰期,用戶的并發(fā)量很大。

          用戶吃飯前需要通過我們系統(tǒng)點(diǎn)餐,然后下單,然后結(jié)賬。當(dāng)時點(diǎn)餐和下單的并發(fā)量挺大的。

          餐廳可能會有很多人,每個人都可能下多個訂單。這樣就會導(dǎo)致用戶的并發(fā)量高,并且數(shù)據(jù)量也很大。

          所以,綜合考慮了一下,當(dāng)時我們采用的技術(shù)方案是:分庫分表

          經(jīng)過調(diào)研之后,覺得使用了當(dāng)當(dāng)網(wǎng)開源的基于jdbc的中間件框架:sharding-jdbc

          當(dāng)時分了4個庫,每個庫有32張表。

          4 總結(jié)

          上面主要從:垂直和水平,兩個方向介紹了我們的系統(tǒng)為什么要分庫分表。

          說實(shí)話垂直方向(即業(yè)務(wù)方向)更簡單。

          在水平方向(即數(shù)據(jù)方向)上,分庫分表的作用,其實(shí)是有區(qū)別的,不能混為一談。

          • 分庫:是為了解決數(shù)據(jù)庫連接資源不足問題,和磁盤IO的性能瓶頸問題。
          • 分表:是為了解決單表數(shù)據(jù)量太大,sql語句查詢數(shù)據(jù)時,即使走了索引也非常耗時問題。此外還可以解決消耗cpu資源問題。
          • 分庫分表:可以解決 數(shù)據(jù)庫連接資源不足、磁盤IO的性能瓶頸、檢索數(shù)據(jù)耗時 和 消耗cpu資源等問題。

          如果在有些業(yè)務(wù)場景中,用戶并發(fā)量很大,但是需要保存的數(shù)據(jù)量很少,這時可以只分庫,不分表。

          如果在有些業(yè)務(wù)場景中,用戶并發(fā)量不大,但是需要保存的數(shù)量很多,這時可以只分表,不分庫。

          如果在有些業(yè)務(wù)場景中,用戶并發(fā)量大,并且需要保存的數(shù)量也很多時,可以分庫分表。

          好了,今天的內(nèi)容就先到這里。

          是不是有點(diǎn)意猶未盡?

          沒關(guān)系,其實(shí)分庫分表相關(guān)內(nèi)容挺多的,本文作為分庫分表系列的第一彈,作為一個開胃小菜吧,分享給大家。

          在文章末尾順便提幾個問題:

          1. 分庫分表的具體實(shí)現(xiàn)方案有哪些?
          2. 分庫分表后如何平滑擴(kuò)容?
          3. 分庫分表后帶來了哪些問題?
          4. 如何在項(xiàng)目中實(shí)現(xiàn)分庫分表功能?

          歡迎關(guān)注,敬請期待我的下一篇文章。


          最后說一句(求關(guān)注,別白嫖我)

          如果這篇文章對您有所幫助,或者有所啟發(fā)的話,幫忙掃描下發(fā)二維碼關(guān)注一下,您的支持是我堅(jiān)持寫作最大的動力。

          求一鍵三連:點(diǎn)贊、轉(zhuǎn)發(fā)、在看。

          關(guān)注公眾號:【蘇三說技術(shù)】,在公眾號中回復(fù):面試、代碼神器、開發(fā)手冊、時間管理有超贊的粉絲福利,另外回復(fù):加群,可以跟很多BAT大廠的前輩交流和學(xué)習(xí)。

          瀏覽 55
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  思思热免费 | 日韩三级片网 | 99在线观看 | 一级视频在线观看免费 | 青娱乐精品盛宴 |