MySQL 高可用架構在業務層面的分析研究

作者: 黃杉  來源: CSDN  發布時間: 2014-10-10 07:11  閱讀: 6654 次  推薦: 11   原文鏈接   [收藏]  

  前言:

  相對于傳統行業的相對服務時間9x9x6或者9x12x5,因為互聯網電子商務以及互聯網游戲的實時性,所以服務要求7*24小時,業務架構不管是應用還是數據庫,都需要容災互備,在mysql的體系中,最好通過在最開始階段的數據庫架構階段來實現容災系統。所以這里從業務宏觀角度闡述下mysql架構的方方面面。

  一. MySQL架構設計—業務分析

  (1)讀多寫少

  虛線表示跨機房部署,比如電子商務系統,一個Master既有讀也有些寫,對讀數據一致性需要比較重要的,讀要放在Master上面。

  M(R)僅僅是一個備庫,只有M(WR)掛了之后,才會切換到M(R)上,這個時候M(R)就變成了讀寫庫。比如游戲系統,有很多Salve會掛載后面一個M(R)上面。

  (2)讀多寫少MMS-電商

  如果是電子商務類型的,這種讀多寫少的,一般是1個master拖上4到6個slave,所有slave掛載在一個master也足夠了。

  切換的時候,把M1的讀寫業務切換到M2上面,然后把所有M1上的slave掛到M2上面去,如下所示:

  (3)讀多寫少MMSS-游戲

  如果是游戲行業的話,讀非常多蠻明顯的,會出現一般1個Master都會掛上10個以上的Slave的情況,所以這個時候,可以把一部分Slave掛載新的M(R)上面。至少會減少一些壓力,這樣至少服務器掛掉的時候,不會對所有的slave有影響,還有一部分在M(R)上的slave在繼續,不會對所有的slave受到影響,見圖3,

圖3

  (4)讀少寫多

  意味著讀并不會影響寫的效率,所以讀寫都可以放在一個M1(WR),而另外一個不提供讀也不提供寫,只提供standby冗余異地容災。

  這個異地容災是非常重要的,否則如果是單機的,單邊的業務,萬一idc機房故障了,一般就會影響在線業務的,這種 造成業務2小時無法應用,對于在線電子商務交易來說,影響是蠻大的,所以為了最大限度的保證7*24小時,必須要做到異地容災,MM要跨idc機房。雖然對資源有一些要求,但是對HA來說是不可缺少的,一定要有這個MM機制。

  做切換的時候,把所有的讀寫從M1直接切換到M2上就可以了。

  (5)讀寫平分秋色

  讀和寫差不多,但是讀不能影響寫的能力,把讀寫放在M1(WR)上,然后把一部分讀也放在M2(R)上面,當然M1和M2也是跨機房部署的。

  切換的時候,把一部分讀和全部寫從M1切換到M2上就可以了。

  二. MySQL架構設計—常見架構

  (1)強一致性

  對讀一致性的權衡,如果是對讀寫實時性要求非常高的話,就將讀寫都放在M1上面,M2只是作為standby,就是采取和上面的一(4)的讀少寫多的一樣的架構模式。

  比如,訂單處理流程,那么對讀需要強一致性,實時寫實時讀,類似這種涉及交易的或者動態實時報表統計的都要采用這種架構模式

  (2)弱一致性

  如果是弱一致性的話,可以通過在M2上面分擔一些讀壓力和流量,比如一些報表的讀取以及靜態配置數據的讀取模塊都可以放到M2上面。比如月統計報表,比如首頁推薦商品業務實時性要求不是很高,完全可以采用這種弱一致性的設計架構模式。

  (3)中間一致性

  如果既不是很強的一致性又不是很弱的一致性,那么我們就采取中間的策略,就是在同機房再部署一個S1(R),作為備庫,提供讀取服務,減少M1(WR)的壓力,而另外一個idc機房的M2只做standby容災方式的用途。

  當然這里會用到3臺數據庫服務器,也許會增加采購壓力,但是我們可以提供更好的對外數據服務的能力和途徑,實際中盡可能兩者兼顧。

  (4)統計業務

  比如PV、UV操作、頁數的統計、流量的統計、數據的匯總等等,都可以劃歸為統計類型的業務。

  數據庫上做大查詢的統計是非常消耗資源的。統計分為實時的統計和非實時的統計,由于mysql主從是邏輯sql的模式,所以不能達到100%的實時,如果是online要嚴格的非常實時的統計比如像火車票以及金融異地結算等的統計,mysql這塊不是它的強項,就只有查詢M1主庫來實現了。

  A,但是對于不是嚴格的實時性的統計,mysql有個很好的機制是binlog,我們可以通過binlog進行解析Parser,解析出來寫入統計表進行統計或者發消息給應用端程序來進行統計。這種是準實時的統計操作,有一定的短暫的可接受的統計延遲現象,如果要100%實時性統計只有查詢M1主庫了。

  通過binlog的方式實現統計,在互聯網行業,尤其是電商和游戲這塊,差不多可以解決90%以上的統計業務。有時候如果用戶或者客戶提出要實時read-time了,大家可以溝通一下為什么需要實時,了解具體的業務場景,有些可能真的不需要實時統計,需要有所權衡,需要跟用戶和客戶多次有效溝通,做出比較適合業務的統計架構模型。

  B,還有一種offline統計業務,比如月份報表年報表統計等,這種完全可以把數據放到數據倉庫里面或者第三方Nosql里面進行統計。

  (5)歷史數據遷移

  歷史數據遷移,需要盡量不影響現在線上的業務,盡量不影響現在線上的查詢寫入操作,為什么要做歷史數據遷移?因為有些業務的數據是有時效性的,比如電商中的已經完成的歷史訂單等,不會再有更新操作了,只有很簡單的查詢操作,而且查詢也不會很頻繁,甚至可能一天都不會查詢一次。

  如果這時候歷史數據還在online庫里面或者online表里面,那么就會影響online的性能,所以對于這種,可以把數據遷移到新的歷史數據庫上,這個歷史數據庫可以是mysql也可以是nosql,也可以是數據倉庫甚至hbase大數據等。

  實現途徑是通過slave庫查詢出所有的數據,然后根據業務規則比如時間、某一個緯度等過濾篩選出數據,放入歷史數據庫(History Databases)里面。遷移完了,再回到主庫M1上,刪除掉這些歷史數據。這樣在業務層面,查詢就要兼顧現在實時數據和歷史數據,可以在filter上面根據遷移規則把online查詢和history查詢對接起來。比如說一個月之內的在online庫查詢一個月之前的在history庫查詢,可以把這個規則放在DB的遷移filter層和應用查詢業務模塊層。如果可以的話,還可以配置更細化,通過應用查詢業務模塊層來影響DB的遷移filter層,比如以前查詢分為一個月為基準,現在查詢業務變化了,以15天為基準,那么應用查詢業務模塊層變化會自動讓DB的filter層也變化,實現半個自動化,更加智能一些。

  (6)MySQL Sharding

  像oracle這種基于rac基于共享存儲的方式,不需要sharding只需要擴從rac存儲就能實現了。但是這種代價相對會比較高一些,共享存儲一般都比較貴,隨著業務的擴展數據的爆炸式增長,你會不停累計你的成本,甚至達到一個天文數字。

  目前這種share disk的方式,除了oracle的業務邏輯層做的非常完善之外其他的解決方案都還不是很完美。

  Mysql的sharding也有其局限性,sharding之后的數據查詢訪問以及統計都會有很大的問題,mysql的sharding是解決share nothing的存儲的一種分布式的方法,大體上分為垂直拆分和水平拆分。

  (6.1)垂直拆分

  可以橫向拆分,可以縱向拆分,可以橫向縱向拆分,還可以按照業務拆分。

  6.1.1橫向拆分

  Mysql庫里面的橫向拆分是指,每一個數據庫實例里面都有很多個db庫,每一個db庫里面都有A表B表,比如db1庫有A表B表,db2庫里也有A表和B表,那么我們把db1、db2庫的A表B表拆分出來,把一個庫分成2個,就拆分成db1、db2、db3、db4,其中db1庫和db2庫放A表數據,db3庫和db4庫放B表的數據,db1、db2庫里面只有A表數據,db3、db4庫里面只有B表的數據。

  打個比方,作為電商來說,每個庫里面都有日志表和訂單表,假如A表是日志表log表,B表是訂單表Order表,一般說來寫日志和寫訂單沒有強關聯性,我們可以講A表日志表和B表訂單表拆分出來。那么這個時候就做了一次橫向的拆分工作,將A表日志表和B表訂單表拆分開來放在不同的庫,當然A表和B表所在的數據庫名也可以保持一致(PS:在不同的實例里面),如下圖所示:

  PS:這種拆分主要針對于不同的業務對表的影響不大,表之間的業務關聯很弱或者基本上沒有業務關聯。拆分的好處是不相關的數據表拆分到不同的實例里面,對數據庫的容量擴展和性能提高的均衡來說,都是蠻有好處的。

  6.1.2縱向拆分

  把同一個實例上的不同的db庫拆分出來,放入單獨的不同實例中。這種拆分的適應場景和要求是db1和db2是沒有多少業務聯系的,類似6.1.2里面的A表和B表那樣。如果你用到了跨庫業務同時使用db1和db2的話,個人建議要重新考慮下業務,重新梳理下盡量把一個模塊的表放在一個庫里面,不要垮庫操作。

  這種庫縱向拆分里面,單獨的庫db1,表A和表B是強關聯的。如下圖所示:

  PS:看到很多使用mysql的人,總是把很多沒有業務關聯性的表放在一個庫里面,或者總是把很多個的db庫放在同一個實例里面,就像使用oracle那樣就一個instance的概念而已。Mysql的使用一大原則就是簡單,盡量單一,簡單的去使用mysql,庫要嚴格的分開;表沒有關系的,要嚴格拆分成庫。這樣的話擴展我們的業務就非常方便簡單了,只需要把業務模塊所在的db拆分出來,放入新的數據庫服務器上即可。

  6.1.3橫向縱向拆分

  有些剛起步的,開始為了快速出產品,就把所以的庫所有的表都放在一個實例上,等業務發展后,就面臨著數據拆分,這里就會把橫向縱向拆分結合起來,一起實現,如下圖所示:

  6.1.4業務拆分

  跟水平拆分有點類似,但是有不同的地方。比如一個供應商,可能整個網站上有10個供應商,一個網站上面每一個供應商都有一定的量,而且供應商之間的數據量規模都差不多的規模,那么這個時候就可以使用供應商的緯度來做拆分。

  比如usern庫中,a、b、c表都是強關聯的,都有完整的業務邏輯存在,這里只有用戶(供應商)緯度是沒有關聯的,那這個時候就可以把數據以用戶的緯度來進行拆分。

  就是用戶1和用戶2各自都有一套完整的業務邏輯,而且彼此之間不關聯,所以就可以把用戶1和用戶2數據拆分到不同的數據庫實例上面。目前很多互聯網公司或者游戲公司有很多業務都是以用戶緯度進行拆分的,比如qunaer、sohu game、sina等。

  (6.2) 水平拆分

  水平拆分相對要簡單一些,但是難度偏大,會導致分布式的情況、跨數據的情況、跨事務的情況可以分為大概三類,1是歷史數據和實時數據拆分,2是單庫多表拆分,3是多庫多表拆分。

  6.2.1實時數據歷史數據的拆分

  和歷史數據遷移是一樣的邏輯,就是要將online庫的數據遷移到listory的數據庫里面,對于實時的讀寫來說,數據是放在online db庫里面,對于時間較遠的數據來說,是放在歷史History DB記錄庫里面的,這里的歷史庫可以是mysql也可以是別的nosql庫等。

  6.2.2單庫多表拆分

  主要不是解決容量問題,而是解決性能問題而擴展的,加入當前實例只有一個DB,有一個大表,一個大表就把整個實例占滿了,這個時候就不能拆分db了,因為只有一個單表,這個時候我們就只能拆表了,拆表的方式主要是解決性能問題,因為單個表越大,對于mysql來說遍歷表的樹形結構遍歷數據會消耗更多的資源,有時候一個簡單的查詢就可能會引起整個db的很多葉子節點都要變動。表的insert、update、delete操作都會引起幾乎所有節點的變更,此時操作量會非常大,操作的時候讀寫性能都會很低,這個時候我們就可以考慮把大表拆分成多個小表,工作經歷中是按照hash取模打散成16個小表,也有按照id主鍵/50取模打散到50個小表當中,下圖實例是打散成2個小表。

  6.2.3多庫多表拆分

  在單庫多表的基礎上,如果單庫空間資源已經不足以提供業務支撐的話,可以考慮多庫多表的方式來做,解決了空間問題和性能問題,不過會有一個問題就是跨庫查詢操作,查詢就會有另外的策略,比如說加一個logic db層來實現跨庫跨實例自動查詢,簡單如下圖所示:

  6.2.4水平拆分小結

  水平拆分原則:

  -- a.盡量均勻的拆分維度。

  -- b.盡量避免跨庫事務。

  -- c.盡量避免跨庫查詢。

  設計:

  --a根據拆分維度,做mod進行數據表拆分,大部分都是取模的拆分機制,比如hash的16模原則等。

  --b根據數據容量,劃分數據庫拆分

  數據操作

  --a跨事務操作:分布式事務,通過預寫日志的方式來間接地實現。

  --b跨庫查詢:數據匯總or消息服務

  6.2.5案例說明

  u 案例:

  – 按照用戶維度進行拆分成64個分庫,1024個分表

  ?user_id%1024拆分到1024張分表中

  ? 每個分庫中存放1024/64張分表

  ? 取模的時候,可以用id的最后4位數據或者3位數字來取模就可以了。

  u 操作1:采用Configure DB

  – 拆分之后的查詢操作,做一個Configure DB,這個DB存放的是所有實例的庫表的映射關系,當我APP發來有一個請求查詢user1的數據,那么這個user1的數據是存放在上千個實例中的哪一個庫表呢?這個關聯信息就在Configure DB里面,APP先去Configure DB里面取得user1的關聯系信息(比如是存放在d_01庫上的t_0016表里面),然后APP根據關聯信息直接去查詢對應的d_01實例的t_0016表里面取得數據。

  u 操作2:采用Proxy

  – 拆分之后的查詢操作,做一個Proxy,APP訪問Proxy,Proxy根據訪問規則就可以直接路由到具體的db實例,生成新的sql去操作對應的db實例,然后通過Proxy協議進行操作把操作結果返回給APP。

  – 優勢是Proxy和db實例是在一個網段,這樣Proxy與db實例的操作的時間是非常短的。

  u 操作3:采用Data Engine

  – 拆分之后的查詢操作,有一個Data Engine Service,這個DES里面配置了所有數據庫實例的映射關系,需要在APP應用端安裝一個Agent,是同步邏輯,在JDBC層實現,DES可以實現讀寫分離,原理可以參考TDDL的實現。

  6.3集群管理

  縱向擴容:一個實例拆分成多個實例,縱向拆分比較簡單,修改的東西比較少,拆分的時候要通知到Configure DB或者DES,以免拆分之后查詢不到數據或者數據錄入不到新的db上面,如下圖所示:

  橫向擴容:比較復雜,在縱向擴容成2個庫的基礎之上,再一次對庫的表進行擴容,所以需要及時通知Configure DB和DES更細庫和表的路由連接信息。

11
1
 
 
 

文章列表

arrow
arrow
    全站熱搜

    大師兄 發表在 痞客邦 留言(0) 人氣()