1 數據庫拆分的興起
在過去幾年中,隨着商業應用數據庫事務量的大幅增加和數據庫體積的增大,數據庫拆分的概念已日益普及。許多在線服務供應商,軟件即服務供應商(SaaS)和社交網站的成功更說明了這一點。
數據庫拆分能夠簡單定義爲針對跨多個服務器的大型數據庫設計的一種「零共享」分區方案,這種方案使數據庫性能和擴展性提升到一個新的水平變得可行。想象一下碎玻璃,您就能理解什麼是sharding(碎片)——將數據庫分紅較小塊所謂的「碎片」,散佈在衆多分佈式服務器上。
術語「sharding」是谷歌工程師們獨創,並經過他們的大表架構的公佈獲得推廣的。然而,「shared-nothing(零分享)」這一數據庫分區的思想已經存在了十年以上。在此期間已經產生了許多實例,特別是一些知名的在線服務提供商的著名的內部解決方案,如eBay、Amazon、Digg、Flickr、Skype、YouTube、Friendster和Wikipedia。
本文的重點是關於數據庫拆分的需求、數據庫分區的可選方案和成功進行數據庫拆分的一些關鍵考慮因素。
1 大表:一個結構化數據分佈式存儲系統,由Fay Chang,Jeffrey Dean及其餘Google員工提出。
2 是什麼推進了對數據庫拆分的需求?
數據庫拆分是一個高可擴展性的方法,用於提升高度事務化、大型以數據庫爲中心的商業應用程序的數據吞吐和總體性能。自從關係數據庫產生以來,顯而易見,商業數據庫通常隨着時間增加而增加,對此應用工程師和設計師們要求不斷地提升數據庫的性能和容量。除此以外,網絡經濟的發展、信息時代的大背景、大量電子商務的普及使得商業數據急劇膨脹,致使了這一趨勢更加明顯。
正如任何一位有經驗的數據庫管理員或應用程序開發人員所深知,當數據層的大小和事務規模呈線性增加的話,響應時間每每呈對數增加,這是不言而喻的。以下圖所示:
圖1. 數據庫大小和事務數的增加對響應時間有着巨大影響。
數據庫性能和擴展性面臨挑戰的內在緣由就是數據庫管理系統自己的基礎設計。任何計算機的數據庫主要依賴於其三個部件:
- CPU
- 內存
- 磁盤
經過進行基準測試,咱們知道,單個服務器上的某個部件只能擴展到必定的限度,而後必須採起其餘措施。很明顯,磁盤I / O是主要瓶頸,由於即便數據庫管理系統獲得改善,它依然保持對CPU和內存的高佔用率。事實上,咱們已經注意到,正是這三個因素的匹配程度決定了數據庫的最大性能。換句話說,你不能經過單純無限制增長CPU(或處理核心)的數量,而不提升內容容量,也不改善磁盤驅動子系統的性能,來使整個數據庫系統總體性能獲得相應的提升。顯而易見,將資源投入到單個數據庫服務器上的回報會逐漸減少。尤爲是在混合使用的商業事務系統上,在執行大量讀寫事務的系統上,以及支持廣義的商業報表任務方面,這些因素會更加明顯。
所以,隨着商業應用程序日益成熟,對它的需求也持續增加。架構師、開發人員和數據庫管理員一直面臨着維護關鍵任務系統的數據庫性能的挑戰。這一前景推進着對數據庫拆分的需求。
3 數據庫分區的可選項
人們早就知道數據庫分區可以改善關係數據庫的性能和擴展性。演變至今的技術包括:
- 主/從服務器:這是被許多組織使用的最簡單的一個選擇。使用一個主服務器處理全部的寫(建立、更新或刪除,或增刪改查)操做,同時使用一個或多個從服務器處理只讀操做。主服務器使用標準地、近似實時的複製功能將數據複製到各個從服務器。主/從模式能夠將數據庫總體性能提高到必定程度,容許讀密集型的操做被分離到從服務器進行處理,但此種方法也有以下侷限性:
l 單個主服務器處理寫操做,在擴展性上有明顯的侷限性,而且會很快產生瓶頸。
l 主/從服務器的複製機制是「近於實時」的,這意味着從服務器不能保證得到主服務器上的即時快照。這種機制對於某些應用來講是可行的,但若是您的應用須要的是最新數據,這種方法是不可取的。
l 許多組織一樣採用主/從服務器的方法來實現高可用性,但一樣受限於主從服務器並不徹底同步。若是主服務器發生災難性故障時,任何事務都將在複製以前丟失,這種狀況是大多商業事務應用所不能接受的。
- 集羣運算:利用多臺服務器同組集羣計算,服務器之間經過羣集的節點共享信息。大多數狀況下這要依賴於一個集中的共享磁盤設備,一般是一個存儲區域網絡(SAN)。集羣中的每一個節點運行數據庫服務器的單一實例,且以不一樣的模式工做:
l 對於高可用性,集羣中的多個節點可用於讀取,但只有一個處理寫(增刪改查)操做。這雖然可使讀取速度更快,而寫操做卻得不到任何改善。若是一個節點失敗時,則羣集中的另外一個節點接替它,繼續在共享磁盤設備上進行工做。因爲一個增刪改查操做瓶頸,這種作法限制了其擴展性。即便是讀取操做也最終會達到一個性能極限,由於集中共享的磁盤設備在性能增幅遞減以前只能分擔這麼大的負載。當一個應用程序須要複雜的聯接或包含未優化的SQL語句時,其讀操做所受的限制就是一個有力的證實。
l 更先進的集羣技術依靠節點之間實時內存複製,該技術經過一種實時信息系統來保持在集羣節點的內存鏡像是實時的。這樣使得每一個節點具有既可工做在讀取模式也可工做在寫入模式,但最終仍是會被通訊節點之間能夠傳輸的流量大小所限制(採用一個典型的網絡或其餘高速通訊機制)。所以,隨着節點的增長,通信和內存複製的開銷呈幾何級數倍增,從而嚴重限制了擴展性,一般只好採用相對較少的節點數。此方案遇到了和傳統集羣同樣的共享磁盤的限制,即不斷增大的單一的大型數據庫會產生愈來愈密集的磁盤讀寫。
- 表分區: 許多數據庫管理系統支持表分區,如在一個大表中的數據能夠跨多個磁盤以提升磁盤I / O利用率。這種分區一般是作橫向(跨磁盤分區分行),但某些系統也能夠垂直分區(在不一樣的分區上放置不一樣的列)。這種方法能夠幫助減小對於某個特定表的磁盤I / O瓶頸,但每每使聯接和其餘操做變慢。此外,因爲這種方法依賴於數據庫管理系統下的單個數據庫實例,全部其餘對於CPU和內存的爭奪所形成的限制進一步限制了其擴展性。
- Federated表:表分區技術的一個分支就是Federated表方法。使用這種方法,表能夠在跨多個服務器被訪問。這種作法管理起來很是複雜,且因爲Federated表必須經過網絡訪問,效率也不高。這種作法可能適合某些報道性或分析性工做,但對於通常的讀/寫事務來講並不是一個很好的選擇。
這些方法的共同缺點是依賴於共享設備和資源。不管是依賴於共享內存,集中磁盤,仍是處理器,擴展性都會受到限制,更不用提其餘缺點了,包括複雜的管理,缺少對關鍵業務需求的支持以及高可用性方面的限制。
4 數據庫拆分,一種「零共享」的方法
數據庫拆分提供了一個跨多個獨立的服務器實現可擴展性的方法。每一個服務器有本身的CPU,內存和磁盤。與傳統的加強數據庫性能的方法相比,它沒有其餘方法所遇到的典型限制。對於「零共享」數據庫如何實現的研究和探討已超過15年之久,但直到最近幾年由於應用數據量的大增,纔在商業領域找到較爲普遍的市場需求。
數據庫拆分的基本概念很是直白:將一個大的數據庫,跨服務器分解成許多更小的數據庫。以下圖所示:
圖2:數據庫拆分就是將大數據庫拆分紅若干個小數據庫。
很明顯,「零共享」數據庫拆分的優點就是大大提升擴展性。當更多的服務器被添加到網絡中時,擴展性以近線性的方式增加。不過,在考慮一個拆分方案時,拆分紅若干小數據庫的方式還有其餘幾個優勢不容忽視:
l 較小的數據庫更易於管理。生產數據庫必須進行全面的管理:按期備份、數據庫優化和其餘常規任務。使用一個大數據庫的話,若是僅就完成操做所需的時間而言,實現這些平常任務很是困難。常規表與索引優化能夠持續到幾小時或幾天,某些狀況下會致使按期維護變得不那麼靈活。經過拆分的方法,每一個單獨的「子庫」能夠單獨維護。這樣,管理更爲簡單,能夠並行執行多個維護任務。
l 較小的數據庫速度更快。拆分的擴展性是顯而易見的,它經過在網絡中跨子庫和服務器的分佈式處理得以實現。還有一個較不明顯的事實是,每一個子庫庫因其較小的尺寸從而在性能上賽過單個大的數據庫。每一個子庫都有本身的服務器,這樣內存和磁盤之間比率大爲提升,從而減小磁盤的I/O。這樣帶來的後果是更少的資源爭奪,更優秀的聯接操做的性能,更快的索引搜索,以及更少的數據庫鎖定。所以,不只拆分後的系統能夠擴展到更高級別的容量,並且單個事務的性能也獲得了提升。
l 數據庫拆分可以下降成本。大多數數據庫拆分方案能夠從成本較低的開源數據庫中受益,甚至能夠從「工做組」版的商業數據庫中受益。此外,拆分數據庫在商用多核心服務器硬件上工做的很好,而這種硬件的花費遠低於昂貴的高端多處理器服務器和昂貴的存儲區域網絡(SAN)。在許可證、軟件維護和硬件投資上節約的綜合成本是很是可觀的,相比其餘解決方案,有時能夠節約70%或者更多。毫無疑問,數據庫拆分對許多組織而言是一個可行的方案,這已由很多大型在線銷售商和軟件即服務(SaaS)供應商的實踐證實過了(巨頭如亞馬遜,易趣,固然還有谷歌)。
5 數據庫拆分的實用性
若是數據庫拆分具備高擴展性,花費更低的成本,而且提升了性能,爲何該技術還沒被普遍採用?它是否適合你的組織?
事實上,數據庫拆分是一項很是有用的技術,但像其餘方案同樣,要成功實施須要考慮不少因素。此外,還存在一些限制,而且數據庫拆分並不能在全部類型的商業應用上良好運行。本章討論了這些關鍵因素以及它們如何能獲得解決。
5.1 數據庫拆分面臨的挑戰
鑑於單個數據庫分佈的性質,一些關鍵因素必須加以考慮:
- 可靠性。首先,任何生產經營性的商業應用都必須是可靠、容錯的,且不能遭受頻繁的斷電。數據層一般是任一可靠性設計方案中最爲關鍵的因素,數據庫拆分的實施也不例外。事實上,鑑於多個拆分數據庫分佈的性質,一個設計優秀的方案顯得尤其重要。爲確保可靠性和容錯性,須要具有如下幾點:
n 單個子庫的自動備份
n 子庫冗餘,確保每一個子庫至少有2個實時的備份可在斷電或服務器發生故障時接替其工做。這就須要一個高性能、高效率、可靠的複製機制。
n 經濟的硬件冗餘,無論是服務器內部的硬件,仍是跨服務器的硬件。
n 斷電或服務器發生故障時自動故障切換。
n 災難恢復的站點管理
- 分佈式查詢。 若是使用分佈式查詢並行處理模式,每一個子庫單獨進行查詢,再將每一個子庫的處理結果進行合併,那麼許多類型的查詢的處理速度會快上不少。這種技術使數據庫性能得到數量級的提高,在不少狀況下性能提升都在10倍或者更多。爲了在應用程序上無縫地進行分佈式查詢,很重要的一點是須要一個設備對每一個子庫的查詢進行處理,而後將結果合併成一個結果集返回到應用層。能從這種分佈式處理模式中受益的常見查詢有:
n 統計彙總,須要對整個系統的數據進行全面掃描。例如產品銷售量計算一般要對整個數據庫進行評估。
n 支持複雜報表的查詢,如給出某一指定商品的前一天、前一週或前一月的全部顧客的列表。
- 避免跨子庫的聯接。在拆分系統中,跨子庫使用內聯的查詢或其餘語句效率很低,執行起來也很困難。在大多數狀況下,若是採用的方法正確,實際上並不須要使用內聯。主要技巧就是複製全局表,即那些相對不變化,一般用來與大型主表進行聯接的對照表。那些包含狀態代碼、國家、類型甚至產品的表都屬此類。咱們須要的是一個自動化的複製機制,以確保在全局表中的值在全部子庫中是同步的,儘可能減小或消除跨子庫聯接。
- 自增加鍵管理。數據庫管理系統所提供的典型的自增加功能對每一條插入數據庫的新行生成一個序號鍵。這對一個單數據庫的應用程序來講沒有問題,但當使用數據庫拆分技術時,必須對這些鍵值進行跨子庫的協調管理。對此,咱們須要爲應用程序提供一個跨子庫運行的、無縫的、自動的方法來生成鍵值,以確保整個系統的鍵值都是惟一的。
- 支持多個拆分方案。有一點很重要,就是據庫拆分技術之因此有效,是由於它提供了一個面向應用的大規模擴展和性能改進技術。事實上,能夠說拆分效果與拆分算法自己和應用程序面臨的問題有多貼切是直接掛鉤的。咱們須要的是一套多樣、靈活的、的拆分方案,其中每個方案針對一個應用程序面臨的特定問題。每個方案都具有固有的性能以及針對應用程序的特質和優點,或者其中之一。事實上,使用錯誤的拆分方案會限制性能,達不到預期效果。單個應用採用多個拆分方案,每一個方案用於應用程序的特定部分,從而得到優化的狀況並不常見。如下列出了一些常見的拆分方案:
n 基於會話的拆分。若是單個用戶或進程在整個用戶或進程的會話期間內,與一個具體的子庫進行交互,則採用這種方案。這是最容易實現的拆分技術,對總體性能來講幾乎沒有額外的開銷,這是由於每一會話期只作一次拆分。從中受益的應用一般是以客戶爲中心的商業應用,每一個客戶相關的全部數據都放在一個子庫上。
n 基於事務的拆分。斷定子庫的依據是檢查給定事務的第一個SQL語句。這一般是經過評估語句中 「拆分鍵」的鍵值來完成(如訂單號)。而後,將事務中其餘全部的語句直接導向同一子庫。
n 基於語句的拆分。以語句爲基礎的拆分是全部拆分類型中最爲進程密集型的一種,它評估每個SQL語句來肯定這條語句應該導入哪一個正確的子庫。一樣的,它一樣須要對「拆分鍵」鍵值進行評估。這種拆分方案適合於數量大粒度小的事務,如記錄通話記錄。
- 決定如何拆分數據的最佳方法。這是另外一領域,變化繁多,不一樣的應用有不一樣的選擇。這與上述幾種拆分方案的選擇有很大的關係。有不少方法能夠肯定如何拆分您的數據,但重要的是要知道您的事務頻率,表的大小量,鍵值如何分佈,以及您的應用的其餘特性。知道了這些數據就能夠肯定最優化的拆分策略:
n 根據表的主鍵進行拆分。這是最直截了當的選擇,也是映射到一個應用的最容易的方法。不過,只有當您的數據分佈合理纔會有效。例如,若是您按客戶ID(這是一個順序的數字型值)拆分數據庫,而大多數事務是針對新客戶的,那麼拆分效果只是微乎其微。另外一方面,若是您選擇一個能將用來合理天然的分發事務的鍵,則能夠得到巨大的收益。
n 按一個鍵的鍵值的模數拆分。這種方法應用很是普遍,它對鍵值取模,並根據模數分發事務。實際上,您能夠預先設定任意數量的子庫,而後取模函數會基於「循環」規則處理鍵值,使得新鍵值可以很是均衡地分佈於整個數據庫。
n 維護子庫索引主表。此項技術使用一個單獨的主表,給不一樣的子庫分配不一樣的值。這種方法很是靈活,適用面很廣。可是,這種方法常常致使數據庫性能不高,由於它須要對每個拆分後的SQL語句進行額外查詢。
由上可知,有不少因素須要考慮,也須要知足許多條件,才能確保數據庫拆分可以成功並且有效,以達到提供經濟的、更高級別的擴展能力和性能的目標。
5.2 何時進行數據庫拆分合適
數據庫拆分對許多類型的、有常規的數據庫需求的商業應用來講很是合適。它一樣能夠有效地應用於數據倉庫應用,不過由於有不少產品和技術能夠實現這方面應用,咱們就不在此詳細討論了。
適合對數據庫進行拆分的常規數據庫需求以下:
- 高度事務化的數據庫應用
- 混合任務的數據庫應用
n 頻繁的讀操做,包括複雜的查詢和聯接
n 寫操做密集型的事務(增刪改查語句,包括插入、更新、刪除)
n 對於公共表和公共行,或者二者之一的資源爭奪
- 常規商業報表
n 典型的「重複分段」報表的生成
n 一些數據分析(混合了其餘任務)
要肯定數據庫拆分是否適合您特定應用或環境,最重要的事情是評估您的數據庫結構能拆分的多好。從本質上講,數據庫拆分是一種「橫向」分區的方法,即單個表的行集(與列相反)分佈在多個子庫上。爲了搞清楚針對於特定狀況下斷定拆分的好壞的依據,如下一些事情很是重要:
- 找出您的數據庫結構中全部事務密集型的表
- 確認您的數據庫目前處理的事務數量(或者是預期須要處理的事務數量)
- 找出全部公用的SQL語句(選擇、插入、更新、刪除),確認每一個語句的使用量
- 理解您的數據庫結構的「表層次」,換句話說就是表之間的從屬關係。
- 肯定基於大容量表的事務的「鍵分佈」狀況,以肯定他們是否均勻地分佈仍是集中於狹窄的區域內。
有了以上信息,您能夠對拆分您的應用的價值和適用性作一個快速的評估。舉一個例子,這有一個簡單的書店系統的數據庫結構,顯示了數據是如何進行拆分的:
圖3. 圖例 書店系統數據庫結構,顯示了數據是如何進行拆分的
在書店系統這個例子當中,主拆分表是「顧客」表。這是用來拆分數據的表。「顧客」表是子庫的父表,「顧客訂單」表和「訂單書目詳情」表是其子表。這些數據根據「顧客ID」屬性進行拆分,全部子表中與指定「顧客ID」的行集都拆分的很好。那些全局表是公用的對照表,它們相對來講操做較少,並被複制給全部的子庫,以免跨子庫的聯接操做。
雖然這個例子很是簡單,但它提供了在決定如何對一個指定的數據庫應用進行拆分時,應該考慮的基本因素。經過這樣的評估方式,您就能夠肯定拆分是否適用於您的特定環境,以及數據庫拆分後所能帶來的好處。
6 結束語
本文對數據庫拆分作了一個概述,包括對數據拆分所面臨挑戰的討論,以及完成一個數據拆分方案的基本方法。數據庫拆分已經在許多大型組織中獲得了證實,也會很好的適用於您的應用中所碰到的具體問題。只要正確使用,數據庫拆分必定會幫助大量的商業事務應用實現得到低成本的、近於線性的擴展性能的目標。算法