為什么顯示有票你卻搶不到?技術(shù)揭秘12306如何保證車票不超賣
每逢小長假,小云都會因為搶票而夜不能寐。她打開12306,一遍遍刷新,發(fā)現(xiàn)還有余票2張,趕緊下單,一頓操作猛如虎,結(jié)果還是沒搶到。

但仔細(xì)想想也能理解:從勾選乘車人到正式下單,整個流程至少需要10秒,如果“見者有份”,恐怕這兩個座位大家要擠擠共用了。
那么,每逢節(jié)假日,當(dāng)全國幾百萬小伙伴同時查票、訂票時,12306是如何保證余票顯示準(zhǔn)、車票不超賣的?
于是,按捺不住好奇心的我們,進行了一番深入研究。原來問題背后隱藏著一個分布式數(shù)據(jù)庫領(lǐng)域極其關(guān)鍵的技術(shù)——數(shù)據(jù)強一致性保障。
1. 什么是強一致?
在介紹概念之前,我們不妨先來模擬一場球賽直播。
假設(shè)筆者做了一款A(yù)PP,后臺使用上圖的主從數(shù)據(jù)庫。比分寫入主節(jié)點,從節(jié)點分擔(dān)用戶查詢。比賽中,Alice驚呼比賽結(jié)束,Bob聞聲刷新APP,卻顯示比賽仍在繼續(xù)!Bob體驗到了明顯的數(shù)據(jù)不一致,于是默默給APP打了個差評……
那么,產(chǎn)生不一致的原因究竟是什么?
異步復(fù)制時,主節(jié)點不等待從節(jié)點寫入就直接返回了。由于網(wǎng)絡(luò)延遲等原因,從節(jié)點無法保證更新時間。Alice和Bob明明在同時同地查詢同一系統(tǒng),得到正確結(jié)果卻有先有后。其實這就是典型的弱一致性。
實際上,為解決單點故障、增強吞吐性能,分布式數(shù)據(jù)庫內(nèi)部都會對同一份數(shù)據(jù)進行復(fù)制,把冗余副本分散保存到不同節(jié)點上。簡單的異步復(fù)制只能構(gòu)建出弱一致系統(tǒng),很難滿足業(yè)務(wù)要求。
那么,究竟什么樣的一致性才靠譜?有哪些類別?下面我們就來認(rèn)識這個神秘家族!
1.1 強一致性/線性一致性(Linearizability)
強一致性/線性一致性是一致性的最高標(biāo)準(zhǔn),實現(xiàn)難度最高。核心要求是:一旦寫操作完成,隨后任意客戶端的查詢都必須返回這一新值。以下圖為例,一旦“寫入b”完成,必須保證讀到b。而寫入過程中,認(rèn)為值的跳變可能發(fā)生在某一瞬間,因此讀到a或b都是可能的。
從業(yè)務(wù)角度來說,強一致性帶來的體驗簡直可以用絲滑來形容!因為它內(nèi)部的數(shù)據(jù)“仿佛”只有一份,即使并發(fā)訪問不同節(jié)點,每個操作也都能原子有序。正因如此,強一致數(shù)據(jù)庫在業(yè)務(wù)架構(gòu)中往往被用在關(guān)鍵位置。
etcd是強一致俱樂部里的元老。它基于Raft共識算法,真正實現(xiàn)了強一致,也因此在Leader選舉、服務(wù)發(fā)現(xiàn)等場景起到重要作用。GaussDB(for Redis)作為一款分布式云數(shù)據(jù)庫,憑借多年潛心打磨,也是強一致的代言人。
1.2 順序一致性(Sequential Consistency)
順序一致性弱于線性一致,不保證操作的全局時序,但保證每個客戶端操作能按順序被執(zhí)行。下圖中,A先寫x=10,后寫x=20;B先寫x=99,后寫x=999。當(dāng)C讀取時,順序一致性保證了10先于20被讀到、99先于999被讀到。
Zookeeper基于ZAB協(xié)議,所有寫操作都經(jīng)由主節(jié)點協(xié)調(diào),實現(xiàn)了順序一致性。
1.3 因果一致性(Causal Consistency)
進一步放寬要求,因果一致性只對并發(fā)訪問中具有因果關(guān)系的操作保序。例如:
A寫入3,B讀到后乘以100再更新它。在這個場景下,由于“A寫入3”與“B寫入300”有著明確因果關(guān)系,因果一致性保證300晚于3被讀到。
因果一致性多用于各種博客的評論系統(tǒng)、社交軟件等。畢竟,我們回復(fù)某條評論的內(nèi)容,不應(yīng)早于評論本身被顯示出來。
1.4 最終一致性(Eventual Consistency)
它指的是停止寫入并等待一段時間,最終所有客戶端都能讀到相同的新數(shù)據(jù),但具體時限不作保證。許多分布式數(shù)據(jù)庫都滿足最終一致性,如MySQL主從集群等。
然而,這其實是一個非常弱的保證。由于不確定系統(tǒng)內(nèi)部過多久才能收斂一致,在此之前,用戶隨時可能體驗到數(shù)據(jù)不一致。因此最終一致性有天然的局限性,經(jīng)常會給業(yè)務(wù)邏輯帶來混亂。
1.5 弱一致性(Weak Consistency)
說弱一致性最為“厚臉皮”也不為過,因為它連數(shù)據(jù)寫入后將來被讀到都不能保證。弱一致性實現(xiàn)技術(shù)門檻低,應(yīng)用場景也不多。嚴(yán)格來說,單純的開源Redis主從集群就屬于這一類別。
OK,一致性家族的各位成員已經(jīng)跟大家打過照面。顯然,一致性越強的數(shù)據(jù)庫系統(tǒng),能夠支撐的業(yè)務(wù)場景越多。有的業(yè)務(wù)同學(xué)小聲說,強一致技術(shù)再牛,可我業(yè)務(wù)簡單,不用也沒關(guān)系吧。實際上恰恰相反:
強一致不僅僅是技術(shù)問題,它更是一個不可忽視的業(yè)務(wù)需求、運維需求!
接下來我們就先來聊一聊:業(yè)務(wù)上那些只有強一致才能搞定的事兒!
2 強一致是業(yè)務(wù)剛需
2.1 計數(shù)器/限流器
計數(shù)服務(wù)是典型的強一致應(yīng)用場景。電商在秒殺活動中,往往會搭建Redis主從集群給下層MySQL做緩存。因為要抗住超大流量,需要Redis的計數(shù)器功能做限流。簡單講,我們初始化counter=5000。隨后每次業(yè)務(wù)訪問都執(zhí)行DECR命令,當(dāng)counter歸零就阻塞后續(xù)請求。此外,每隔一個時間段重置counter=5000,通過這樣的手段來實現(xiàn)“細(xì)水長流”。
然而,完美的假設(shè)還不夠!
開源Redis采用異步復(fù)制,如遇網(wǎng)絡(luò)不暢,經(jīng)常發(fā)生主節(jié)點復(fù)制buffer堆積。這將導(dǎo)致從節(jié)點counter偏大很多。此時,一旦主節(jié)點宕機,切換到從節(jié)點繼續(xù)執(zhí)行DECR命令,壓力很容易超出閾值,全部落到下層脆弱的MySQL,隨時可能引起系統(tǒng)雪崩!
因此,在限流場景下,只有真正的強一致才能提供可靠的計數(shù)器。
2.2 Leader選舉
當(dāng)業(yè)務(wù)部署的節(jié)點較多、可用性要求高時,往往要用到Leader選舉。etcd作為強一致KV存儲,能完美cover這一場景。etcd依賴兩大功能實現(xiàn)Leader選舉:
1)TTL:給key設(shè)置有效期,到期后key自動刪除。
2)CAS:對key的原子操作 (這一功能只有強一致數(shù)據(jù)庫才能實現(xiàn)) ,使用etcd搭建Leader選舉服務(wù)的設(shè)計如下:
1)約定key,用于選舉時搶占。其value用于保存Leader節(jié)點名稱。
2)約定TTL,用于給key設(shè)定有效期。
3)啟動時:每個參與節(jié)點嘗試cas create key&設(shè)置TTL。在etcd集群強一致CAS機制保障下,只有一個節(jié)點能執(zhí)行成功。該節(jié)點成為Leader并將名稱寫入value;其余節(jié)點成為Follower。
4)運行中:每個節(jié)點定期TTL/2嘗試get key,將value與自身名稱對比:
如相同,說明已是Leader,此后只需每隔TTL/2刷新key的TTL即可。
如不同,說明是Follower,接下來要每隔TTL/2執(zhí)行cas create key&設(shè)置TTL。
5)當(dāng)Leader節(jié)點異常退出,無法刷新TTL,key會很快過期。此時,其余Follow之中便會有新的Leader產(chǎn)生。
從原理上能看出,強一致能力是Leader選舉的根基。類似的“剛需”業(yè)務(wù)場景還有很多,強一致不可或缺。
好了,業(yè)務(wù)上的事兒就聊到這里,接下來讓我們聽聽運維怎么說。
3. 強一致為運維減負(fù)
3.1 輔助組件架構(gòu)復(fù)雜、問題難定位
后臺架構(gòu)中,MySQL主從熱備也是常見的部署方式。由于數(shù)據(jù)保存在本地磁盤中,當(dāng)主庫發(fā)生嚴(yán)重故障,僅僅依靠MySQL自身同步機制,主從切換后無法保證所提供數(shù)據(jù)與之前狀態(tài)完全一致。于是出現(xiàn)了“重量級”的輔助組件——MHA(Master High Availability)。我們來看一下它的部署方式:
MHA負(fù)責(zé)在故障轉(zhuǎn)移過程中,幫助從庫盡量追平主庫最新狀態(tài),提供近似一致的數(shù)據(jù)。但這一能力需要額外的Manager節(jié)點,同時還要在每一個MySQL節(jié)點上部署Node服務(wù)。故障切換時,Manager先為從庫補充落后的數(shù)據(jù),再通過切換VIP恢復(fù)用戶訪問,過程可能長達數(shù)十秒。
這樣的HA系統(tǒng)部署和后期維護都很復(fù)雜。如未能順利執(zhí)行故障切換或發(fā)生數(shù)據(jù)丟失,運維面臨的場面都將很棘手。其實運維同學(xué)何嘗不希望手中的系統(tǒng)穩(wěn)定運行呢?要是數(shù)據(jù)庫自身能提供強一致保障,何苦再依賴復(fù)雜的輔助組件!
讀到這里,對強一致的看法,相信各位讀者心里已經(jīng)有了自己的一桿秤。讓我們再一次劃重點:
強一致不僅僅是技術(shù)問題,它更是一個不可忽視的業(yè)務(wù)需求、運維需求!
從產(chǎn)品選型角度出發(fā),開源Redis提供的一致性保證很弱。而etcd雖有強一致能力,但它單點寫入性能不足,也未能提供hash、sorted set、stream等誘人的數(shù)據(jù)結(jié)構(gòu)……
此時,有人會陷入糾結(jié),到底選擇哪一種,GaussDB(for Redis)應(yīng)聲而起——我,都可以。
4. GaussDB(for Redis)與強一致
自設(shè)計之初,GaussDB(for Redis)(后文簡稱高斯Redis)給自己的定位就是“強一致KV數(shù)據(jù)庫”,因此徹底摒棄了開源Redis的異步復(fù)制機制。借助華為云GaussDB系列先進的“存算分離”架構(gòu),將全量數(shù)據(jù)下沉到強一致存儲層(DFV Pool),從核心技術(shù)上超越了傳統(tǒng)開源產(chǎn)品的極限。
讓我們來一起認(rèn)識一下高斯Redis的強悍:
用戶購買的實例作為一個整體,提供強一致KV存儲。
用戶業(yè)務(wù)統(tǒng)一通過Proxy集群接入高斯Redis,不用考慮內(nèi)部復(fù)雜邏輯。多點并發(fā)訪問實例,讀寫操作滿足強一致性,再也不必?fù)?dān)心開源Redis異步復(fù)制的不一致隱患。
計算層智能處理數(shù)據(jù)分片、動態(tài)故障轉(zhuǎn)移,將數(shù)據(jù)全量下沉到共享存儲池。
cfgsvr集群統(tǒng)一管理ShardServer節(jié)點,自動對海量數(shù)據(jù)進行分片。并能夠在故障場景實現(xiàn)秒級接管,嚴(yán)格防止任何中間態(tài)下的數(shù)據(jù)不一致。
存儲層通過RDMA高速網(wǎng)絡(luò)實現(xiàn)高性能分布式數(shù)據(jù)持久化,三副本冗余保證強一致、零丟失。
DFV Pool是強一致、高性能的分布式存儲系統(tǒng)。這是華為內(nèi)部自研的公司級Data Lake,它能夠穩(wěn)定支撐各類全棧數(shù)據(jù)服務(wù)。高斯Redis突破了開源Redis“小格局”的內(nèi)存架構(gòu),將數(shù)據(jù)全量下沉,基于DFV Pool強大的一致性保障能力,給用戶業(yè)務(wù)帶來更廣闊的拓展空間。
5. 結(jié)語
試想,當(dāng)處在關(guān)鍵位置的數(shù)據(jù)庫“不給力”,業(yè)務(wù)層就要忙于為系統(tǒng)添加復(fù)雜、易出錯的一致性保障邏輯。與此同時,運維還要時刻擔(dān)心故障引發(fā)的數(shù)據(jù)落后問題…這樣的系統(tǒng)真的“香”嗎?
試想如果12306顯示你搶到票了,上車的時候卻發(fā)現(xiàn)有四五個人和你是同一個座位,太詭異了。
所以,專業(yè)的事情交給專業(yè)的團隊來做。GaussDB(for Redis)自研發(fā)初期就持續(xù)關(guān)注數(shù)據(jù)強一致性設(shè)計,借助強一致存儲池DFV Pool,它可以提供真正強一致的海量KV存儲解決方案。
Redis 數(shù)據(jù)庫
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內(nèi)刪除侵權(quán)內(nèi)容。
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內(nèi)刪除侵權(quán)內(nèi)容。