基於MySQL的分散式資料庫TDSQL十年鍛造經驗分享

IT技術精選文摘發表於2018-06-13

640?wx_fmt=gif

騰訊資料庫技術發展之路

 

我來自騰訊TEG計費平臺部,一開始負責公司整個計費體系的儲存系統研發,現在主要負責TDSQL資料庫的研發。這是我們產品的幾個發展階段:

 

640?wx_fmt=png

 

我是2007年進入公司的,在此之前公司業務是一個野蠻生長階段,所以騰訊在資料庫的高可用、安全性方面考慮不多,到了2007年左右,業務經歷了第二次騰飛之前的一個平穩階段。

 

趁這個時機,團隊啟動了一個7*24高可用服務專案,目標就是保證計費等公司級別敏感業務高可用、核心資料的零流失、核心交易的零錯賬。這也是TDSQL的前身。

 

當時提出的解決方案更多還是在應用層解決,兩個DB之間資料如果不同步,則會在業務層鎖定,在出現故障時做主備切換,並讓沒有同步完資料的使用者交易不可用,其它使用者正常交易。按照CAP原理來理解就是:當故障(P)出現時,我們犧牲少數使用者的可用性(A),來保證100%的資料一致性(C)。

 

640?wx_fmt=png

 

到了2009年,考慮到這樣的高一致性解決方案易用性並不好,我們基於類似思路做了一套KeyValue系統,這比研發一套SQL系統要簡單很多,但依然有一個問題,KV系統不像SQL是標準化的東西,而且功能沒有SQL豐富,所以業務系統從SQL遷移到KV儲存,相當於儲存架構都改了。而我們線上業務是7*24服務的,所以改造及遷移工作量也比較大,推廣時間週期依然長。

 

640?wx_fmt=png 

在微眾成功落地投產後,我們希望我們的產品能為更多金融機構提供服務,所以在15年在騰訊雲上也釋出該產品,現在我們提供公有云PaaS服務,也提供私有云產品。

 

以上就是騰訊十年的資料庫技術發展之路,接下來是今天分享的重點,我會先從TDSQL核心特性開始,然後講講分散式水平擴充套件,最後分享在騰訊內部以及在部分客戶的部署實踐。

 

一、核心特性

 

開源MySQL的玩法跟Oracle的確實有很大的差距,Oracle看起來就是一個高富帥,而MySQL看起來怎麼也是一個經濟適用男。例如我們支撐的業務以及客戶,清一色的X86伺服器,網路也是普通的專線網路,還是很經濟實惠的。

 

所以有些傳統企業的客戶跟我們交流,問如果一臺機器掛了怎麼辦?誇張一點來說,就是這臺伺服器我們就不要了,但這在Oracle生態下是不可能發生的事情。所以基於機器壞了就不要了的理念,在容災方面上的設計就很不一樣了。

 

640?wx_fmt=png 

所以這也是我們為什麼將TDSQL在騰訊雲上開發出來的一個目的,就是希望TDSQL在近十年在騰訊海量資料運營下走過的彎路、以及解決的問題,在其它團隊不要再走一遍。

 

剛開始我們是定位金融這一塊,這當中有幾個問題必須要解決,一是高可用問題,二是資料可靠性、零丟失的問題。因為之前在行業內做分散式資料庫的人認為,MySQL體系做不到資料零丟失或者是主備之間資料的一致性,但其實這個東西是沒什麼問題的,是完全可以做到的,看看我們是怎麼做這個點的。

  

640?wx_fmt=jpeg

圖:TDSQL核心架構

 

這是TDSQL的架構,現在分散式架構一般分為三個核心模組,第一模組是資料節點(上圖右下角),通常是一主兩備的方式。上面的兩個模組組成排程系統,暫時是用ZooKeeper來做後設資料管理。第三模組是接入計算層,當發生故障時主備切換和對路由的更新都在閘道器層面上做。上面的排程系統還包括負責監測故障、故障切換的操作,以及分散式場景下的擴縮容任務管理等,此外包括一些複雜SQL的重新以及計算工作。這是大體的核心架構。

 

  1 複製

 

 主備資料複製方式

 

我們再從右下角的Set講起,通常是一主兩備的方式。現在MySQL是兩種複製模式,一種是非同步複製,一種是半同步複製。但我們實測時會發現問題,當主備之間同步超時時,半同步複製會由超時時間退化為非同步,這在金融場景下風險是比較大的。

 

按照CAP的原理,寧願犧牲一定的可用性也不願意把資料丟失,假裝置機異常了,退化為非同步了,主機繼續交易。

 

如果此時主機再發生故障,資料庫層面很可能出現資料丟失,一旦資料庫層面出現資料丟失,事後要去修復是非常困難的,所以這種時候我們是不讓它退化,繼續強同步(可能交易失敗),當然在具體實現時會做調整,根據業務特性去做配置設定是否退化非同步。兩個備機裡只一個備機成功出現故障的概率會低很多,但不是說完全不會出現故障,但概率會低很多。

 

640?wx_fmt=jpeg

 

 強同步更新流程

 

640?wx_fmt=jpeg

 

此外,在實際測試時做同城跨資料中心,這時的效能損耗會非常大,在MySQL 5.6版本效能損耗要降到原來的十分之一左右。現在5.7版本,在同步這裡官方做了一些非同步化處理,效能下降問題已經好很多了,但依然會有效能損耗。所以在複製這塊,我們主要是去解決這兩個問題。剛才講的一主兩備,兩個備機是都做強同步複製的。

 

 半同步複製的不足

 

640?wx_fmt=jpeg

 

這是我們自己實測的結果,TPS下降非常快,所以我們做了兩個非同步化處理。

 

640?wx_fmt=jpeg

 

經過這些非同步化改造,在效能方面我們目前可以做到同城跨資料中心,5毫秒以內的延遲的情況下,能夠保證資料強同步和非同步之間TPS不會下降,網路單筆時耗可能會增加,但增加網路延遲這是很正常的一種情況。也正是因為有了強同步TPS不會下降的問題,所以我們也敢在業務大規模推行同城三中心架構,這個架構我在下面會再具體展開講。

 

640?wx_fmt=jpeg

 

 SET結構

 

640?wx_fmt=jpeg

 

一般在同城三個資料中心之間一主兩備,這三個資料節點放在三個資料中心。在這種情況下,做強同步任何一個資料中心異常都能夠自動地切換過去,切換到另外的資料中心。所以這種可用度是非常高的。現在能夠承諾的是同城做強同步的話可以到RTO 40秒,RPO為0。

 

在跨城通常還是做非同步的同步,這裡如果需要強行切換到跨城異地的備份中心,會有資料丟失的風險。當然這也是概率的問題,我們認為只有像在整個深圳三個資料中心全都掛掉了,或地震級別的災難才會出現到這種情況,所以如果真要做跨城切換的情況下,有少量的資料丟失是可以接受的。

 

640?wx_fmt=png 

剛才我們在同城跨資料中心切換承諾的是40秒,為什麼說是40秒呢?我們是分成了兩部分,第一部分20秒是故障檢測階段,第二部分是服務恢復階段,服務恢復階段主要是根據Raft協議選主、等待資料回放完成等工作,我們保守一點承諾是20秒完成,不過在我們實際運營環境中,通常3-4秒就可以完成這些工作。相對來說,服務恢復階段在業界是比較成熟的,理論也比較完備。

 

在這裡我想重點要提一下故障檢測階段。其實故障檢測是非常難的事情,首先我們都是基於X86的伺服器,雖然現在伺服器硬體一年比一年往上翻,效能越來越好,但實際上依然會有很多業務在上線時設計得不合理,每個使用者來的時候都會做全表掃描,有時你根本防不勝防,如果稍微沒注意放過去了就一下子把系統給沖垮了,整個資料庫節點表現就是不可用了。

 

那麼,在資源被消耗光的情況下要不要做切換?在業務看來,資料庫基本上是不可用的,理論上是需要切換的,但是你切換後,發現沒啥用,SQL請求裡面又把新主機壓垮了。

 

此外,我們現在普遍使用的SSD盤,SSD有一個問題是壽命的問題,壞也不是一下子突然壞了,這中間有一條曲線,IOPS和磁碟響應時間有一個逐漸變差的過程。那這種情況下怎麼切,在什麼時間點切換呢?

 

在故障檢測這個點上,目前來看很難有統一的一個理論說怎麼發現故障、怎麼去切換,這是非常難的事情,更多還是經驗方面的積累,我們秉承的原則還是:切換後,如果系統可用效能提升,才切,否則免切。這確實可以避免很多沒有意義的切換。

 

  2 主備高一致性保障

 

 資料高可用性的保障機制(恢復)

 

故障檢測時間是可以配置的,我們配置3秒鐘一次監測,大概要連續6次出現異常情況才會去觸發切換,而且連續6次的情況下還要匹配到自己內部的邏輯——是不是切換過去就能夠解決問題,如果像剛才那種因為業務使用不當導致了系統資料庫不用的話切過去也沒什麼用,在這種情況下不會做無謂的切換。

 

如果有時候系統出了問題可能會引發連續的切換,連續切換對系統也沒什麼好處,比如說我們切換了一次後,配置在未來的一段時間不會做切換,用這樣的邏輯做判斷。

 

640?wx_fmt=jpeg

 

這裡是我們在服務恢復階段的示例演示。剛開始A是主機,B、C作為備機,而且B稍微延遲一些,C備機資料更新一點,此時a+3這個事務,依舊是未提交成功的,此時如果A主機故障了,那麼排程系統會選擇C作為新主機,B作為C的備機,組成一主一備的Set。

 

此時,我們會優先考慮,A節點是否能快速恢復(如MySQL bug,或者網路閃斷等),如果能,則對a+3事務Rollback後,作為備機,繼續提供服務;如果A節點不能快速恢復(如磁碟故障,伺服器故障),則需要重新找一臺伺服器,通過物理備份+追Binlog的方式,快速構建一個新備機,儘可能地快速恢復為一主兩備的三節點Set提供服務。

 

 高一致性容災:如何保證沒有髒資料

 

640?wx_fmt=jpeg

 

整個切換流程是一個嚴謹的操作,每個操作是有順序的,否則可能會出現雙寫的情況,這都是靠切換流程來保障。

 

通常同城三中心架構,每個資料中心都是對等平等的。一旦因為故障,導致主備發生切換,除非再次發生故障,我們不會主動切換回來,這是同城三中心高度對等架構的好處。

 

任何一箇中心的節點都可以提供主服務,這種更加標準化的部署,運維可以做到自動化操作,對運維管理的複雜程度要稍微低些。

 

 

 可靠性保障體系

 

640?wx_fmt=jpeg

 

這是冷備系統,每天會做全量的映象,並實時做Binlog的增量備份,這些都會經過壓縮後儲存在分散式檔案系統上,以便客戶可以恢復到歷史某一個時刻的資料點。目前我們在公有云上預設提供30天的任意時間點回檔。

 

為什麼需要每天做映象呢?還是為了恢復的速度問題。比如說遊戲出現了重大Bug需要快速回檔,第二是DBA誤操作刪除資料了,這些情況都需要從冷備恢復。當然,每天一個映象在一些情況下恢復時間也會比較長,假設每天凌晨4點鐘做備份,但剛好在備份前一兩個小時資料被刪掉了,那這種恢復就需要用前一天凌晨4點的映象資料,外加追一天的Binlog日誌恢復,這個時間是比較長的。

 

640?wx_fmt=png 

  3 效能

 

 效能指標:單節點

 

效能絕對數值本身沒什麼太大意義,不同的廠商可以用不同測試場景,釋出對自己產品有利的資料。這裡我想補充一點就是關於硬體。

 

硬體發展其實很快。大概兩年前,我們自己內部用一個代號為Z3的伺服器,大概1.3T SSD FusionIO卡。到了2017年年初,我們現在已經開始用上了TS85伺服器,這種機型已經相當厲害了,是24個物理核,512G記憶體,4塊1.8T NVME SSD卡,我們把它做成RAID 0,在資料庫裡很少有人說資料盤是用RAID 0的,但在我們架構裡通常都是RAID 0。前提就是資料三副本,我們系統的可靠性及可用性不依賴單個副本,一個副本故障了就重新構建一個副本。

 

640?wx_fmt=jpeg

 

 讀寫分離

 

  • 基於資料庫賬號的讀寫分離
     

     

640?wx_fmt=jpeg

 

  • 基於Hint的讀寫分離

 

640?wx_fmt=png

 

二、分散式叢集

 

  1 水平擴充套件性

 

640?wx_fmt=jpeg

 

下面講一下分散式實踐。TDSQL一開始是定位在騰訊內部做計費、金融支付這類場景,是常見的OLTP場景。考慮到OLTP場景,一個系統的實時交易資料量並不會超級大,所以我們採用預分片的策略,一開始把資料幫你做好邏輯分片,例如設定為64個分片或者是128個分片,當然要做到1024個分片甚至更多都沒什麼問題,但通常來說用不了那麼多分片。

 

640?wx_fmt=png 

此外,有些表的資料沒有必要做分散式,可能是配置表,所以會有廣播小表或者是NoSharding表,這樣做交易事務會非常方便。

 

 三種資料Sharding方式

 

640?wx_fmt=jpeg

 

 

 SQL支援

 

640?wx_fmt=jpeg

 

MySQL本身在複雜SQL場景下處理會比Oracle差一些,尤其是在資料分析方面。但通常來說,標準的聚合函式都是沒什麼問題,我們現在也支援基於兩階段提交的分散式事務,但Join是有不同的。。

 

640?wx_fmt=png 

所以我們更加偏向於保守一些,而且儘量地把錯誤在前面開發測試階段發現,而不是到生產的時候才處理,當然我們也在逐步放開一些限制,在系統層面去做好控制、確保安全。

 

  2 分散式事務

 

640?wx_fmt=jpeg

 

分散式事務最核心的點是異常處理。我們的分散式事務是基於兩階段提交的。做分散式系統最複雜的一個問題就是當出現網路故障、網路超時的情況時如何處理。

 

任何一筆網路請求可能有三種結果:正確、失敗、超時。對於超時怎麼處理是最關鍵的,所以我們有一套測試環境,專門隨機模擬各種異常,包括網路、伺服器各種情況下,用於驗證我們分散式事務機制的健壯性。

 

第二點是分散式事務的死鎖檢測。我們在MySQL的鎖資訊裡面增加上了分散式事務ID,在出現一定超時時間後,會主動去測試整個叢集裡面是否有多個事務之間佔用的鎖構成了環,也就是死鎖,一旦出現死鎖,我們會根據我們的策略,Kill掉某個事務,確保其它事務正常執行。

 

640?wx_fmt=jpeg

 

 分散式事務效能對比

 

640?wx_fmt=jpeg

 

分散式事務不可避免是對效能的對比,目前我們的效能是損失大概是在30%左右,這是一個相當不錯的效能了。而且TDSQL也是通過TPCC測試驗證的。

 

 

 兩種模式

 

我們也提供了兩個版本,一個是分散式版本,一個是No-sharding版本,如前面提到的在分散式版本里SQL會有一些限制,No-sharding提供的是完全SQL相容的高可用方案。

 

640?wx_fmt=jpeg

 

 

 TDSQL整體檢視

 

前面也提到了MySQL和Oracle對比生態系統不夠完善,Oracle的配套工具相當完善,此外就像Oracle有很多專家,客戶出了什麼問題,ITPUB發個帖子說有沒有專家過來幫我解決問題,就會有很多專家過來解決,在MySQL體系下還沒有這樣的方法去處理。

 

確實周邊配套、內部監控的處理包括本身的優化沒有提供很好的工具,所以在這方面我們也投入了很大的精力。如果做產品化的話,這是非常重要的過程,無論是公有云還是私有云,目前提供給騰訊內部的其它業務也是雲方式,整個這一套東西部署進去就能實現DBaaS服務,你可以直接購買TDSQL的例項應用。

 

640?wx_fmt=jpeg

 

三、部署實踐

最後講一下我們經常用的部署實踐。

 

  1 同城主從雙中心

 

640?wx_fmt=jpeg

 

同城雙中心沒有什麼很大的借鑑,這是微眾銀行最開始的架構。微眾銀行是全國第一家網際網路新籌民營銀行,所以是從零開始建構的,最開始的時候同城只有兩個資料中心,最大的問題是出了故障時彼此都不知道到底是誰出了故障。

 

640?wx_fmt=png 

但今年微眾銀行已經徹底換成同城三中心架構,任一中心都可以切換,資料的架構看起來比較簡單,可用性會好很多。這確實對成本的要求比較高,建設一個符合監管規範的金融級資料中心成本相當高,所以很多客戶不願意為了你再去搞多一個資料中心,只有微眾是做類似金融科技才會搞三中心的架構。

 

微眾當時評估成本,當它的賬戶量達到2000萬以上時,單使用者成本能夠達到原來傳統IOE架構的十分之一左右,越到後面使用者量越增加就越划得來。

 

  2 兩地三中心

 

640?wx_fmt=jpeg

 

考慮到客戶當前的資料中心及成本情況,更多的是客戶會做兩地三中心的架構,比如說深圳兩個中心一主兩備,通常在主資料中心會加一個備機,這個備機是為了做非同步複製。

 

因為非同步複製跟強同步複製本身上來說沒有區別,所以非同步大部分情況下資料也是最新的,如果真的主機出現故障要切換時會去優先選擇本地備機,避免跨資料中心切換,如果資料確實跟其它的強同步節點最新的資料是一致的,當然沒有非同步節點也是沒有什麼問題的。

 

  3 兩地四中心(自動化切換的強同步架構)

 

640?wx_fmt=jpeg

 

在騰訊內部通常就是這種部署架構,基本上能夠滿足大部分客戶的需求。同城三個資料中心對等,任何資料中心及故障都能40秒內切換,資料零丟失,效能也穩定可靠,所以對業務來說是非常友好的。

公眾號推薦:

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

相關文章