概念一「單庫」mysql
概念二「分片」算法
分片解決的是「數據量太大」的問題,也就是一般說的「水平切分」。sql
一旦引入分片,勢必有「數據路由」的概念,哪一個數據訪問哪一個庫。數據庫
路由規則一般有3種方法:緩存
(1)範圍:range架構
優勢:簡單,容易擴展異步
缺點:各庫壓力不均(新號段更活躍)性能
(2)哈希:hashui
優勢:簡單,數據均衡,負載均勻spa
缺點:遷移麻煩(2庫擴3庫數據要遷移)
(3)路由服務:router-config-server
優勢:靈活性強,業務與路由算法解耦
缺點:每次訪問數據庫前多一次查詢
大部分互聯網公司採用的方案二:哈希分庫,哈希路由
概念三「分組」
分組解決「可用性」問題,分組一般經過主從複製的方式實現。
互聯網公司數據庫實際軟件架構是:又分片,又分組(以下圖)
數據庫軟件架構師平時設計些什麼東西呢?至少要考慮如下四點:
(1)如何保證數據可用性
(2)如何提升數據庫讀性能(大部分應用讀多寫少,讀會先成爲瓶頸)
(3)如何保證一致性
(4)如何提升擴展性
解決可用性問題的思路是=>冗餘
如何保證站點的可用性?複製站點,冗餘站點
如何保證服務的可用性?複製服務,冗餘服務
如何保證數據的可用性?複製數據,冗餘數據
數據的冗餘,會帶來一個反作用=>引起一致性問題(先不說一致性問題,先說可用性)
如何保證數據庫「讀」高可用?
冗餘讀庫
冗餘讀庫帶來的反作用?讀寫有延時,可能不一致
上面這個圖是不少互聯網公司mysql的架構,寫仍然是單點,不能保證寫高可用。
如何保證數據庫「寫」高可用?
冗餘寫庫
採用雙主互備的方式,能夠冗餘寫庫
帶來的反作用?雙寫同步,數據可能衝突(例如「自增id」同步衝突),如何解決同步衝突,有兩種常看法決方案:
(1)兩個寫庫使用不一樣的初始值,相同的步長來增長id:1寫庫的id爲0,2,4,6...;2寫庫的id爲1,3,5,7…
(2)不使用數據的id,業務層本身生成惟一的id,保證數據不衝突
58同城沒有使用上述兩種架構來作讀寫的「高可用」,58同城採用的是「雙主當主從用」的方式:
還是雙主,但只有一個主提供服務(讀+寫),另外一個主是「shadow-master」,只用來保證高可用,平時不提供服務。
master掛了,shadow-master頂上(vip漂移,對業務層透明,不須要人工介入)
這種方式的好處:
1)讀寫沒有延時
2)讀寫高可用
不足:
1)不能經過加從庫的方式擴展讀性能
2)資源利用率爲50%,一臺冗餘主沒有提供服務
那如何提升讀性能呢?進入第二個話題,如何提供讀性能。
提升讀性能的方式大體有三種,第一種是創建索引。這種方式不展開,要提到的一點是,不一樣的庫能夠創建不一樣的索引。
寫庫不創建索引;
線上讀庫創建線上訪問索引,例如uid;
線下讀庫創建線下訪問索引,例如time;
第二種擴充讀性能的方式是,增長從庫,這種方法你們用的比較多,可是,存在兩個缺點:
(1)從庫越多,同步越慢
(2)同步越慢,數據不一致窗口越大(不一致後面說,仍是先說讀性能的提升)
58同城沒有采用這種方法提升數據庫讀性能(沒有從庫),採用的是增長緩存。常見的緩存架構以下:
上游是業務應用,下游是主庫,從庫(讀寫分離),緩存。
58同城的玩法是:服務+數據庫+緩存一套
業務層不直接面向db和cache,服務層屏蔽了底層db、cache的複雜性。爲何要引入服務層,今天不展開,58採用了「服務+數據庫+緩存一套」的方式提供數據訪問,用cache提升讀性能。
無論採用主從的方式擴展讀性能,仍是緩存的方式擴展讀性能,數據都要複製多份(主+從,db+cache),必定會引起一致性問題。
主從數據庫的一致性,一般有兩種解決方案:
(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設置一個超時時間。
說完一致性,最後一個話題是擴展性。
原來用hash的方式路由,分爲2個庫,數據量仍是太大,要分爲3個庫,勢必須要進行數據遷移,58同城有一個很帥氣的「數據庫秒級擴容」方案。
如何秒級擴容?
首先,咱們不作2庫變3庫的擴容,咱們作2庫變4庫(庫加倍)的擴容(將來4->8->16)
服務+數據庫是一套(省去了緩存)
數據庫採用「雙主」的模式。
擴容步驟:
第一步,將一個主庫提高
第二步,修改配置,2庫變4庫(原來MOD2,如今配置修改後MOD4)
擴容完成
原MOD2爲偶的部分,如今會MOD4餘0或者2
原MOD2爲奇的部分,如今會MOD4餘1或者3
數據不須要遷移,同時,雙主互相同步,一遍是餘0,一邊餘2,兩邊數據同步也不會衝突,秒級完成擴容!
最後,要作一些收尾工做:
(1)將舊的雙主同步解除
(2)增長新的雙主(雙主是保證可用性的,shadow-master平時不提供服務)
(3)刪除多餘的數據(餘0的主,能夠將餘2的數據刪除掉)
這樣,秒級別內,咱們就完成了2庫變4庫的擴展。
OK,今天主要分享了58同城,數據庫軟件架構上:
(1)如何保證數據可用性
(2)如何提升數據庫讀性能
(3)如何保證數據一致性
(4)如何進行秒級擴容
轉自:58沈劍 架構師之路