58同城數據庫軟件架構設計與實踐

轉載自

http://mp.weixin.qq.com/s?__biz=MjM5ODYxMDA5OQ==&mid=400465735&idx=1&sn=8d7067de4cc8f73ea5558f07e0a9340e&scene=0#wechat_redirect

緣起:受@蕭田國 蕭總邀請,上週五晚上在“高效運維1號羣”內分享了《58同城數據庫軟件架構設計與實踐》(這個topic今年在數據庫大會上分享過),應組織方要求,發出紀要。


一、基本概念

二、數據庫架構設計思路

1)可用性

2)讀性能

3)一致性

4)擴展性

 


一、基本概念

概念一“單庫”

 

概念二“分片”


分片解決的是“數據量太大”的問題,也就是通常說的“水平切分”。

一旦引入分片,勢必有“數據路由”的概念,哪個數據訪問哪個庫。

 

路由規則通常有3種方法:

1範圍range

優點:簡單,容易擴展

缺點:各庫壓力不均(新號段更活躍)

2哈希hash

優點:簡單,數據均衡,負載均勻

缺點:遷移麻煩(2庫擴3庫數據要遷移)

3路由服務router-config-server

優點:靈活性強,業務與路由算法解耦

缺點:每次訪問數據庫前多一次查詢

 

大部分互聯網公司採用的方案二:哈希分庫,哈希路由

 

概念三“分組”


分組解決“可用性”問題,分組通常通過主從複製的方式實現。

 

互聯網公司數據庫實際軟件架構是:又分片,又分組(如下圖)

 


二、數據庫架構設計思路

數據庫軟件架構師平時設計些什麼東西呢?至少要考慮以下四點:

1)如何保證數據可用性

2)如何提高數據庫讀性能(大部分應用讀多寫少,讀會先成爲瓶頸)

3)如何保證一致性

4)如何提高擴展性


2.1如何保證數據的可用性?

解決可用性問題的思路是=>冗餘

如何保證站點的可用性?複製站點,冗餘站點

如何保證服務的可用性?複製服務,冗餘服務

如何保證數據的可用性?複製數據,冗餘數據

 

數據的冗餘,會帶來一個副作用=>引發一致性問題(先不說一致性問題,先說可用性)

 

如何保證數據庫“讀”高可用?

冗餘讀庫


冗餘讀庫帶來的副作用?讀寫有延時,可能不一致

上面這個圖是很多互聯網公司mysql的架構,寫仍然是單點,不能保證寫高可用。

 

如何保證數據庫“寫”高可用?

冗餘寫庫


採用雙主互備的方式,可以冗餘寫庫

帶來的副作用?雙寫同步,數據可能衝突(例如“自增id”同步衝突),如何解決同步衝突,有兩種常見解決方案:

1)兩個寫庫使用不同的初始值,相同的步長來增加id1寫庫的id0,2,4,6...2寫庫的id1,3,5,7…

2)不使用數據的id,業務層自己生成唯一的id,保證數據不衝突

 

58同城沒有使用上述兩種架構來做讀寫的“高可用”,58同城採用的是“雙主當主從用”的方式


仍是雙主,但只有一個主提供服務(讀+寫),另一個主是“shadow-master”,只用來保證高可用,平時不提供服務。

master掛了,shadow-master頂上(vip漂移,對業務層透明,不需要人工介入)

這種方式的好處

1)讀寫沒有延時

2)讀寫高可用

不足

1)不能通過加從庫的方式擴展讀性能

2)資源利用率爲50%,一臺冗餘主沒有提供服務

 

那如何提高讀性能呢?進入第二個話題,如何提供讀性能。


2.2如何擴展讀性能?

提高讀性能的方式大致有三種,第一種是建立索引這種方式不展開,要提到的一點是,不同的庫可以建立不同的索引


寫庫不建立索引;

線上讀庫建立線上訪問索引,例如uid

線下讀庫建立線下訪問索引,例如time

 

第二種擴充讀性能的方式是,增加從庫,這種方法大家用的比較多,但是,存在兩個缺點:

1)從庫越多,同步越慢

2)同步越慢,數據不一致窗口越大(不一致後面說,還是先說讀性能的提高)

 

58同城沒有采用這種方法提高數據庫讀性能(沒有從庫),採用的是增加緩存常見的緩存架構如下:


上游是業務應用,下游是主庫,從庫(讀寫分離),緩存。

 

58同城的玩法是:服務+數據庫+緩存一套


業務層不直接面向dbcache,服務層屏蔽了底層dbcache的複雜性。爲什麼要引入服務層,今天不展開,58採用了“服務+數據庫+緩存一套”的方式提供數據訪問,用cache提高讀性能。

 

不管採用主從的方式擴展讀性能,還是緩存的方式擴展讀性能,數據都要複製多份(主+從,db+cache),一定會引發一致性問題。


2.3如何保證一致性?

主從數據庫的一致性,通常有兩種解決方案:

1)中間件


如果某一個key有寫操作,在不一致時間窗口內,中間件會將這個key的讀操作也路由到主庫上。

這個方案的缺點是,數據庫中間件的門檻較高(百度,騰訊,阿里,360等一些公司有,當然58也有)

2)強制讀主


58的“雙主當主從用”的架構,不存在主從不一致的問題。

 

第二類不一致,是db與緩存間的不一致


常見的緩存架構如上,此時寫操作的順序是

1)淘汰cache

2)寫數據庫

讀操作的順序是

1)讀cache,如果cache hit則返回

2)如果cache miss,則讀從庫

3)讀從庫後,將數據放回cache

 

在一些異常時序情況下,有可能從【從庫讀到舊數據(同步還沒有完成),舊數據入cache後】,數據會長期不一致。

 

解決辦法是“緩存雙淘汰”,寫操作時序升級爲:

1)淘汰cache

2)寫數據庫

3)在經驗“主從同步延時窗口時間”後,再次發起一個異步淘汰cache的請求

 

這樣,即使有髒數據如cache,一個小的時間窗口之後,髒數據還是會被淘汰。帶來的代價是,多引入一次讀miss(成本可以忽略)。

 

除此之外,58同城的最佳實踐之一是:建議爲所有cache中的item設置一個超時時間。

 

說完一致性,最後一個話題是擴展性。


2.4如何提高數據庫的擴展性?

原來用hash的方式路由,分爲2個庫,數據量還是太大,要分爲3個庫,勢必需要進行數據遷移,58同城有一個很帥氣的“數據庫秒級擴容”方案。

如何秒級擴容?

首先,我們不做2庫變3庫的擴容,我們做2庫變4(庫加倍)的擴容(未來4->8->16

服務+數據庫是一套(省去了緩存)

數據庫採用“雙主”的模式。

 

擴容步驟

第一步,將一個主庫提升

第二步,修改配置,2庫變4庫(原來MOD2,現在配置修改後MOD4

擴容完成

MOD2爲偶的部分,現在會MOD40或者2

MOD2爲奇的部分,現在會MOD41或者3

數據不需要遷移,同時,雙主互相同步,一遍是餘0,一邊餘2,兩邊數據同步也不會衝突,秒級完成擴容!

 

最後,要做一些收尾工作:

1)將舊的雙主同步解除

2)增加新的雙主(雙主是保證可用性的,shadow-master平時不提供服務)

3)刪除多餘的數據(餘0的主,可以將餘2的數據刪除掉)


這樣,秒級別內,我們就完成了2庫變4庫的擴展。


OK,今天主要分享了58同城,數據庫軟件架構上:

1)如何保證數據可用性

2)如何提高數據庫讀性能

3)如何保證數據一致性

4)如何進行秒級擴容

希望大家有收穫,謝謝大家!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章