互聯網數據庫架構設計思路

一 、58同城數據庫架構設計思路

(1)可用性設計html

解決思路:複製+冗餘sql

反作用:複製+冗餘必定會引起一致性問題數據庫

保證「讀」高可用的方法:複製從庫,冗餘數據,以下圖緩存

 0
帶來的問題:主從不一致微信

解決方案:見下文網絡

保證「寫」高可用的通常方法:雙主模式,即複製主庫(不少公司用單master,此時沒法保證寫的可用性),冗餘數據,以下圖架構

 1
帶來的問題:雙主同步key衝突,引不一致app

解決方案:數據庫設計

a)方案一:由數據庫或者業務層保證key在兩個主上不衝突分佈式

b)方案二:見下文

58同城保證「寫」高可用的方法:「雙主」當「主從」用,不作讀寫分離,在「主」掛掉的狀況下,「從」(實際上是另一個主),頂上,以下圖

 2
優勢:讀寫都到主,解決了一致性問題;「雙主」當「主從」用,解決了可用性問題

帶來的問題:讀性能如何擴充?解決方案見下文

(2)讀性能設計:如何擴展讀性能

最經常使用的方法是,創建索引

創建很是多的索引,反作用是:

a)下降了寫性能

b)索引佔內存多了,放在內存中的數據就少了,數據命中率就低了,IO次數就多了

可是否想到,不一樣的庫能夠創建不一樣的索引呢?以下圖

 3
TIPS:不一樣的庫能夠創建不一樣索引

主庫只提供寫,不創建索引

online從庫只提供online讀,創建online讀索引

offline從庫只提供offline讀,創建offline讀索引

提升讀性能常見方案二,增長從庫

4

上文已經提到,這種方法會引起主從不一致問題,從庫越多,主從時延越長,不一致問題越嚴重

這種方案很常見,但58沒有采用

提升讀性能方案三,增長緩存

傳統緩存的用法是:

a)發生寫請求時,先淘汰緩存,再寫數據庫

b)發生讀請求時,先讀緩存,hit則返回,miss則讀數據庫並將數據入緩存(此時可能舊數據入緩存),以下圖

 5
帶來的問題:

a)如上文所述,數據複製會引起一致性問題,因爲主從延時的存在,可能引起緩存與數據庫數據不一致

b)全部app業務層都要關注緩存,沒法屏蔽「主+從+緩存」的複雜性

58同城緩存使用方案:服務+數據+緩存

 6
好處是:

1)引入服務層屏蔽「數據庫+緩存」

2)不作讀寫分離,讀寫都到主的模式,不會引起不一致

(3)一致性設計

主從不一致解決方案

方案一:引入中間件

 7
中間件將key上的寫路由到主,在必定時間範圍內(主從同步完成的經驗時間),該key上的讀也路由到主

方案二:讀寫都到主

8

上文已經提到,58同城採用了這種方法,不作讀寫分離,不會不一致

數據庫與緩存不一致解決方案

兩次淘汰法

9

異常的讀寫時序,或致使舊數據入緩存,一次淘汰不夠,要進行二次淘汰

a)發生寫請求時,先淘汰緩存,再寫數據庫,額外增長一個timer,必定時間(主從同步完成的經驗時間)後再次淘汰

b)發生讀請求時,先讀緩存,hit則返回,miss則讀數據庫並將數據入緩存(此時可能舊數據入緩存,但會被二次淘汰淘汰掉,最終不會引起不一致)

(4)擴展性設計

(4.1)58同城秒級別數據擴容

需求:原來水平切分爲N個庫,如今要擴充爲2N個庫,但願不影響服務,在秒級別完成

 10
最開始,分爲2庫,0庫和1庫,均採用「雙主當主從用」的模式保證可用性

 11
接下來,將從庫提高,並修改服務端配置,秒級完成擴庫

因爲是2擴4,不會存在數據遷移,原來的0庫變爲0庫+2庫,原來的1庫變爲1庫和3庫

此時損失的是數據的可用性

 12
最後,解除舊的雙主同步(0庫和2庫不會數據衝突),爲了保證可用性增長新的雙主同步,並刪除掉多餘的數據

這種方案能夠秒級完成N庫到2N庫的擴容。

存在的問題:只能完成N庫擴2N庫的擴容(不須要數據遷移),非通用擴容方案(例如3庫擴4庫就沒法完成)

(4.2)非指數擴容,數據庫增長字段,數據遷移

[這些方法在(上)篇中都已經介紹過,此處再也不冗餘,有興趣的朋友回覆「同城」回看(上)篇]

方案一:追日誌方案

方案二:雙寫方案

(4.3)水平切分怎麼切

四類場景覆蓋99%拆庫業務

a)「單key」場景,用戶庫如何拆分: user(uid, XXOO)

b)「1對多」場景,帖子庫如何拆分: tiezi(tid, uid, XXOO)

c)「多對多」場景,好友庫如何拆分: friend(uid, friend_uid, XXOO)

d)「多key」場景,訂單庫如何拆分:order(oid, buyer_id, seller_id, XXOO)

[這些拆庫方案在(上)篇中都已經介紹過,此處再也不冗餘,有興趣的朋友回覆「同城」回看(上)篇]

(5)海量數據下,SQL怎麼玩

不會這麼玩

a)各類聯合查詢

b)子查詢

c)觸發器

d)用戶自定義函數

e)「事務」都用的不多

緣由:對數據庫性能影響極大

拆庫後,IN查詢怎麼玩[回覆「同城」回看(上)篇]

拆庫後,非Partition key的查詢怎麼玩[回覆「同城」回看(上)篇]

拆庫後,誇庫分頁怎麼玩?[回覆「同城」回看(上)篇]

問題的提出與抽象:ORDER BY xxx OFFSET xxx LIMIT xxx

單機方案:ORDER BY time OFFSET 10000 LIMIT 100

分庫後的難題:如何確認全局偏移量

分庫後傳統解決方案:查詢改寫+內存排序

a)ORDER BY time OFFSET 0 LIMIT 10000+100

b)對20200條記錄進行排序

c)返回第10000至10100條記錄

優化方案一:增長輔助id,以減小查詢量

優化方案二:模糊查詢

a)業務上:禁止查詢XX頁以後的數據

b)業務上:容許模糊返回 => 第100頁數據的精確性真這麼重要麼?

最後的大招!!!(因爲時間問題,只在DTCC2015上分享了喲)

優化方案三:終極方案,業務無損,查詢改寫與兩段查詢

需求:ORDER BY x OFFSET 10000 LIMIT 4; 如何在分庫下實現(假設分3庫)

步驟1、查詢改寫: ORDER BY x OFFSET 3333 LIMIT 4

[4,7,9,10] <= 1庫返回

[3,5,6,7] <= 2庫返回

[6,8,9,11] <= 3庫返回

步驟2、找到步驟一返回的min和max,即3和11

步驟3、經過min和max二次查詢:ORDER BY x WHERE x BETWEEN 3 AND 11

[3,4,7,9,10] <= 1庫返回,4在1庫offset是3333,因而3在1庫的offset是3332

[3,5,6,7,11] <= 2庫返回,3在2庫offset是3333

[3,5,6,8,9,11] <= 3庫返回,6在3庫offset是3333,因而3在3庫的offset是3331

步驟4、找出全局OFFSET

3是全局offset3332+3333+3331=9996

噹噹噹當,跳過3,3,3,4,因而全局OFFSET 10000 LIMIT 4是[5,5,6,6]

總結:58同城數據庫架構設計思路

(1)可用性,解決思路是冗餘(複製)

(1.1)讀可用性:多個從庫

(1.2)寫可用性:雙主模式 or 雙主當主從用(58的玩法)

(2)讀性能,三種方式擴充讀性能

(2.1)增長索引:主從上的索引能夠不同

(2.2)增長從庫

(2.3)增長緩存:服務+緩存+數據一套(58的玩法)

(3)一致性

(3.1)主從不一致:引入中間層 or 讀寫都走主庫(58的玩法)

(3.2)緩存不一致:雙淘汰來解決緩存不一致問題

(4)擴展性

(4.1)數據擴容:提高從庫,double主庫,秒級擴容

(4.2)字段擴展:追日誌法 or 雙寫法

(4.3)水平切分

(單key)用戶庫如何拆分:, user(uid XXOO)

(1對多)帖子庫如何拆分: tiezi(tid, uid, XXOO)

(多對多)好友庫如何拆分: friend(uid, friend_uid, XXOO)

(多key)訂單庫如何拆分:order(oid, buyer_id, seller_id, XXOO)

(5)SQL玩法

(5.0)不這麼玩:聯合查詢,子查詢,觸發器,自定義函數,事務

(5.1)IN查詢:分發MR or 拼裝成不一樣SQL語句

(5.2)非partition key查詢:定位一個庫 or 分發MR

(5.3)誇庫分頁

(5.3.1)修改sql語句,服務內排序

(5.3.2)引入特殊id,減小返回數量

(5.3.3)業務優化,容許模糊查詢

(5.3.4)查詢改寫,二段查詢

58同城的案例到這兒

 

2、數據庫之父Codd的12條法則

另外,咱們回顧一下數據庫之父Codd的12條法則,做爲數據庫設計的指導性方針:

  1. 信息法則
    關係數據庫中的全部信息都用惟一的一種方式表示——表中的值。
  2. 保證訪問法則
    依靠表名、主鍵值和列名的組合,保證能訪問每一個數據項。
  3. 空值的系統化處理
    支持空值(NULL),以系統化的方式處理空值,空值不依賴於數據類型。
  4. 基於關係模型的動態聯機目錄
    數據庫的描述應該是自描述的,在邏輯級別上和普通數據採用一樣的表示方式,即數據庫必須含有描述該數據庫結構的系統表或者數據庫描述信息應該包含在用戶能夠訪問的表中。
  5. 統一的數據子語言法則
    一個關係數據庫系統能夠支持幾種語言和多種終端使用方式,但必須至少有一種語言,它的語句可以一某種定義良好的語法表示爲字符串,並能全面地支持如下全部規則:數據定義、視圖定義、數據操做、約束、受權以及事務。(這種語言就是SQL)
  6. 視圖更新法則
    全部理論上能夠更新的視圖也能夠由系統更新。
  7. 高級的插入、更新和刪除操做
    把一個基礎關係或派生關係做爲單個操做對象處理的能力不只適應於數據的檢索,還適用於數據的插入、修改個刪除,即在插入、修改和刪除操做中數據行被視做集合。
  8. 數據的物理獨立性
    無論數據庫的數據在存儲表示或訪問方式上怎麼變化,應用程序和終端活動都保持着邏輯上的不變性。
  9. 數據的邏輯獨立性
    當對錶作了理論上不會損害信息的改變時,應用程序和終端活動都會保持邏輯上的不變性。
  10. 數據完整性的獨立性
    專用於某個關係型數據庫的完整性約束必須能夠用關係數據庫子語言定義,並且能夠存儲在數據目錄中,而非程序中。
  11. 分佈獨立性
    無論數據在物理是否分佈式存儲,或者任什麼時候候改變分佈策略,RDBMS的數據操縱子語言必須能使應用程序和終端活動保持邏輯上的不變性。
  12. 非破壞性法則
    若是一個關係數據庫系統支持某種低級(一次處理單個記錄)語言,那麼這個低級語言不能違反或繞過更高級語言(一次處理多個記錄)規定的完整性法則或約束,即用戶不能以任何方式違反數據庫的約束。

 

還有一些經驗:

  • 下降對數據庫功能的依賴
    功能應該由程序實現,而非DB實現。緣由在於,若是功能由DB實現時,一旦更換的DBMS不如以前的系統強大,不能實現某些功能,這時咱們將不得不去修改代碼。因此,爲了杜絕此類狀況的發生,功能應該有程序實現,數據庫僅僅負責數據的存儲,以達到最低的耦合。
  • 定義實體關係的原則
    當定義一個實體與其餘實體之間的關係時,須要考量以下:
    • 牽涉到的實體 識別出關系所涉及的全部實體。
    • 全部權 考慮一個實體「擁有」另外一個實體的狀況。
    • 基數 考量一個實體的實例和另外一個實體實例關聯的數量。



來自網絡資料收集與整合,但願對您軟件開發有幫助。 其它您可能感興趣的文章:
企業應用之性能實時度量系統演變
雲計算參考架構幾例
智能移動導遊解決方案簡介
人力資源管理系統的演化

若有想了解更多軟件,系統 IT,企業信息化 資訊,請關注個人微信訂閱號:

MegadotnetMicroMsg_thumb1_thumb1_thu[1]


做者:Petter Liu
出處:http://www.cnblogs.com/wintersun/
本文版權歸做者和博客園共有,歡迎轉載,但未經做者贊成必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接,不然保留追究法律責任的權利。
該文章也同時發佈在個人獨立博客中-Petter Liu Blog

相關文章
相關標籤/搜索