當前位置:首頁 » 數據倉庫 » 資料庫tcc與xa
擴展閱讀
webinf下怎麼引入js 2023-08-31 21:54:13
堡壘機怎麼打開web 2023-08-31 21:54:11

資料庫tcc與xa

發布時間: 2023-07-17 21:42:35

1. 深入理解分布式事務,高並發下分布式事務的解決方案

1、什麼是分布式事務

分布式事務就是指事務的參與者、支持事務的伺服器、資源伺服器以及事務管理器分別位於不同的分布式系統的不同節點之上。以上是網路的解釋,簡單的說,就是一次大的操作由不同的小操作組成,這些小的操作分布在不同的伺服器上,且屬於不同的應用,分布式事務需要保證這些小操作要麼全部成功,要麼全部失敗。本質上來說,分布式事務就是為了保證不同資料庫的數據一致性。

2、分布式事務的產生的原因

2.1、資料庫分庫分表

當資料庫單表一年產生的數據超過1000W,那麼就要考慮分庫分表,具體分庫分表的原理在此不做解釋,以後有空詳細說,簡單的說就是原來的一個資料庫變成了多個資料庫。這時候,如果一個操作既訪問01庫,又訪問02庫,而且要保證數據的一致性,那麼就要用到分布式事務。

2.2、應用SOA化

所謂的SOA化,就是業務的服務化。比如原來單機支撐了整個電商網站,現在對整個網站進行拆解,分離出了訂單中心、用戶中心、庫存中心。對於訂單中心,有專門的資料庫存儲訂單信息,用戶中心也有專門的資料庫存儲用戶信息,庫存中心也會有專門的資料庫存儲庫存信息。這時候如果要同時對訂單和庫存進行操作,那麼就會涉及到訂單資料庫和庫存資料庫,為了保證數據一致性,就需要用到分布式事務。

以上兩種情況表象不同,但是本質相同,都是因為要操作的資料庫變多了!

3、事務的ACID特性

3.1、原子性(A)

所謂的原子性就是說,在整個事務中的所有操作,要麼全部完成,要麼全部不做,沒有中間狀態。對於事務在執行中發生錯誤,所有的操作都會被回滾,整個事務就像從沒被執行過一樣。

3.2、一致性(C)

事務的執行必須保證系統的一致性,就拿轉賬為例,A有500元,B有300元,如果在一個事務里A成功轉給B50元,那麼不管並發多少,不管發生什麼,只要事務執行成功了,那麼最後A賬戶一定是450元,B賬戶一定是350元。

3.3、隔離性(I)

所謂的隔離性就是說,事務與事務之間不會互相影響,一個事務的中間狀態不會被其他事務感知。

3.4、持久性(D)

所謂的持久性,就是說一單事務完成了,那麼事務對數據所做的變更就完全保存在了資料庫中,即使發生停電,系統宕機也是如此。

4、分布式事務的應用場景

4.1、支付

最經典的場景就是支付了,一筆支付,是對買家賬戶進行扣款,同時對賣家賬戶進行加錢,這些操作必須在一個事務里執行,要麼全部成功,要麼全部失敗。而對於買家賬戶屬於買家中心,對應的是買家資料庫,而賣家賬戶屬於賣家中心,對應的是賣家資料庫,對不同資料庫的操作必然需要引入分布式事務。

4.2、在線下單

買家在電商平台下單,往往會涉及到兩個動作,一個是扣庫存,第二個是更新訂單狀態,庫存和訂單一般屬於不同的資料庫,需要使用分布式事務保證數據一致性。

5、常見的分布式事務解決方案

5.1、基於XA協議的兩階段提交

XA是一個分布式事務協議,由Tuxedo提出。XA中大致分為兩部分:事務管理器和本地資源管理器。其中本地資源管理器往往由資料庫實現,比如Oracle、DB2這些商業資料庫都實現了XA介面,而事務管理器作為全局的調度者,負責各個本地資源的提交和回滾。XA實現分布式事務的原理如下:

總的來說,XA協議比較簡單,而且一旦商業資料庫實現了XA協議,使用分布式事務的成本也比較低。但是,XA也有致命的缺點,那就是性能不理想,特別是在交易下單鏈路,往往並發量很高,XA無法滿足高並發場景。XA目前在商業資料庫支持的比較理想,在mysql資料庫中支持的不太理想,mysql的XA實現,沒有記錄prepare階段日誌,主備切換回導致主庫與備庫數據不一致。許多nosql也沒有支持XA,這讓XA的應用場景變得非常狹隘。

5.2、消息事務+最終一致性

所謂的消息事務就是基於消息中間件的兩階段提交,本質上是對消息中間件的一種特殊利用,它是將本地事務和發消息放在了一個分布式事務里,保證要麼本地操作成功成功並且對外發消息成功,要麼兩者都失敗,開源的RocketMQ就支持這一特性,具體原理如下:

1、A系統向消息中間件發送一條預備消息

2、消息中間件保存預備消息並返回成功

3、A執行本地事務

4、A發送提交消息給消息中間件

通過以上4步完成了一個消息事務。對於以上的4個步驟,每個步驟都可能產生錯誤,下面一一分析:

步驟一出錯,則整個事務失敗,不會執行A的本地操作步驟二出錯,則整個事務失敗,不會執行A的本地操作步驟三出錯,這時候需要回滾預備消息,怎麼回滾?答案是A系統實現一個消息中間件的回調介面,消息中間件會去不斷執行回調介面,檢查A事務執行是否執行成功,如果失敗則回滾預備消息步驟四齣錯,這時候A的本地事務是成功的,那麼消息中間件要回滾A嗎?答案是不需要,其實通過回調介面,消息中間件能夠檢查到A執行成功了,這時候其實不需要A發提交消息了,消息中間件可以自己對消息進行提交,從而完成整個消息事務基於消息中間件的兩階段提交往往用在高並發場景下,將一個分布式事務拆成一個消息事務(A系統的本地操作+發消息)+B系統的本地操作,其中B系統的操作由消息驅動,只要消息事務成功,那麼A操作一定成功,消息也一定發出來了,這時候B會收到消息去執行本地操作,如果本地操作失敗,消息會重投,直到B操作成功,這樣就變相地實現了A與B的分布式事務。原理如下:

雖然上面的方案能夠完成A和B的操作,但是A和B並不是嚴格一致的,而是最終一致的,我們在這里犧牲了一致性,換來了性能的大幅度提升。當然,這種玩法也是有風險的,如果B一直執行不成功,那麼一致性會被破壞,具體要不要玩,還是得看業務能夠承擔多少風險。

5.3、TCC編程模式

所謂的TCC編程模式,也是兩階段提交的一個變種。TCC提供了一個編程框架,將整個業務邏輯分為三塊:Try、Confirm和Cancel三個操作。以在線下單為例,Try階段會去扣庫存,Confirm階段則是去更新訂單狀態,如果更新訂單失敗,則進入Cancel階段,會去恢復庫存。總之,TCC就是通過代碼人為實現了兩階段提交,不同的業務場景所寫的代碼都不一樣,復雜度也不一樣,因此,這種模式並不能很好地被復用。

6、總結

分布式事務,本質上是對多個資料庫的事務進行統一控制,按照控制力度可以分為:不控制、部分控制和完全控制。不控制就是不引入分布式事務,部分控制就是各種變種的兩階段提交,包括上面提到的消息事務+最終一致性、TCC模式,而完全控制就是完全實現兩階段提交。部分控制的好處是並發量和性能很好,缺點是數據一致性減弱了,完全控制則是犧牲了性能,保障了一致性,具體用哪種方式,最終還是取決於業務場景。作為技術人員,一定不能忘了技術是為業務服務的,不要為了技術而技術,針對不同業務進行技術選型也是一種很重要的能力

2. 分庫分表 VS newsql資料庫

最近與同行 科技 交流,經常被問到分庫分表與分布式資料庫如何選擇,網上也有很多關於中間件+傳統關系資料庫(分庫分表)與NewSQL分布式資料庫的文章,但有些觀點與判斷是我覺得是偏激的,脫離環境去評價方案好壞其實有失公允。

本文通過對兩種模式關鍵特性實現原理對比,希望可以盡可能客觀、中立的闡明各自真實的優缺點以及適用場景。

首先關於「中間件+關系資料庫分庫分表」算不算NewSQL分布式資料庫問題,國外有篇論文pavlo-newsql-sigmodrec,如果根據該文中的分類,Spanner、TiDB、OB算是第一種新架構型,Sharding-Sphere、Mycat、DRDS等中間件方案算是第二種(文中還有第三種雲資料庫,本文暫不詳細介紹)。

基於中間件(包括SDK和Proxy兩種形式)+傳統關系資料庫(分庫分表)模式是不是分布式架構?我覺得是的,因為存儲確實也分布式了,也能實現橫向擴展。但是不是"偽"分布式資料庫?從架構先進性來看,這么說也有一定道理。"偽"主要體現在中間件層與底層DB重復的SQL解析與執行計劃生成、存儲引擎基於B+Tree等,這在分布式資料庫架構中實際上冗餘低效的。為了避免引起真偽分布式資料庫的口水戰,本文中NewSQL資料庫特指這種新架構NewSQL資料庫。

NewSQL資料庫相比中間件+分庫分表的先進在哪兒?畫一個簡單的架構對比圖:

這些大多也是NewSQL資料庫產品主要宣傳的點,不過這些看起來很美好的功能是否真的如此?接下來針對以上幾點分別闡述下的我的理解。

這是把雙刃劍。

CAP限制

想想更早些出現的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確實提高了分布式事務的性能。

但不管如何優化,相比於1PC,2PC多出來的GID獲取、網路開銷、prepare日誌持久化還是會帶來很大的性能損失,尤其是跨節點的數量比較多時會更加顯著,例如在銀行場景做個批量扣款,一個文件可能上W個賬戶,這樣的場景無論怎麼做還是吞吐都不會很高。

雖然NewSQL分布式資料庫產品都宣傳完備支持分布式事務,但這並不是說應用可以完全不用關心數據拆分,這些資料庫的最佳實踐中仍然會寫到,應用的大部分場景盡可能避免分布式事務。

既然強一致事務付出的性能代價太大,我們可以反思下是否真的需要這種強一致的分布式事務?尤其是在做微服務拆分後,很多系統也不太可能放在一個統一的資料庫中。嘗試將一致性要求弱化,便是柔性事務,放棄ACID(Atomicity,Consistency, Isolation, Durability),轉投BASE(Basically Available,Soft state,Eventually consistent),例如Saga、TCC、可靠消息保證最終一致等模型,對於大規模高並發OLTP場景,我個人更建議使用柔性事務而非強一致的分布式事務。關於柔性事務,筆者之前也寫過一個技術組件,最近幾年也涌現出了一些新的模型與框架(例如阿里剛開源的Fescar),限於篇幅不再贅述,有空再單獨寫篇文章。

HA與異地多活

主從模式並不是最優的方式,就算是半同步復制,在極端情況下(半同步轉非同步)也存在丟數問題,目前業界公認更好的方案是基於paxos分布式一致性協議或者其它類paxos如raft方式,Google Spanner、TiDB、cockcoachDB、OB都採用了這種方式,基於Paxos協議的多副本存儲,遵循過半寫原則,支持自動選主,解決了數據的高可靠,縮短了failover時間,提高了可用性,特別是減少了運維的工作量,這種方案技術上已經很成熟,也是NewSQL資料庫底層的標配。

當然這種方式其實也可以用在傳統關系資料庫,阿里、微信團隊等也有將MySQL存儲改造支持paxos多副本的,MySQL也推出了官方版MySQL Group Cluster,預計不遠的未來主從模式可能就成為 歷史 了。

需要注意的是很多NewSQL資料庫廠商宣傳基於paxos或raft協議可以實現【異地多活】,這個實際上是有前提的,那就是異地之間網路延遲不能太高 。以銀行「兩地三中心」為例,異地之間多相隔數千里,延時達到數十毫秒,如果要多活,那便需異地副本也參與資料庫日誌過半確認,這樣高的延時幾乎沒有OLTP系統可以接受的。

資料庫層面做異地多活是個美好的願景,但距離導致的延時目前並沒有好的方案。 之前跟螞蟻團隊交流,螞蟻異地多活的方案是在應用層通過MQ同步雙寫交易信息,異地DC將交易信息保存在分布式緩存中,一旦發生異地切換,資料庫同步中間件會告之數據延遲時間,應用從緩存中讀取交易信息,將這段時間內涉及到的業務對象例如用戶、賬戶進行黑名單管理,等數據同步追上之後再將這些業務對象從黑名單中剔除。由於雙寫的不是所有資料庫操作日誌而只是交易信息,數據延遲隻影響一段時間內數據,這是目前我覺得比較靠譜的異地度多活方案。

另外有些系統進行了單元化改造,這在paxos選主時也要結合考慮進去,這也是目前很多NewSQL資料庫欠缺的功能。

Scale橫向擴展與分片機制

paxos演算法解決了高可用、高可靠問題,並沒有解決Scale橫向擴展的問題,所以分片是必須支持的。NewSQL資料庫都是天生內置分片機制的,而且會根據每個分片的數據負載(磁碟使用率、寫入速度等)自動識別熱點,然後進行分片的分裂、數據遷移、合並,這些過程應用是無感知的,這省去了DBA的很多運維工作量。以TiDB為例,它將數據切成region,如果region到64M時,數據自動進行遷移。

分庫分表模式下需要應用設計之初就要明確各表的拆分鍵、拆分方式(range、取模、一致性哈希或者自定義路由表)、路由規則、拆分庫表數量、擴容方式等。相比NewSQL資料庫,這種模式給應用帶來了很大侵入和復雜度,這對大多數系統來說也是一大挑戰。

這里有個問題是NewSQL資料庫統一的內置分片策略(例如tidb基於range)可能並不是最高效的,因為與領域模型中的劃分要素並不一致,這導致的後果是很多交易會產生分布式事務。 舉個例子,銀行核心業務系統是以客戶為維度,也就是說客戶表、該客戶的賬戶表、流水表在絕大部分場景下是一起寫的,但如果按照各表主鍵range進行分片,這個交易並不能在一個分片上完成,這在高頻OLTP系統中會帶來性能問題。

分布式SQL支持

常見的單分片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,因為實現了效率也往往並不高,還不如交給應用去做。

存儲引擎

傳統關系資料庫的存儲引擎設計都是面向磁碟的,大多都基於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資料庫還未完全成熟的階段,分庫分表可以說是一個上限低但下限高的方案,尤其傳統行業的核心系統,如果你仍然打算把資料庫當做一個黑盒產品來用,踏踏實實用好分庫分表會被認為是個穩妥的選擇。

很多時候軟體選型取決於領域特徵以及架構師風格,限於筆者知識與所屬行業特點所限,以上僅為個人粗淺的一些觀點,歡迎討論。

3. 資料庫為什麼要分庫分表

1 基本思想之什麼是分庫分表?
從字面上簡單理解,就是把原本存儲於一個庫的數據分塊存儲到多個庫上,把原本存儲於一個表的數據分塊存儲到多個表上。
2 基本思想之為什麼要分庫分表?


據庫中的數據量不一定是可控的,在未進行分庫分表的情況下,隨著時間和業務的發展,庫中的表會越來越多,表中的數據量也會越來越大,相應地,數據操作,增
刪改查的開銷也會越來越大;另外,由於無法進行分布式式部署,而一台伺服器的資源(CPU、磁碟、內存、IO等)是有限的,最終資料庫所能承載的數據量、
數據處理能力都將遭遇瓶頸。
3 分庫分表的實施策略。

分庫分表有垂直切分和水平切分兩種。
3.1
何謂垂直切分,即將表按照功能模塊、關系密切程度劃分出來,部署到不同的庫上。例如,我們會建立定義資料庫workDB、商品資料庫payDB、用戶數據
庫userDB、日誌資料庫logDB等,分別用於存儲項目數據定義表、商品定義表、用戶數據表、日誌數據表等。
3.2
何謂水平切分,當一個表中的數據量過大時,我們可以把該表的數據按照某種規則,例如userID散列,進行劃分,然後存儲到多個結構相同的表,和不同的庫
上。例如,我們的userDB中的用戶數據表中,每一個表的數據量都很大,就可以把userDB切分為結構相同的多個userDB:part0DB、
part1DB等,再將userDB上的用戶數據表userTable,切分為很多userTable:userTable0、userTable1等,
然後將這些表按照一定的規則存儲到多個userDB上。
3.3 應該使用哪一種方式來實施資料庫分庫分表,這要看資料庫中數據量的瓶頸所在,並綜合項目的業務類型進行考慮。
如果資料庫是因為表太多而造成海量數據,並且項目的各項業務邏輯劃分清晰、低耦合,那麼規則簡單明了、容易實施的垂直切分必是首選。

如果資料庫中的表並不多,但單表的數據量很大、或數據熱度很高,這種情況之下就應該選擇水平切分,水平切分比垂直切分要復雜一些,它將原本邏輯上屬於一體
的數據進行了物理分割,除了在分割時要對分割的粒度做好評估,考慮數據平均和負載平均,後期也將對項目人員及應用程序產生額外的數據管理負擔。
在現實項目中,往往是這兩種情況兼而有之,這就需要做出權衡,甚至既需要垂直切分,又需要水平切分。我們的游戲項目便綜合使用了垂直與水平切分,我們首先對資料庫進行垂直切分,然後,再針對一部分表,通常是用戶數據表,進行水平切分。
4 分庫分表存在的問題。

4.1 事務問題。
在執行分庫分表之後,由於數據存儲到了不同的庫上,資料庫事務管理出現了困難。如果依賴資料庫本身的分布式事務管理功能去執行事務,將付出高昂的性能代價;如果由應用程序去協助控制,形成程序邏輯上的事務,又會造成編程方面的負擔。
4.2 跨庫跨表的join問題。
在執行了分庫分表之後,難以避免會將原本邏輯關聯性很強的數據劃分到不同的表、不同的庫上,這時,表的關聯操作將受到限制,我們無法join位於不同分庫的表,也無法join分表粒度不同的表,結果原本一次查詢能夠完成的業務,可能需要多次查詢才能完成。
4.3 額外的數據管理負擔和數據運算壓力。

外的數據管理負擔,最顯而易見的就是數據的定位問題和數據的增刪改查的重復執行問題,這些都可以通過應用程序解決,但必然引起額外的邏輯運算,例如,對於
一個記錄用戶成績的用戶數據表userTable,業務要求查出成績最好的100位,在進行分表之前,只需一個order
by語句就可以搞定,但是在進行分表之後,將需要n個order
by語句,分別查出每一個分表的前100名用戶數據,然後再對這些數據進行合並計算,才能得出結果。

4. 分布式資料庫的工作原理是什麼

分布式數據有不同的理論支撐,TiDB 官方社區(AskTUG)


目前國產數據排名靠前的可以了解下 TiDB

  • 水平彈性擴展

    通過簡單地增加新節點即可實現 TiDB 的水平擴展,按需擴展吞吐或存儲,輕松應對高並發、海量數據場景。

  • 分布式事務

    TiDB 100% 支持標準的 ACID 事務。

  • 真正金融級高可用

    相比於傳統主從 (M-S) 復制方案,基於 Raft 的多數派選舉協議可以提供金融級的 100% 數據強一致性保證,且在不丟失大多數副本的前提下,可以實現故障的自動恢復 (auto-failover),無需人工介入。

5. 資料庫架構選型與落地,看這篇就夠了

隨著時間和業務的發展,資料庫中的數據量增長是不可控的,庫和表中的數據會越來越大,隨之帶來的是更高的 磁碟 IO 系統開銷 ,甚至 性能 上的瓶頸,而單台伺服器的 資源終究是有限 的。

因此在面對業務擴張過程中,應用程序對資料庫系統的 健壯性 安全性 擴展性 提出了更高的要求。

以下,我從資料庫架構、選型與落地來讓大家入門。

資料庫會面臨什麼樣的挑戰呢?

業務剛開始我們只用單機資料庫就夠了,但隨著業務增長,數據規模和用戶規模上升,這個時候資料庫會面臨IO瓶頸、存儲瓶頸、可用性、安全性問題。

為了解決上述的各種問題,資料庫衍生了出不同的架構來解決不同的場景需求。

將資料庫的寫操作和讀操作分離,主庫接收寫請求,使用多個從庫副本負責讀請求,從庫和主庫同步更新數據保持數據一致性,從庫可以水平擴展,用於面對讀請求的增加。

這個模式也就是常說的讀寫分離,針對的是小規模數據,而且存在大量讀操作的場景。

因為主從的數據是相同的,一旦主庫宕機的時候,從庫可以 切換為主庫提供寫入 ,所以這個架構也可以提高資料庫系統的 安全性 可用性

優點:

缺點:

在資料庫遇到 IO瓶頸 過程中,如果IO集中在某一塊的業務中,這個時候可以考慮的就是垂直分庫,將熱點業務拆分出去,避免由 熱點業務 密集IO請求 影響了其他正常業務,所以垂直分庫也叫 業務分庫

優點:

缺點:

在資料庫遇到存儲瓶頸的時候,由於數據量過大造成索引性能下降。

這個時候可以考慮將數據做水平拆分,針對數據量巨大的單張表,按照某種規則,切分到多張表裡面去。

但是這些表還是在同一個庫中,所以庫級別的資料庫操作還是有IO瓶頸(單個伺服器的IO有上限)。

所以水平分表主要還是針對 數據量較大 ,整體業務 請求量較低 的場景。

優點:

缺點:

四、分庫分表

在資料庫遇到存儲瓶頸和IO瓶頸的時候,數據量過大造成索引性能下降,加上同一時間需要處理大規模的業務請求,這個時候單庫的IO上限會限制處理效率。

所以需要將單張表的數據切分到多個伺服器上去,每個伺服器具有相應的庫與表,只是表中數據集合不同。

分庫分表能夠有效地緩解單機和單庫的 性能瓶頸和壓力 ,突破IO、連接數、硬體資源等的瓶頸。

優點:

缺點:

註:分庫還是分表核心關鍵是有沒有IO瓶頸

分片方式都有什麼呢?

RANGE(范圍分片)

將業務表中的某個 關鍵欄位排序 後,按照順序從0到10000一個表,10001到20000一個表。最常見的就是 按照時間切分 (月表、年表)。

比如將6個月前,甚至一年前的數據切出去放到另外的一張表,因為隨著時間流逝,這些表的數據被查詢的概率變小,銀行的交易記錄多數是採用這種方式。

優點:

缺點:

HASH(哈希分片)

將訂單作為主表,然後將其相關的業務表作為附表,取用戶id然後 hash取模 ,分配到不同的數據表或者資料庫上。

優點:

缺點:

講到這里,我們已經知道資料庫有哪些架構,解決的是哪些問題,因此, 我們在日常設計中需要根據數據的特點,數據的傾向性,數據的安全性等來選擇不同的架構

那麼,我們應該如何選擇資料庫架構呢?

雖然把上面的架構全部組合在一起可以形成一個強大的高可用,高負載的資料庫系統,但是架構選擇合適才是最重要的。

混合架構雖然能夠解決所有的場景的問題,但是也會面臨更多的挑戰,你以為的完美架構,背後其實有著更多的坑。

1、對事務支持

分庫分表後(無論是垂直還是水平拆分),就成了分布式事務了,如果依賴資料庫本身的分布式事務管理功能去執行事務,將付出高昂的性能代價(XA事務);如果由應用程序去協助控制,形成程序邏輯上的事務,又會造成編程方面的負擔(TCC、SAGA)。

2、多庫結果集合並 (group by,order by)

由於數據分布於不同的資料庫中,無法直接對其做分頁、分組、排序等操作,一般應對這種多庫結果集合並的查詢業務都需要採用數據清洗、同步等其他手段處理(TIDB、KUDU等)。

3、數據延遲

主從架構下的多副本機制和水平分庫後的聚合庫都會存在主數據和副本數據之間的延遲問題。

4、跨庫join

分庫分表後表之間的關聯操作將受到限制,我們無法join位於不同分庫的表(垂直),也無法join分表粒度不同的表(水平), 結果原本一次查詢就能夠完成的業務,可能需要多次查詢才能完成。

5、分片擴容

水平分片之後,一旦需要做擴容時。需要將對應的數據做一次遷移,成本代價都極高的。

6、ID生成

分庫分表後由於資料庫獨立,原有的基於資料庫自增ID將無法再使用,這個時候需要採用其他外部的ID生成方案。

一、應用層依賴類(JDBC)

這類分庫分表中間件的特點就是和應用強耦合,需要應用顯示依賴相應的jar包(以Java為例),比如知名的TDDL、當當開源的 sharding-jdbc 、蘑菇街的TSharding等。

此類中間件的基本思路就是重新實現JDBC的API,通過重新實現 DataSource PrepareStatement 等操作資料庫的介面,讓應用層在 基本 不改變業務代碼的情況下透明地實現分庫分表的能力。

中間件給上層應用提供熟悉的JDBC API,內部通過 sql解析 sql重寫 sql路由 等一系列的准備工作獲取真正可執行的sql,然後底層再按照傳統的方法(比如資料庫連接池)獲取物理連接來執行sql,最後把數據 結果合並 處理成ResultSet返回給應用層。

優點

缺點

二、中間層代理類(Proxy)

這類分庫分表中間件的核心原理是在應用和資料庫的連接之間搭起一個 代理層 ,上層應用以 標準的MySQL協議 來連接代理層,然後代理層負責 轉發請求 到底層的MySQL物理實例,這種方式對應用只有一個要求,就是只要用MySQL協議來通信即可。

所以用MySQL Navicat這種純的客戶端都可以直接連接你的分布式資料庫,自然也天然 支持所有的編程語言

在技術實現上除了和應用層依賴類中間件基本相似外,代理類的分庫分表產品必須實現標準的MySQL協議,某種意義上講資料庫代理層轉發的就是MySQL協議請求,就像Nginx轉發的是Http協議請求。

比較有代表性的產品有開創性質的Amoeba、阿里開源的Cobar、社區發展比較好的 Mycat (基於Cobar開發)等。

優點

缺點

JDBC方案 :無中心化架構,兼容市面上大多數關系型資料庫,適用於開發高性能的輕量級 OLTP 應用(面向前台)。

Proxy方案 :提供靜態入口以及異構語言的支持,適用於 OLAP 應用(面向後台)以及對分片資料庫進行管理和運維的場景。

混合方案 :在大型復雜系統中存在面向C端用戶的前台應用,也有面向企業分析的後台應用,這個時候就可以採用混合模式。

JDBC 採用無中心化架構,適用於 Java 開發的高性能的輕量級 OLTP 應用;Proxy 提供靜態入口以及異構語言的支持,適用於 OLAP 應用以及對分片資料庫進行管理和運維的場景。

ShardingSphere是一套開源的分布式資料庫中間件解決方案組成的生態圈,它由 Sharding-JDBC Sharding-Proxy Sharding-Sidecar (計劃中)這3款相互獨立的產品組成,他們均提供標准化的數據分片、分布式事務和資料庫治理功能,可適用於如Java同構、異構語言、容器、雲原生等各種多樣化的應用場景。

ShardingSphere提供的核心功能:

Sharding-Proxy

定位為透明化的 資料庫代理端 ,提供封裝了 資料庫二進制協議的服務端版本 ,用於完成對 異構語言的支持

目前已提供MySQL版本,它可以使用 任何兼容MySQL協議的訪問客戶端 (如:MySQL Command Client, MySQL Workbench, Navicat等)操作數據,對DBA更加友好。

應用程序完全透明 ,可直接當做MySQL使用。

適用於任何兼容MySQL協議的客戶端。

Sharding-JDBC

定位為 輕量級Java框架 ,在Java的JDBC層提供的額外服務。 它使用客戶端直連資料庫,以jar包形式提供服務,無需額外部署和依賴,可理解為 增強版的JDBC驅動,完全兼容JDBC和各種ORM框架

以電商SaaS系統為例,前台應用採用Sharding-JDBC,根據業務場景的差異主要分為三種方案。

分庫(用戶)

問題解析:頭部企業日活高並發高,單獨分庫避免干擾其他企業用戶,用戶數據的增長緩慢可以不分表。

拆分維度:企業ID分庫

拆分策略:頭部企業單獨庫、非頭部企業一個庫

分庫分表(訂單)

問題解析:訂單數據增長速度較快,在分庫之餘需要分表。

拆分維度:企業ID分庫、用戶ID分表

拆分策略:頭部企業單獨庫、非頭部企業一個庫,分庫之後用戶ID取模拆分表

單庫分表(附件)

問題解析:附件數據特點是並發量不大,只需要解決數據增長問題,所以單庫IO足以支撐的情況下分表即可。

拆分維度:用戶ID分表

拆分策略:用戶ID取模分表

問題一:分布式事務

分布式事務過於復雜也是分布式系統最難處理的問題,由於篇幅有限,後續會開篇專講這一塊內容。

問題二:分布式ID

問題三:跨片查詢

舉個例子,以用戶id分片之後,需要根據企業id查詢企業所有用戶信息。

sharding針對跨片查詢也是能夠支持的,本質上sharding的跨片查詢是採用同時查詢多個分片的數據,然後聚合結果返回,這個方式對資源耗費比較大,特別是對資料庫連接資源的消耗。

假設分4個資料庫,8個表,則sharding會同時發出32個SQL去查詢。一下子消耗掉了32個連接;

特別是針對單庫分表的情況要注意,假設單庫分64個表,則要消耗64個連接。如果我們部署了2個節點,這個時候兩個節點同時查詢的話,就會遇到資料庫連接數上限問題(mysql默認100連接數)

問題四:分片擴容

隨著數據增長,每個片區的數據也會達到瓶頸,這個時候需要將原有的分片數量進行增加。由於增加了片區,原先的hash規則也跟著變化,造成了需要將舊數據做遷移。

假設原先1個億的數據,hash分64個表,現在增長到50億的數據,需要擴容到128個表,一旦擴容就需要將這50億的數據做一次遷移,遷移成本是無法想像的。

問題五:一致性哈希

首先,求出每個 伺服器的hash值 ,將其配置到一個 0~2^n 的圓環上 (n通常取32)

其次,用同樣的方法求出待 存儲對象的主鍵 hash值 ,也將其配置到這個圓環上。

然後,從數據映射到的位置開始順時針查找,將數據分布到找到的第一個伺服器節點上。

一致性hash的優點在於加入和刪除節點時只會影響到在哈希環中相鄰的節點,而對其他節點沒有影響。

所以使用一致性哈希在集群擴容過程中可以減少數據的遷移。

好了,這次分享到這里,我們日常的實踐可能只會用到其中一種方案,但它不是資料庫架構的全貌,打開技術視野,才能更好地把存儲工具利用起來。

老規矩,一鍵三連,日入兩千,點贊在看,年薪百萬!

本文作者:Jensen

7年Java老兵,小米主題設計師,手機輸入法設計師,ProcessOn特邀講師。

曾涉獵航空、電信、IoT、垂直電商產品研發,現就職於某知名電商企業。

技術公眾號 【架構師修行錄】 號主,專注於分享日常架構、技術、職場干貨,Java Goals:架構師。

交個朋友,一起成長!