如何構建日均千萬PV Web站點 (三) Sharding


        其實國內許多大型網站為了應對日益復雜的業務場景,通過使用分而治之的手段將整個網站業務分成不同的產品線,比如說國內那些大型購物交易網站它們都將自己的網站首頁、商鋪、訂單、買家、賣家等拆分不同的產品線,分歸不同的業務團隊負責;

    集體到技術,也會根據產品線划分,將一個網站拆分成許多不同的應用,每個應用用獨立部署維護。應用之間可以通過一個超鏈接建立關系(在首頁上的導航鏈接每個都指向不同的應用地址),也可以通過消息隊列進行數據分發,當然最多的還是通過訪問同一個數據庫存儲系統來構成一個關聯的完整系統 此時的架構如下圖所示:

  分布式服務,隨着業務拆分越來越小,存儲系統越來越龐大,應用系統的整體復雜度呈指數級增加,部署維護越來越困難,由於所有應用要和所有數據庫系統連接,在數萬台服務器規模的網站中,這些連接的數目是服務器規模的平方,導致數據庫連接資源不足,拒絕服務。

  既然每一個應用系統都需要執行許多相同的業務操作,比如用戶管理、商品管理等,那么可以將這些共用的業務提取出來,獨立部署。由這些可復用的業務連接數據庫,提供共用服務,而應用系統只需要管理用戶界面,通過分布式服務調用共用業務服務完成具體業務操作

數據庫如何sharding?

數據的切分(Sharding)根據其切分規則的類型,可以分為兩種切分模式。一種是按照 不同的表(或者 Schema)來切分到不同的數據庫(主機)之上,這種切可以稱之為數據的 垂直(縱向)切分;另外一種則是根據表中的數據的邏輯關系,將同一個表中的數據按照某 種條件拆分到多台數據庫(主機)上面,這種切分稱之為數據的水平(橫向)切分。 垂直切分的最大特點就是規則簡單,實施也更為方便,尤其適合各業務之間的耦合度非 常低,相互影響很小,業務邏輯非常清晰的系統。在這種系統中,可以很容易做到將不同業 務模塊所使用的表分拆到不同的數據庫中。根據不同的表來進行拆分,對應用程序的影響也 更小,拆分規則也會比較簡單清晰。 水平切分於垂直切分相比,相對來說稍微復雜一些。因為要將同一個表中的不同數據拆 分到不同的數據庫中,對於應用程序來說,拆分規則本身就較根據表名來拆分更為復雜, 后期的數據維護也會更為復雜一些。 當我們某個(或者某些)表的數據量和訪問量特別的大,通過垂直切分將其放在獨立的 設備上后仍然無法滿足性能要求,這時候我們就必須將垂直切分和水平切分相結合,先垂直 切分,然后再水平切分,才能解決這種超大型表的性能問題。 下面我們就針對垂直、水平以及組合切分這三種數據切分方式的架構實現及切分后數據 的整合進行相應的分析。 14.2 數據的垂直切分 我們先來看一下,數據的垂直切分到底是如何一個切分法的。數據的垂直切分,也可以 稱之為縱向切分。將數據庫想象成為由很多個一大塊一大塊的“數據塊”(表)組成,我們 垂直的將這些 “數據塊”切開,然后將他們分散到多台數據庫主機上面。這樣的切分方法就 是一個垂直(縱向)的數據切分。 一個架構設計較好的應用系統,其總體功能肯定是由很多個功能模塊所組成的,而每一 個功能模塊所需要的數據對應到數據庫中就是一個或者多個表。而在架構設計中,各個功能 模塊相互之間的交互點越統一越少,系統的耦合度就越低,系統各個模塊的維護性以及擴展 性也就越好。這樣的系統,實現數據的垂直切分也就越容易。 當我們的功能模塊越清晰,耦合度越低,數據垂直切分的規則定義也就越容易。完全可 以根據功能模塊來進行數據的切分,不同功能模塊的數據存放於不同的數據庫主機中,可以 很容易就避免掉跨數據庫的 Join 存在,同時系統架構也非常的清晰.

當然,很難有系統能夠做到所有功能模塊所使用的表完全獨立,完全不需要訪問對方的 表或者需要兩個模塊的表進行 Join 操作。這種情況下,我們就必須根據實際的應用場景進 行評估權衡。決定是遷就應用程序將需要 Join 的表的相關某快都存放在同一個數據庫中, 還是讓應用程序做更多的事情,也就是程序完全通過模塊接口取得不同數據庫中的數據, 然 后在程序中完成 Join 操作。 一般來說,如果是一個負載相對不是很大的系統,而且表關聯又非常的頻繁,那可能數 據庫讓步,將幾個相關模塊合並在一起減少應用程序的工作的方案可以減少較多的工作量, 是一個可行的方案。 當然,通過數據庫的讓步,讓多個模塊集中共用數據源,實際上也是簡介的默許了各模 塊架構耦合度增大的發展,可能會讓以后的架構越來越惡化。尤其是當發展到一定階段之后 , 發現數據庫實在無法承擔這些表所帶來的壓力,不得不面臨再次切分的時候,所帶來的架構 改造成本可能會遠遠大於最初的時候。 所以,在數據庫進行垂直切分的時候,如何切分,切分到什么樣的程度,是一個比較考 驗人的難題。只能在實際的應用場景中通過平衡各方面的成本和收益,才能分析出一個真正 適合自己的拆分方案。 比如在本書所使用示例系統的 example 數據庫,我們簡單的分析一下,然后再設計一 個簡單的切分規則,進行一次垂直垂直拆分。 系統功能可以基本分為四個功能模塊:用戶,群組消息,相冊以及事件,

分別對應為如 下這些表:

1. 用戶模塊表:user,user_profile,user_group,user_photo_album

2. 群組討論表:groups,group_message,group_message_content,top_message

3. 相冊相關表:photo,photo_album,photo_album_relation,photo_comment

 

4. 事件信息表:event 初略一看,沒有哪一個模塊可以脫離其他模塊獨立存在,模塊與模塊之間都存在着關系 , 莫非無法切分? 當然不是,我們再稍微深入分析一下,可以發現,雖然各個模塊所使用的表之間都有關 聯,但是關聯關系還算比較清晰,也比較簡單。 群組討論模塊和用戶模塊之間主要存在通過用戶或者是群組關系來進行關聯。一般 關聯的時候都會是通過用戶的 id 或者 nick_name 以及 group 的 id 來進行關 聯,通過模塊之間的接口實現不會帶來太多麻煩; 相冊模塊僅僅與用戶模塊存在通過用戶的關聯。這兩個模塊之間的關聯基本就有通 過用戶 id 關聯的內容,簡單清晰,接口明確; 事件模塊與各個模塊可能都有關聯,但是都只關注其各個模塊中對象的 ID信息 , 同樣可以做到很容易分拆。 所以,我們第一步可以將數據庫按照功能模塊相關的表進行一次垂直拆分,每個模塊所 涉及的表單獨到一個數據庫中,模塊與模塊之間的表關聯都在應用系統端通過藉口來處理。 如下圖所示:

通過這樣的垂直切分之后,之前只能通過一個數據庫來提供的服務,就被分拆成四個數 據庫來提供服務,服務能力自然是增加幾倍了。

垂直切分的優點

1、數據庫的拆分簡單明了,拆分規則明確;

2、應用程序模塊清晰明確,整合容易;

3、數據維護方便易行,容易定位;

垂直切分的缺點

1、部分表關聯無法在數據庫級別完成,需要在程序中完成;

2、對於訪問極其頻繁且數據量超大的表仍然存在性能平靜,不一定能滿足要求;

3、事務處理相對更為復雜;

4、切分達到一定程度之后,擴展性會遇到限制;

5、過讀切分可能會帶來系統過渡復雜而難以維護。

  針對於垂直切分可能遇到數據切分及事務問題,在數據庫層面實在是很難找到一個較好 的處理方案。實際應用案例中,數據庫的垂直切分大多是與應用系統的模塊相對應,同一個 模塊的數據源存放於同一個數據庫中,可以解決模塊內部的數據關聯問題。而模塊與模塊之間,則通過應用程序以服務接口方式來相互提供所需要的數據。雖然這樣做在數據庫的總體 操作次數方面確實會有所增加,但是在系統整體擴展性以及架構模塊化方面,都是有益的。 可能在某些操作的單次響應時間會稍有增加,但是系統的整體性能很可能反而會有一定的提 升。而擴展瓶頸問題,就只能依靠下一節將要介紹的數據水平切分架構來解決了。

   數據的水平切分

   上面一節分析介紹了數據的垂直切分,這一節再分析一下數據的水平切分。數據的垂直 切分基本上可以簡單的理解為按照表按照模塊來切分數據,而水平切分就不再是按照表或者 是功能模塊來切分了。一般來說,簡單的水平切分主要是將某個訪問極其平凡的表再按照某 個字段的某種規則來分散到多個表之中,每個表中包含一部分數據。 簡單來說,我們可以將數據的水平切分理解為是按照數據行的切分,就是將表中的某些 行切分到一個數據庫,而另外的某些行又切分到其他的數據庫中。當然,為了能夠比較容易的判定各行數據被切分到哪個數據庫中了,切分總是都需要按照某種特定的規則來進行的。 如根據某個數字類型字段基於特定數目取模,某個時間類型字段的范圍,或者是某個字符類 型字段的 hash 值。如果整個系統中大部分核心表都可以通過某個字段來進行關聯,那這個 字段自然是一個進行水平分區的上上之選了,當然,非常特殊無法使用就只能另選其他了。 一般來說,像現在互聯網非常火爆的 Web2.0 類型的網站,基本上大部分數據都能夠通 過會員用戶信息關聯上,可能很多核心表都非常適合通過會員 ID 來進行數據的水平切分。 而像論壇社區討論系統,就更容易切分了,非常容易按照論壇編號來進行數據的水平切分。 切分之后基本上不會出現各個庫之間的交互。 如我們的示例系統,所有數據都是和用戶關聯的,那么我們就可以根據用戶來進行水平 拆分,將不同用戶的數據切分到不同的數據庫中。當然,唯一有點區別的是用戶模塊中的 groups 表和用戶沒有直接關系,所以 groups 不能根據用戶來進行水平拆分。對於這種特 殊情況下的表,我們完全可以獨立出來,單獨放在一個獨立的數據庫中。其實這個做法可以 說是利用了前面一節所介紹的 “數據的垂直切分”方法,我將在下一節中更為詳細的介紹這 種垂直切分與水平切分同時使用的聯合切分方法。 所以,對於我們的示例數據庫來說,大部分的表都可以根據用戶 ID 來進行水平的切分 。 不同用戶相關的數據進行切分之后存放在不同的數據庫中。如將所有用戶 ID 通過 2 取模 然后分別存放於兩個不同的數據庫中。每個和用戶 ID 關聯上的表都可以這樣切分。這樣, 基本上每個用戶相關的數據,都在同一個數據庫中,即使是需要關聯,也可以非常簡單的關 聯上。 我們可以通過下圖來更為直觀的展示水平切分相關信息:

水平切分的優點

1、表關聯基本能夠在數據庫端全部完成;

2、不會存在某些超大型數據量和高負載的表遇到瓶頸的問題;

3、應用程序端整體架構改動相對較少; 事務處理相對簡單;

4、只要切分規則能夠定義好,基本上較難遇到擴展性限制;

水平切分的缺點

1、切分規則相對更為復雜,很難抽象出一個能夠滿足整個數據庫的切分規則;

2、后期數據的維護難度有所增加,人為手工定位數據更困難;

3、應用系統各模塊耦合度較高,可能會對后面數據的遷移拆分造成一定的困難。

    垂直與水平聯合切分的使用

    上面兩節內容中,我們分別,了解了“垂直”和“水平”這兩種切分方式的實現以及切 分之后的架構信息,同時也分析了兩種架構各自的優缺點。但是在實際的應用場景中,除了 那些負載並不是太大,業務邏輯也相對較簡單的系統可以通過上面兩種切分方法之一來解決 擴展性問題之外,恐怕其他大部分業務邏輯稍微復雜一點,系統負載大一些的系統,都無法 通過上面任何一種數據的切分方法來實現較好的擴展性,而需要將上述兩種切分方法結合使 用,不同的場景使用不同的切分方法。 在這一節中,我將結合垂直切分和水平切分各自的優缺點,進一步完善我們的整體架構 , 讓系統的擴展性進一步提高。 一般來說,我們數據庫中的所有表很難通過某一個(或少數幾個)字段全部關聯起來, 所以很難簡單的僅僅通過數據的水平切分來解決所有問題。而垂直切分也只能解決部分問 題,對於那些負載非常高的系統,即使僅僅只是單個表都無法通過單台數據庫主機來承擔其 負載。我們必須結合“垂直”和“水平”兩種切分方式同時使用,充分利用兩者的優點,避 開其缺點。 每一個應用系統的負載都是一步一步增長上來的,在開始遇到性能瓶頸的時候,大多數 架構師和 DBA 都會選擇先進行數據的垂直拆分,因為這樣的成本最先,最符合這個時期所追 求的最大投入產出比。然而,隨着業務的不斷擴張,系統負載的持續增長,在系統穩定一段 時期之后,經過了垂直拆分之后的數據庫集群可能又再一次不堪重負,遇到了性能瓶頸。 這時候我們該如何抉擇?是再次進一步細分模塊呢,還是尋求其他的辦法來解決?如果 我們再一次像最開始那樣繼續細分模塊,進行數據的垂直切分,那我們可能在不久的將來, 又會遇到現在所面對的同樣的問題。而且隨着模塊的不斷的細化,應用系統的架構也會越來 越復雜,整個系統很可能會出現失控的局面。 這時候我們就必須要通過數據的水平切分的優勢,來解決這里所遇到的問題。而且, 我們完全不必要在使用數據水平切分的時候,推倒之前進行數據垂直切分的成果,而是在其基 礎上利用水平切分的優勢來避開垂直切分的弊端,解決系統復雜性不斷擴大的問題。而水平 拆分的弊端(規則難以統一)也已經被之前的垂直切分解決掉了,讓水平拆分可以進行的得心應手。 對於我們的示例數據庫,假設在最開始,我們進行了數據的垂直切分,然而隨着業務的 不斷增長,數據庫系統遇到了瓶頸,我們選擇重構數據庫集群的架構。如何重構?考慮到之 前已經做好了數據的垂直切分,而且模塊結構清晰明確。而業務增長的勢頭越來越猛,即使 現在進一步再次拆分模塊,也堅持不了太久。我們選擇了在垂直切分的基礎上再進行水平拆分。 在經歷過垂直拆分后的各個數據庫集群中的每一個都只有一個功能模塊,而每個功能模 塊中的所有表基本上都會與某個字段進行關聯。如用戶模塊全部都可以通過用戶ID進行切分,群組討論模塊則都通過群組ID來切分,相冊模塊則根據相冊ID來進切分,最后的事 件通知信息表考慮到數據的時限性(僅僅只會訪問最近某個事件段的信息),則考慮按時間 來切分。 下圖展示了切分后的整個架構:

實際上,在很多大型的應用系統中,垂直切分和水平切這兩種數據的切分方法基本上都 是並存的,而且經常在不斷的交替進行,以不斷的增加系統的擴展能力。我們在應對不同的 應用場景的時候,也需要充分考慮到這兩種切分方法各自的局限,以及各自的優勢,在不同的時期(負載壓力)使用不同的結合方式。

聯合切分的優點

1、可以充分利用垂直切分和水平切分各自的優勢而避免各自的缺陷;

2、讓系統擴展性得到最大化提升;

聯合切分的缺點

1、數據庫系統架構比較復雜,維護難度更大;

2、應用程序架構也相對更復雜。

關於數據庫如何sharding詳情請參考<<MySQL性能調優與架構設計>>


免責聲明!

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



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