最近與同行科技交流,常常被問到分庫分表與分佈式數據庫如何選擇,網上也有不少關於中間件+傳統關係數據庫(分庫分表)與NewSQL分佈式數據庫的文章,但有些觀點與判斷是我以爲是偏激的,脫離環境去評價方案好壞其實有失公允。html
本文經過對兩種模式關鍵特性實現原理對比,但願能夠儘量客觀、中立的闡明各自真實的優缺點以及適用場景。算法
首先關於「中間件+關係數據庫分庫分表」算不算NewSQL分佈式數據庫問題,國外有篇論文pavlo-newsql-sigmodrec,若是根據該文中的分類,Spanner、TiDB、OB算是第一種新架構型,Sharding-Sphere、Mycat、DRDS等中間件方案算是第二種(文中還有第三種雲數據庫,本文暫不詳細介紹)。
基於中間件(包括SDK和Proxy兩種形式)+傳統關係數據庫(分庫分表)模式是否是分佈式架構?我以爲是的,由於存儲確實也分佈式了,也能實現橫向擴展。可是不是"僞"分佈式數據庫?從架構先進性來看,這麼說也有必定道理。"僞"主要體如今中間件層與底層DB重複的SQL解析與執行計劃生成、存儲引擎基於B+Tree等,這在分佈式數據庫架構中實際上冗餘低效的。爲了不引發真僞分佈式數據庫的口水戰,本文中NewSQL數據庫特指這種新架構NewSQL數據庫。sql
NewSQL數據庫相比中間件+分庫分表的先進在哪兒?畫一個簡單的架構對比圖:數據庫
這些大多也是NewSQL數據庫產品主要宣傳的點,不過這些看起來很美好的功能是否真的如此?接下來針對以上幾點分別闡述下的個人理解。緩存
這是把雙刃劍。微信
想一想更早些出現的NoSQL數據庫爲什麼不支持分佈式事務(最新版的mongoDB等也開始支持了),是缺少理論與實踐支撐嗎?並非,緣由是CAP定理依然是分佈式數據庫頭上的頸箍咒,在保證強一致的同時必然會犧牲可用性A或分區容忍性P。爲何大部分NoSQL不提供分佈式事務?網絡
那麼NewSQL數據庫突破CAP定理限制了嗎?並無。NewSQL數據庫的鼻主Google Spanner(目前絕大部分分佈式數據庫都是按照Spanner架構設計的)提供了一致性和大於5個9的可用性,宣稱是一個「其實是CA」的,其真正的含義是系統處於 CA 狀態的機率很是高,因爲網絡分區致使的服務停用的機率很是小,究其真正緣由是其打造私有全球網保證了不會出現網絡中斷引起的網絡分區,另外就是其高效的運維隊伍,這也是cloud spanner的賣點。詳細可見CAP提出者Eric Brewer寫的《Spanner, TrueTime 和CAP理論》。數據結構
推薦一篇關於分佈式系統有趣的文章,站在巨人的分佈式肩膀上,其中提到:分佈式系統中,您能夠知道工做在哪裏,或者您能夠知道工做什麼時候完成,但您沒法同時瞭解二者;兩階段協議本質上是反可用性協議。架構
兩階段提交協議是否嚴格支持ACID,各類異常場景是否是均可以覆蓋?
2PC在commit階段發送異常,其實跟最大努力一階段提交相似也會有部分可見問題,嚴格講一段時間內並不能保證A原子性和C一致性(待故障恢復後recovery機制能夠保證最終的A和C)。完備的分佈式事務支持並非一件簡單的事情,須要能夠應對網絡以及各類硬件包括網卡、磁盤、CPU、內存、電源等各種異常,經過嚴格的測試。以前跟某友商交流,他們甚至說目前已知的NewSQL在分佈式事務支持上都是不完整的,他們都有案例跑不過,圈內人士這麼篤定,也說明了分佈式事務的支持完整程度實際上是層次不齊的。併發
但分佈式事務又是這些NewSQL數據庫的一個很是重要的底層機制,跨資源的DML、DDL等都依賴其實現,若是這塊的性能、完備性打折扣,上層跨分片SQL執行的正確性會受到很大影響。
傳統關係數據庫也支持分佈式事務XA,但爲什麼不多有高併發場景下用呢? 由於XA的基礎兩階段提交協議存在網絡開銷大,阻塞時間長、死鎖等問題,這也致使了其實際上不多大規模用在基於傳統關係數據庫的OLTP系統中。
NewSQL數據庫的分佈式事務實現也仍然多基於兩階段提交協議,例如google percolator分佈式事務模型,
採用原子鐘+MVCC+ Snapshot Isolation(SI),這種方式經過TSO(Timestamp Oracle)保證了全局一致性,經過MVCC避免了鎖,另外經過primary lock和secondary lock將提交的一部分轉爲異步,相比XA確實提升了分佈式事務的性能。
SI是樂觀鎖,在熱點數據場景,可能會大量的提交失敗。另外SI的隔離級別與RR並不是徹底相同,它不會有幻想讀,但會有寫傾斜。
但無論如何優化,相比於1PC,2PC多出來的GID獲取、網絡開銷、prepare日誌持久化仍是會帶來很大的性能損失,尤爲是跨節點的數量比較多時會更加顯著,例如在銀行場景作個批量扣款,一個文件可能上W個帳戶,這樣的場景不管怎麼作仍是吞吐都不會很高。
Spanner給出的分佈式事務測試數據
雖然NewSQL分佈式數據庫產品都宣傳完備支持分佈式事務,但這並非說應用能夠徹底不用關心數據拆分,這些數據庫的最佳實踐中仍然會寫到,應用的大部分場景儘量避免分佈式事務。
既然強一致事務付出的性能代價太大,咱們能夠反思下是否真的須要這種強一致的分佈式事務?尤爲是在作微服務拆分後,不少系統也不太可能放在一個統一的數據庫中。嘗試將一致性要求弱化,即是柔性事務,放棄ACID(Atomicity,Consistency, Isolation, Durability),轉投BASE(Basically Available,Soft state,Eventually consistent),例如Saga、TCC、可靠消息保證最終一致等模型,對於大規模高併發OLTP場景,我我的更建議使用柔性事務而非強一致的分佈式事務。關於柔性事務,筆者以前也寫過一個技術組件,最近幾年也涌現出了一些新的模型與框架(例如阿里剛開源的Fescar),限於篇幅再也不贅述,有空再單獨寫篇文章。
解決分佈式事務是否只能用兩階段提交協議?
oceanbase1.0中經過updateserver避免分佈式事務的思路頗有啓發性 ,不過2.0版後也變成了2PC。
業界分佈式事務也並不是只有兩階段提交這一解,也有其它方案its-time-to-move-on-from-two-phase(若是打不開,國內有翻譯版https://www.jdon.com/51588)
主從模式並非最優的方式,就算是半同步複製,在極端狀況下(半同步轉異步)也存在丟數問題,目前業界公認更好的方案是基於paxos分佈式一致性協議或者其它類paxos如raft方式,Google Spanner、TiDB、cockcoachDB、OB都採用了這種方式,基於Paxos協議的多副本存儲,遵循過半寫原則,支持自動選主,解決了數據的高可靠,縮短了failover時間,提升了可用性,特別是減小了運維的工做量,這種方案技術上已經很成熟,也是NewSQL數據庫底層的標配。
固然這種方式其實也能夠用在傳統關係數據庫,阿里、微信團隊等也有將MySQL存儲改造支持paxos多副本的,MySQL也推出了官方版MySQL Group Cluster,預計不遠的將來主從模式可能就成爲歷史了。
分佈式一致性算法自己並不難,但具體在工程實踐時,須要考慮不少異常並作不少優化,實現一個生產級可靠成熟的一致性協議並不容易。例如實際使用時必須轉化實現爲multi-paxos或multi-raft,須要經過batch、異步等方式減小網絡、磁盤IO等開銷。
須要注意的是不少NewSQL數據庫廠商宣傳基於paxos或raft協議能夠實現【異地多活】,這個其實是有前提的,那就是異地之間網絡延遲不能過高。以銀行「兩地三中心」爲例,異地之間多相隔數千裏,延時達到數十毫秒,若是要多活,那便需異地副本也參與數據庫日誌過半確認,這樣高的延時幾乎沒有OLTP系統能夠接受的。
數據庫層面作異地多活是個美好的願景,但距離致使的延時目前並無好的方案。以前跟螞蟻團隊交流,螞蟻異地多活的方案是在應用層經過MQ同步雙寫交易信息,異地DC將交易信息保存在分佈式緩存中,一旦發生異地切換,數據庫同步中間件會告之數據延遲時間,應用從緩存中讀取交易信息,將這段時間內涉及到的業務對象例如用戶、帳戶進行黑名單管理,等數據同步追上以後再將這些業務對象從黑名單中剔除。因爲雙寫的不是全部數據庫操做日誌而只是交易信息,數據延遲隻影響一段時間內數據,這是目前我以爲比較靠譜的異地度多活方案。
另外有些系統進行了單元化改造,這在paxos選主時也要結合考慮進去,這也是目前不少NewSQL數據庫欠缺的功能。
paxos算法解決了高可用、高可靠問題,並無解決Scale橫向擴展的問題,因此分片是必須支持的。NewSQL數據庫都是天生內置分片機制的,並且會根據每一個分片的數據負載(磁盤使用率、寫入速度等)自動識別熱點,而後進行分片的分裂、數據遷移、合併,這些過程應用是無感知的,這省去了DBA的不少運維工做量。以TiDB爲例,它將數據切成region,若是region到64M時,數據自動進行遷移。
分庫分表模式下須要應用設計之初就要明確各表的拆分鍵、拆分方式(range、取模、一致性哈希或者自定義路由表)、路由規則、拆分庫表數量、擴容方式等。相比NewSQL數據庫,這種模式給應用帶來了很大侵入和複雜度,這對大多數系統來講也是一大挑戰。
分庫分表模式也能作到在線擴容,基本思路是經過異步複製先追加數據,而後設置只讀完成路由切換,最後放開寫操做,固然這些須要中間件與數據庫端配合一塊兒才能完成。
這裏有個問題是NewSQL數據庫統一的內置分片策略(例如tidb基於range)可能並非最高效的,由於與領域模型中的劃分要素並不一致,這致使的後果是不少交易會產生分佈式事務。舉個例子,銀行核心業務系統是以客戶爲維度,也就是說客戶表、該客戶的帳戶表、流水錶在絕大部分場景下是一塊兒寫的,但若是按照各表主鍵range進行分片,這個交易並不能在一個分片上完成,這在高頻OLTP系統中會帶來性能問題。
常見的單分片SQL,這二者都能很好支持。NewSQL數據庫因爲定位與目標是一個通用的數據庫,因此支持的SQL會更完整,包括跨分片的join、聚合等複雜SQL。中間件模式多面嚮應用需求設計,不過大部分也支持帶拆分鍵SQL、庫表遍歷、單庫join、聚合、排序、分頁等。但對跨庫的join以及聚合支持就不夠了。
NewSQL數據庫通常並不支持存儲過程、視圖、外鍵等功能,而中間件模式底層就是傳統關係數據庫,這些功能若是隻是涉及單庫是比較容易支持的。
NewSQL數據庫每每選擇兼容MySQL或者PostgreSQL協議,因此SQL支持僅侷限於這兩種,中間件例如驅動模式每每只需作簡單的SQL解析、計算路由、SQL重寫,因此能夠支持更多種類的數據庫SQL。
SQL支持的差別主要在於分佈式SQL執行計劃生成器,因爲NewSQL數據庫具備底層數據的分佈、統計信息,所以能夠作CBO,生成的執行計劃效率更高,而中間件模式下沒有這些信息,每每只能基於規則RBO(Rule-Based-Opimization),這也是爲何中間件模式通常並不支持跨庫join,由於實現了效率也每每並不高,還不如交給應用去作。
這裏也能夠看出中間件+分庫分表模式的架構風格體現出的是一種妥協、平衡,它是一個面向應用型的設計;而NewSQL數據庫則要求更高、「大包大攬」,它是一個通用底層技術軟件,所以後者的複雜度、技術門檻也高不少。
傳統關係數據庫的存儲引擎設計都是面向磁盤的,大多都基於B+樹。B+樹經過下降樹的高度減小隨機讀、進而減小磁盤尋道次數,提升讀的性能,但大量的隨機寫會致使樹的分裂,從而帶來隨機寫,致使寫性能降低。NewSQL的底層存儲引擎則多采用LSM,相比B+樹LSM將對磁盤的隨機寫變成順序寫,大大提升了寫的性能。不過LSM的的讀因爲須要合併數據性能比B+樹差,通常來講LSM更適合應在寫大於讀的場景。固然這只是單純數據結構角度的對比,在數據庫實際實現時還會經過SSD、緩衝、bloom filter等方式優化讀寫性能,因此讀性能基本不會降低太多。NewSQL數據因爲多副本、分佈式事務等開銷,相比單機關係數據庫SQL的響應時間並不佔優,但因爲集羣的彈性擴展,總體QPS提高仍是很明顯的,這也是NewSQL數據庫廠商說分佈式數據庫更看重的是吞吐,而不是單筆SQL響應時間的緣由。
分佈式數據庫是個新型通用底層軟件,準確的衡量與評價須要一個多維度的測試模型,需包括髮展示狀、使用狀況、社區生態、監控運維、周邊配套工具、功能知足度、DBA人才、SQL兼容性、性能測試、高可用測試、在線擴容、分佈式事務、隔離級別、在線DDL等等,雖然NewSQL數據庫發展通過了必定時間檢驗,但多集中在互聯網以及傳統企業非核心交易系統中,目前還處於快速迭代、規模使用不斷優化完善的階段。
相比而言,傳統關係數據庫則通過了多年的發展,經過完整的評測,在成熟度、功能、性能、周邊生態、風險把控、相關人才積累等多方面都具備明顯優點,同時對已建系統的兼容性也更好。
對於互聯網公司,數據量的增加壓力以及追求新技術的基因會更傾向於嘗試NewSQL數據庫,不用再考慮庫表拆分、應用改造、擴容、事務一致性等問題怎麼看都是很是吸引人的方案。
對於傳統企業例如銀行這種風險意識較高的行業來講,NewSQL數據庫則可能在將來一段時間內仍處於探索、審慎試點的階段。基於中間件+分庫分表模式架構簡單,技術門檻更低,雖然沒有NewSQL數據庫功能全面,但大部分場景最核心的訴求也就是拆分後SQL的正確路由,而此功能中間件模式應對仍是綽綽有餘的,能夠說在大多數OLTP場景是夠用的。
限於篇幅,其它特性例如在線DDL、數據遷移、運維工具等特性就不在本文展開對比。
若是看完以上內容,您還不知道選哪一種模式,那麼結合如下幾個問題,先思考下NewSQL數據庫解決的點對於自身是否是真正的痛點:
若是以上有2到3個是確定的,那麼你能夠考慮用NewSQL數據庫了,雖然前期可能須要必定的學習成本,但它是數據庫的發展方向,將來收益也會更高,尤爲是互聯網行業,隨着數據量的日新月異,分庫分錶帶來的痛苦會與日俱增。固然選擇NewSQL數據庫你也要作好承擔必定風險的準備。
若是你還未作出抉擇,不妨再想一想下面幾個問題:
若是這些問題有多數是確定的,那仍是分庫分表吧。在軟件領域不多有完美的解決方案,NewSQL數據庫也不是數據分佈式架構的銀彈。相比而言分庫分表是一個代價更低、風險更小的方案,它最大程度複用傳統關係數據庫生態,經過中間件也能夠知足分庫分表後的絕大多數功能,定製化能力更強。在當前NewSQL數據庫還未徹底成熟的階段,分庫分表能夠說是一個上限低但下限高的方案,尤爲傳統行業的核心繫統,若是你仍然打算把數據庫當作一個黑盒產品來用,踏踏實實用好分庫分表會被認爲是個穩妥的選擇。
不少時候軟件選型取決於領域特徵以及架構師風格,限於筆者知識與所屬行業特色所限,以上僅爲我的粗淺的一些觀點,歡迎討論。