天天看點

58同城資料庫架構設計思路(下)

DTCC(Database Tech Conference China)2015,中國資料庫技術大會舉辦在即,會上58同城将分享《資料庫架構師做什麼?58同城資料庫架構設計思路(下)》,大會内容搶先看,一起來看看58同城怎麼玩資料庫架構設計的。

58同城資料庫架構設計思路

(1)可用性設計

解決思路:複制+備援

副作用:複制+備援一定會引發一緻性問題

保證“讀”高可用的方法:複制從庫,備援資料,如下圖

58同城資料庫架構設計思路(下)

帶來的問題:主從不一緻

解決方案:見下文

保證“寫”高可用的一般方法:雙主模式,即複制主庫(很多公司用單master,此時無法保證寫的可用性),備援資料,如下圖

58同城資料庫架構設計思路(下)

帶來的問題:雙主同步key沖突,引不一緻

解決方案:

a)方案一:由資料庫或者業務層保證key在兩個主上不沖突

b)方案二:見下文

58同城保證“寫”高可用的方法:“雙主”當“主從”用,不做讀寫分離,在“主”挂掉的情況下,“從”(其實是另外一個主),頂上,如下圖

58同城資料庫架構設計思路(下)

優點:讀寫都到主,解決了一緻性問題;“雙主”當“主從”用,解決了可用性問題

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

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

最常用的方法是,建立索引

建立非常多的索引,副作用是:

a)降低了寫性能

b)索引占記憶體多了,放在記憶體中的資料就少了,資料命中率就低了,IO次數就多了

但是否想到,不同的庫可以建立不同的索引呢?如下圖

58同城資料庫架構設計思路(下)

TIPS:不同的庫可以建立不同索引

主庫隻提供寫,不建立索引

online從庫隻提供online讀,建立online讀索引

offline從庫隻提供offline讀,建立offline讀索引

提高讀性能常見方案二,增加從庫

58同城資料庫架構設計思路(下)

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

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

提高讀性能方案三,增加緩存

傳統緩存的用法是:

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

b)發生讀請求時,先讀緩存,hit則傳回,miss則讀資料庫并将資料入緩存(此時可能舊資料入緩存),如下圖

58同城資料庫架構設計思路(下)

帶來的問題:

a)如上文所述,資料複制會引發一緻性問題,由于主從延時的存在,可能引發緩存與資料庫資料不一緻

b)所有app業務層都要關注緩存,無法屏蔽“主+從+緩存”的複雜性

58同城緩存使用方案:服務+資料+緩存

58同城資料庫架構設計思路(下)

好處是:

1)引入服務層屏蔽“資料庫+緩存”

2)不做讀寫分離,讀寫都到主的模式,不會引發不一緻

(3)一緻性設計

主從不一緻解決方案

方案一:引入中間件

58同城資料庫架構設計思路(下)

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

方案二:讀寫都到主

58同城資料庫架構設計思路(下)

上文已經提到,58同城采用了這種方法,不做讀寫分離,不會不一緻

資料庫與緩存不一緻解決方案

兩次淘汰法

58同城資料庫架構設計思路(下)

異常的讀寫時序,或導緻舊資料入緩存,一次淘汰不夠,要進行二次淘汰

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

b)發生讀請求時,先讀緩存,hit則傳回,miss則讀資料庫并将資料入緩存(此時可能舊資料入緩存,但會被二次淘汰淘汰掉,最終不會引發不一緻)

(4)擴充性設計

(4.1)58同城秒級别資料擴容

需求:原來水準切分為N個庫,現在要擴充為2N個庫,希望不影響服務,在秒級别完成

58同城資料庫架構設計思路(下)
最開始,分為2庫,0庫和1庫,均采用“雙主當主從用”的模式保證可用性
58同城資料庫架構設計思路(下)

接下來,将從庫提升,并修改服務端配置,秒級完成擴庫

由于是2擴4,不會存在資料遷移,原來的0庫變為0庫+2庫,原來的1庫變為1庫和3庫

此時損失的是資料的可用性

58同城資料庫架構設計思路(下)

最後,解除舊的雙主同步(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庫)

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

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

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

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

步驟二、找到步驟一傳回的min和max,即3和11

步驟三、通過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

步驟四、找出全局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同城資料實戰(上) + 58同城資料庫設計(下)的内容全部完成。