分布式MySQL数据库TDSQL架构分析
分布式MySQL數據庫TDSQL架構分析
發表于11小時前| 次閱讀| 來源程序員電子刊| 0 條評論| 作者雷海林
MySQLTDSQL騰訊架構 width="22" height="16" src="http://hits.sinajs.cn/A1/weiboshare.html?url=http%3A%2F%2Fwww.csdn.net%2Farticle%2F2015-06-02%2F2824824&type=3&count=&appkey=&title=%E8%85%BE%E8%AE%AF%E8%AE%A1%E8%B4%B9%E5%B9%B3%E5%8F%B0%E9%83%A8%E4%B8%BA%E4%BA%86%E8%A7%A3%E5%86%B3%E5%9F%BA%E4%BA%8E%E5%86%85%E5%AD%98%E7%9A%84NoSQL%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88HOLD%E5%B9%B3%E5%8F%B0%E5%9C%A8%E5%BA%94%E5%AF%B9%E5%A4%9A%E7%A7%8D%E4%B8%9A%E5%8A%A1%E6%8E%A5%E5%85%A5%E6%97%B6%E7%9A%84%E4%B8%8D%E8%B6%B3%EF%BC%8C%E7%BB%93%E5%90%88%E5%9B%A2%E9%98%9F%E5%9C%A8MySQL%E9%A2%86%E5%9F%9F%E5%A4%9A%E5%B9%B4%E5%BA%94%E7%94%A8%E5%92%8C%E4%BC%98%E5%8C%96%E7%BB%8F%E9%AA%8C%EF%BC%8C%E6%9C%80%E7%BB%88%E5%9C%A8MySQL%E5%AD%98%E5%82%A8%E5%BC%95%E6%93%8E%E5%9F%BA%E7%A1%80%E4%B8%8A%EF%BC%8C%E6%89%93%E9%80%A0%E4%B8%80%E5%A5%97%E5%88%86%E5%B8%83%E5%BC%8FSQL%E7%B3%BB%E7%BB%9FTDSQL%E3%80%82%E6%9C%AC%E6%96%87%E6%98%AF%E5%AF%B9%E8%AF%A5%E7%B3%BB%E7%BB%9F%E6%9E%B6%E6%9E%84%E5%88%86%E6%9E%90%E3%80%82&pic=&ralateUid=&language=zh_cn&rnd=1433246451075" frameborder="0" scrolling="no" allowtransparency="true">摘要:騰訊計費平臺部為了解決基于內存的NoSQL解決方案HOLD平臺在應對多種業務接入時的不足,結合團隊在MySQL領域多年應用和優化經驗,最終在MySQL存儲引擎基礎上,打造一套分布式SQL系統TDSQL。本文是對該系統架構分析。
騰訊計費平臺部托管著公司90%以上的虛擬賬戶,如QB、Q點、包月服務、游戲的二級賬戶等,為了保證能順暢支撐公司各大業務的實時在線交易,并且在各種災難場景下數據是一致并且可用的,對系統的可用性、一致性切換要求非常高,因此計費團隊歷來都非常重視高一致性存儲系統的建設。
到目前為止,計費高一致性存儲層的解決方案大致經過了3個階段,本文將分享最新的基于MySQL的分布式解決方案。
隨著業務的發展,基于內存的NoSQL解決方案HOLD平臺在高峰期一天支撐3000億讀寫,證明了分布式Cache的巨大價值;但隨著各種業務的接入,NoSQL方案的不足也逐步顯現出來了,如下所示。
基于上面的分析,結合我們在MySQL領域多年的應用和優化經驗,最終決定在MySQL存儲引擎基礎之上,打造一套分布式的SQL系統。
整體架構
針對上面的需求,TDSQL最終的結構如圖1所示(與當前大部分中心化的分布式系統類似)。
圖1 TDSQL架構
系統由三個模塊組成:Scheduler、Agent、網關,三個模塊的交互都是通過ZooKeeper完成,極大簡化了各個節點之間的通信機制,相對于第二代HOLD的開發簡單了很多。
Scheduler作為集群的管理調度中心,主要功能包括:
Agent模塊負責監控本機MySQL實例的運行情況,主要功能包括:
網關基于MySQL Proxy開發,在網絡層、連接管理、SQL解析、路由等方面做了大量優化,主要特點和功能如下:
自動擴容機制
目前,針對MySQL的擴容,一般有下面兩種策略。
通過上述2種擴容方法的比較,為了應對海量擴展的需求,應該是重點選用水平擴容的方法。但水平擴容的實現一般對業務是有感知的,比如采用什么規則來拆表,拆開的表放到哪些節點,如果某個子表還有瓶頸應該怎么擴容,擴容是否還需要業務配合等等這些事情如果全部交給業務會比較繁瑣,因此這些需求應該盡量全部交給TDSQL自身來完成,對業務完全透明。
分表邏輯
在TDSQL中,每個表(邏輯表)可能會拆分成多個子表(建表的時候通過在建表語句中嵌入注釋的方式提供一個shard字段名,最多會拆分出1W個子表),每個子表在MySQL上都是一個真實的物理表,這里稱為一個shard,因此一張表的數據可能會按這樣的方式分布在多個Set中,如圖2所示
圖2 TDSQL的邏輯表
每個SQL請求到達網關之后,網關會做詞法和語法解析,重點會解析出shard字段,如果帶了shard字段就可以直接查詢路由表并發送到某個具體的set中。計費的OLTP類業務99%的請求都會帶上shard字段;如果某筆請求沒有shard字段,查詢路由之后會將請求發送到所有的shard對應的set中,并對所有返回的結果做一些聚合運算。
擴容流程
上面描述了shard的方式,但是這樣的shard結構不是固定不變的,當Scheduler檢測到某個set,某個表的CPU、磁盤超過閾值之后就會啟動擴容流程。
這里描述下具體的擴容流程。
擴容過程中一般都要盡量避免影響業務,目前來看存在2種比較成熟的策略。
策略1先切后搬:先修改路由,將需要遷走的數據的請求直接發送到新set,在新set交易過程中如發現本地的數據不存在,則去原set拉取數據,然后再通過一些離線的策略將要遷移的數據全量再搬遷一次,HOID平臺就是采用這樣的策略。
策略2先搬后切:讓請求繼續在原set交易,擴容程序首先記錄一個binlog位置點,并將源set中符合遷移條件的數據全部遷移出去,最后再將搬遷過程中新增的binlog追完,最后修改路由規則,將請求發送到新set。
綜合來看,策略1最大的優點是假如是因為壓力大做的遷移,可能很快就能將部分請求發送新set了,實現對原set的壓力分擔;策略2實現上在最后的追路由階段需要更多的精細化控制,實現會稍微復雜點,但策略2有個非常大的好處就是擴容過程中回滾非常方便,如有異常直接干掉擴容任務即可。
對于TDSQL這類數據庫業務系統來說,策略1實現會非常麻煩,因為請求到達新set之后可能需要去源set拉取數據,這個需要對MySQL本身進行修改;另外假如一個批量更新的update操作,可能要往新老set都發送一次請求,比較復雜,所以最終選擇了策略2。策略2會有更大的通用性,開發模式基本上可以統一到所有類似的系統。
下面描述采用策略2具體的擴容流程。假如要將Set1中的t_shard_1的數據遷移一半到Set4中的t_shard_4(1667-3333)。
圖3 策略2的擴容流程
Scheduler首先在Set4中創建好表t_shard_4。
后將擴容任務下發到Set1中的agent模塊,agent檢測到擴容任務之后會采用mysqldump+where條件的方式將t_shard_1中shard號段為1667-3333的記錄導出來并通過管道用并行的方式插入到Set4(不會在本地存文件,避免引起過多的IO),用mysqldump導出鏡像的時候會有一個binlog位置。
從mysqldump記錄的binlog位置開始讀取binlog并插入到到Set4,追到所有binlog文件末尾的時候(這需要一個循環,每次循環記錄從開始追binlog截止到追到文件結尾消耗的時間,必須保證追單次循環要在幾秒之內完成,避免遺留的binlog太多導致最后一次追binlog消耗太多的時間,從而影響業務過久),對原來的表t_shard_1重命名t_shard_5,此時針對這個表不會再有新請求,若還有請求過來都會失敗,然后再追一次binlog到文件結尾(因為上面的循環保證了追binlog不會太耗時間了,所以此次會快速完成),然后上報狀態到ZooKeeper,表明擴容任務完成。
Scheduler收到擴容完成的信息之后會修改路由表,最后由網關拉取到新路由完成整體的擴容;從表重命名開始到網關拉取到新路由,這段時間這個原始shard不可用,從我們測試結果來看這個不可用的時間是200毫秒左右;如果某個網關異常,拉取不到新路由,繼續訪問老表t_shard_1會一直失敗,這樣就可以保證數據的一致性。
容災機制
對于TDSQL來說,我們希望容災做到自動切換,自動恢復,主備一致性(保證業務提交的事務在切換過程不丟失),跨IDC容災。
【MySQL異步復制】
在MySQL發展的早期,就提供了異步復制的技術,只要寫的壓力不是特別大,在網絡條件較好的情況下,發生主備切換基本上能將影響控制到秒級別,因此吸引了很多開發者的關注和使用。但這套方案提供的一致性保證,對于計費或者金融行業是不夠的。
圖4是異步復制的大致流程,很顯然主機提交了binlog就會返回給業務成功,沒有保證binlog同步到了備機,這樣在切換的瞬間很有可能丟失這部分事務。
圖4 異步復制
【MySQL半同步復制】
到了MySQL 5.5版本的時候,Google提供了一個半同步半異步的插件,確保必須收到一個備機的應答才讓事務在主機中提交;當備機應答超時的情況下,強同步就會自動退化成異步模式(這也是半同步半異步名字的由來)。
圖5 半同步復制
這套方案相對異步復制,在數據的可靠性方面確實好很多,在主機本身故障的情況下,基本能保證不丟失事務(因為最后一個事務,至少有一個備機上存在),但一旦退化成異步復制就回到過去了。TDSQL沒直接采用這套方案,是因為:在主備跨IDC(ping延遲2-3毫秒)時性能非常很低。
【Cluster方案】
除了上面的方案外,開源社區還有三個Cluster解決方案,分別是Oracle的NDB引擎、Percona XtraDB Cluster和MariaDB Galera Cluster,從公開資料的性能對比上來看,后2者在性能和系統靈活性等方面都強于NDB(同時采用NDB意味著也放棄了InnoDB引擎,NDB主要是基于全內存的,并且需要高速網絡環境支持,所以不考慮了);Percona XtraDB Cluster和MariaDB Galera Cluster強同步機制的底層都是采用Galera這套強同步的架構。MariaDB Galera Cluster具有如下非常吸引人的特性:
目前來看,Galera是一套相當完美的方案。但是,在跨IDC的性能測試中,其性能下降比較大,另外,實現方案也比較復雜,目前對它的代碼理解還不夠透徹,所以暫時沒有在計費領域大范圍推廣使用。但我相信這個方向是對的,有吸引力的,隨著后續Galera越來越完善,我們對它研究得越透徹,也許有一天會采用這套方案。
【性能測試和分析】
上面的三種復制模式對比測試,數據如圖6所示。
圖6 三種復制模式的對比
從圖6的數據可以看出,半同步和Galera模式對性能的損耗還是非常大的,Galera的毛刺尤其嚴重,所以在跨IDC環境下還不是適合計費這樣對延遲要求非常低的場景。
為什么性能損耗會這么嚴重呢?這個看明白MySQL的網絡模型就清楚了。外界可查的MySQL最早的公開版本應該是1996年的3.1.1.1版本,這么多年來,網絡模型基本上變化不大,與Apache有點類似,有點區別的是MySQL采用的是每個連接一個線程的模型,這套模型最大的好處就是開發特別簡單,線程內部都是同步調用,只要不訪問外部接口,支撐每秒幾百上千的請求量也基本夠用,因為大部分情況下IO是瓶頸。不過隨著當前硬件的發展,尤其是SSD、FusionIO的出現,IOPS從200+/s進化到幾十萬甚至百萬次/s,IO基本上不再是瓶頸,若再采用這套模型并采用阻塞的方式調用延遲較大的外部接口,則CPU都會阻塞在等網絡應答上了,性能自然上不去。
不過在MySQL5.6企業版和MariaDB、Percona中都引入了線程池,使得網絡模型靈活了很多,圖7是簡化后的對比模型。
圖7 簡化的對比模型
TDSQL采用的強同步方案
從上面的分析可知,半同步半異步是比較輕量級的高一致性容災方案,但受限于已有的同步網絡模型,CPU利用不起來。我們如果在線程池基礎之上做一些修改,參考半同步的思路就可以實現一個高性能的強同步方案。
目前的做法是采用與Linux內核處理中斷的思路:將上面線程池模型的第三個環節(執行SQL的邏輯)拆成兩個部分:
改造后性能提升明顯,如圖8所示。
圖8 改造后的性能
數據高可用性保障機制
除上述強同步機制外,TDSQL還做了以下增強,以提升數據的可用性。
接下來的方向
總結
以上是生活随笔為你收集整理的分布式MySQL数据库TDSQL架构分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 人机交互、大数据分析:移动互联网的技术创
- 下一篇: OpenStack行业实践和发展趋势