1. 程式人生 > >分布式數據庫拆表拆庫的常用策略

分布式數據庫拆表拆庫的常用策略

工作 不同 mysq 其它 blog 詞條 缺點 很多 輕松

在大容量,高負荷的web系統中,對數據庫進行一系列拆分,可有效提升數據庫容量和性能。在初學程序的早期,程序員通常都喜歡按傳統數據庫設計模式,設計為單庫和單一功能表的結構,這樣的結構在數據量和並發量達到一定程度之後,會出現嚴重性能問題和維護問題。在出現問題的時候才著手進行優化,會非常痛苦,所以應該在系統架設之初就考慮好之後會出現的問題。

目前有些數據庫策略是采用單庫結構,然後通過同步分發到數臺服務器實現讀寫分離。個人覺得這樣的策略非常笨拙,還是想辦法將其分隔開來好,否則每臺機器的內存都很容易超支。

一般只對數據量比較大的表進行拆分,這應該沒有什麽異議;還有一種是有可能會進行維護的比較重要的表,比如文章目錄表,如果有從其它系統倒數據進來的可能的話,也要拆掉,不然倒數據時一不小心把目錄表弄壞了,發現忘了備份,那真是欲哭無淚。


下面來分析一下:

一、時間結構

如果業務系統對時效性較高,比如新聞發布系統的文章表,可以把數據庫設計成時間結構,按時間分有幾種結構:

1) 平板式

表類似:
article_200901
article_200902
article_200903

用年來分還是用月可自定,但用日期的話表就太多了,也沒這必要。一般建議是按月分就可以。

這種分法,其難處在於,假設我要列20條數據,結果這三張表裏都有2條,那麽業務上很有可能要求讀三次表。如果時間長了,有幾十張表,而每張表是0條,那不就是要讀完整個系統的表才行麽?另外這個結構,要作分頁是比較難實現的。

主鍵:在這個系統中,主鍵是13位帶毫秒的時間戳,不要用自動編號,否則難以通過主鍵定位到表,也可以在查詢時帶上時間,但比較煩瑣。

2) 歸檔式

表類似:
article_old
article_new

為了解決平板式的缺點,可以采用時間歸檔式設計,可以看到這個系統只有兩張表。一張是舊文章表,一張是新文章表,新文章表放2個月的信息,每天定期把2個月中的最早一天的文章歸入舊表中。這樣一方面可以解決性能問題,因為一般新聞發布系統讀取的都是新的內容,舊的內容讀取少;第二可以委婉地解決功能問題,比如平板式所說的問題,在歸檔式中最多也只需要讀2張表就完成了。

歸檔式的缺點在於舊表容量還是相對比較大,如果業務允許,可對舊表中的超舊內容進行再歸檔或直接清理掉。

二、版塊結構

如果按照文章的所屬版塊進行拆表,比如新聞、體育版塊拆表,一方面可以使每個表數據量分離,另一方面是各版塊之間相互影響可降到最低。假如新聞版塊的數據表損壞或需要維護,並不會影響到體育版塊的正常工作,從而降低了風險。版塊結構同時常用於bbs這樣的系統。

板塊結構也有幾種分法:

1) 對應式

對於版塊數量不多,而且較為固定的形式,就直接對應就好。比如新聞版塊,可以分出新聞的目錄表,新聞的文章表等。

news_category
news_article
sports_category
sports_article

可看到每一個版塊都對應著一組相同的表結構,好處就是一目了然。在功能上,因為版塊之間還是有一些隔閡,所以需要聯合查詢的需求不多,開發上比時間結構的方式要輕松。

主鍵:依舊要考慮的,在這個系統中,主鍵是版塊+時間戳,單純的時間戳或自動編號也能用,查詢時要記得帶上版塊用於定位表。

2) 冷熱式

對應式的缺點是,如果版塊數量很大而且不確定,那要分出的表數量就太多了。舉個例子:百度貼吧,如果按一個詞條一個表設計,那得有多少張表呢?

用這樣的方式吧。

tieba_汽車
tieba_飛機
tieba_火箭
tieba__unite

這個表汽車、火箭表是屬於熱門表,定義為新建的版塊放在unite表裏面,待到其超過一萬張主貼的時候才開對應表結構。因為在貼吧這種系統中,冷門版塊肯定比熱門版塊多得多,這些冷門版塊通常只有幾張帖子,為它們開表也太浪費了;同時熱門版塊數量和訪問量等,又比冷門版塊多得多,非常有特點。

unite表還可以擴展成哈希表,利用詞條的md5編碼,可以分成n張表,我算了一下,md5前一位可分16張表,兩位即是256張表。

tieba_unite_ab
tieba_unite_ac
...

三、哈希結構

哈希結構通常用於博客之類的基於用戶的場合,在博客這樣的系統裏有幾個特點,1是用戶數量非常多,2是每個用戶發的文章數量都較少,3是用戶發文章不定期,4是每個用戶發得不多,但總量仍非常之大。基於這些特點,用以上所說的任何一種分表方式都不合適,一沒有固定的時效不宜用時間拆,二用戶很多,而且還偏偏都是冷門,所以也不宜用版塊(用戶)拆。

哈希結構在上面有所提及,既然按每個用戶不好直接拆,那就把一群用戶歸進一個表好了。

blog_aa
blog_ab
blog_ac
...

如上所說,md5取前兩位哈希可以達到1296張表,如果覺得不夠,那就再加一位,總數可達46656張表,還不夠?

表的數量太多,要創建這些表也是挺麻煩的,可以考慮在程序裏往數據庫insert之前,多執行一句判斷表存在與否並創建表的語句,很實用,消耗也並不很大。

主鍵:依舊要考慮的,在這個系統中,主鍵是用戶ID+時間戳,單純的時間戳或自動編號也能用,但查詢時要記得帶上用戶名用於定位表。

四、總分結構

以上的這些結構,根據每個業務系統,能想出的估計還有很多。不過現在互聯網業務越來越復雜了,有些時候,單一的拆分法還不能實現需求,需要幾種拆分方案一起實施,多管齊下,這時候其中的邏輯會讓人繞暈。我就開發過一個系統,僅僅是將哈希結構和時間結構混著一用,覺得邏輯就相當復雜。

所以,除了拆表之外,按最原始的單庫單表,再建一個總表,是非常有利的架構。在這個架構中,每次往數據庫會寫入兩倍數據,讀取主要依賴拆表提升性能,總表用於實現拆表後難以實現的功能並且用於每天的定時備份;另外總表和分表還相互是一個完整的備份,任何一個分表損壞或數據不正常,都可以從總表中讀到正確的數據並恢復,反之亦然。

在總分結構中,讓人感到質疑的是總表的性能和可維護性。我的方案是總表可采用相對能保證穩定的一些服務軟件和架構,例如oracle,或 lvs+pgpool+PostgreSQL,重點保證數據穩定;相對的,分表就用輕量級的mysql,重點在於速度。能夠對總分表各采用不同的軟件和方案,也是總分結構的一大特點。



總結:如何通過拆表來優化系統,最基本的是要按業務需求和特點分析。本文僅僅是提供了幾種基本方法,具體工作要先動腦好好想,千萬不可亂套,用錯了工作量要加十倍噢。

分布式數據庫拆表拆庫的常用策略