看到外賣平臺這樣改善資料庫架構,DBA表示放心了
今天我想和大家分享餓了麼作為高速發展的網際網路企業之一,在發展歷程中資料庫技術如何跟隨企業發展並不斷滿足業務的需求,會大致介紹下資料庫經歷了哪些階段,以及我們做了怎樣的一些事情。
分享內容大致涉及到以下5點:
-
資料庫架構怎麼滿足業務、支撐業務發展;
-
怎麼提高資料庫的可用性;
-
如何對資料流進行相應的控制和保護;
-
規模大了以後如何提高資料庫運維的效率;
-
一些個人認為重要原則的總結。
首先簡單介紹一下餓了麼的概況,點過外賣的同學應該都知道餓了麼吧?
餓了麼發展最快階段也是最近四五年的事情,我是2015年進入餓了麼的,那時每天才幾十萬的訂單,伺服器也不多;到了2016年時每天訂單達到了幾百萬,商戶也更多了;而2017年不管是訂單、運單都是千萬以上,直到現在都還在快速增長。
這麼多資料的產生對底層資料儲存是非常大的挑戰,而且那個時候要在非常短的時間內應對業務的爆發性的增長,所以當時底層的技術挑戰也是非常大的。
一、資料庫架構
1、垂直拆分
在資料庫架構方面餓了麼開始的時候也是比較原始的階段,最初是一主多從的架構;發展到後面發現訂單資料庫很難再滿足業務往上增長的需求了;過百萬之後一主不管幾從都很難滿足業務的需求(因為寫太大),這就面臨著需要拆分的情況,需要把熱點業務單獨拆出來,把一套資料庫拆成多套,進行垂直的業務拆分。
資料庫架構-垂直
拆分根據什麼原則呢?又怎麼來預算訂單庫現在的架構能承載多少的TPS和QPS呢?
我們當時是結合訂單量、對應的QPS、TPS資料,再根據半年後的增長情況來推算出每個業務大概會產生出多少的QPS、TPS,然後結合每套叢集能承載的TPS、QPS數量(基於壓測),就能估算出需要拆分成什麼樣的結構、以及拆分後每一套(半年後)大致需要承載多少TPS、QPS。
當時按業務垂直拆分後,這一套方案承載了200、300萬訂單的規模,垂直拆分的優勢是代價小見效快(業務程式碼改動並不大),能快速有效的支撐業務。
2、水平拆分
雖然按垂直架構拆分完了,但是熱點的地方依然還是熱點,比如說訂單隨著下單量的增長依然會變成很大的瓶頸。那如何打破瓶頸呢?
我們需要把訂單這個熱點再單獨拆分成多套。
資料庫架構-水平
也就是行業裡說得比較多的“水平拆分”,把原來的一張訂單表在底層拆成1000張小表,放在不同的叢集上。這樣即使這一個訂單的量再大,也能夠通過不斷水平擴容機器來將壓力拆分到更多的叢集上,從而滿足了熱點的效能承載。
我們可以通過壓測計算出每套叢集能承載出多少QPS和TPS,再結合現在的業務情況就能估算出多少訂單會對應產生多少的QPS和TPS,進而也能知道拆分成多少套叢集能承載多少的業務量,所以也就知道了要擴多少機器才能滿足半年或者一年後的業務增長。
如果說底層因為擴容做了分片策略,但是這個改動對業務不是透明的話,那就意味著業務需要做很多改造來適應底層的分片邏輯,一般業務是很難接受的。
所以,我們的水平拆分為了對業務做到透明,需要做一層代理層(我們叫DAL),代理層會幫助業務程式碼做到對資料庫底層拆分邏輯的訪問透明,業務看到的還是一張訂單表,但是底層變了1000張表。
完成水平擴容後基本上所謂的熱點也不會存在太大的瓶頸,如果再往上增長的話可以繼續拆小,繼續新增更多的機器來承載。
3、多活架構
垂直拆分之後,我們就沒有效能瓶頸了嗎?
其實機房也會成為我們的瓶頸。一般來講企業都是租賃供應商的機房,一個機房能進多少機器不是無限的,供應商也不可能給你預留太多的位置。
當你服務所在的機房放不進去機器以後,你會發現雖然技術架構能滿足水平擴容,但是在物理上不能再加機器了,效能瓶頸依然會到來。
為打破單個機房面臨的容量瓶頸,我們需要擴容到更多的機房,所以我們做了“多活架構”。
資料庫架構-多活
在每個機房資料庫都是簡單的主從架構,下單的時候北京使用者可以在第一個機房下單,上海使用者可以在第二個機房下單。
這樣的話下單的高峰壓力會分散到多個點去,同一套叢集在兩個機房都有部署,意味著承載的效能變大了。這個時候就可以在兩個機房放機器,如果一個機房的機器滿了放不下,我們可以把流量引到另一個機房,擴容另一邊機房,這樣就打破了單個機房對容量的限制。
我們多活邏輯是根據使用者所在的位置決定他在哪個機房下單,可能他今天在北京明天在上海,下的單在不同的機房,要讓使用者看到所有的資料,就必須要讓資料雙向流通起來,所以多機房之間做資料的相互流通是資料庫做多活的必備條件。
有很多企業做的是熱備,只是在一邊下單,但是另一邊是backup的狀態,一旦這邊出現問題以後再切到那邊,這樣的架構並不能解決效能問題,而且資源利用率很低(有多少公司出問題真敢切?);而我們多活的架構可以在兩個機房同時下單,能讓效能、資源利用率和可靠性都得到明顯提高。
資料庫架構層面從垂直拆分、水平拆分到多活後,基本能滿足絕大多數企業的業務發展了,這當中我們有兩個組建發揮了重要的作用,也一起介紹下:
1)DAL
代理層(DAL),最直觀的需求是能做分庫分表,能做讀寫分離,還可以做資源隔離、連線數隔離、連線的管理等,更重要的是還能對資料庫進行相應的保護。
外賣業務大多數人都是在中午下單,所以11點左右是餓了麼的業務最高峰。
為了緩解資料庫壓力,我們會通過DAL層做消峰處理,當流量過大時我們會讓使用者訊息做排隊的處理,由此緩解對資料庫的瞬間衝擊。如果流量特別大的時候還可以做限流、熔斷等處理。
還有黑白名單機制,大家瞭解資料庫運維的話會知道,如果研發寫的SQL有問題,放入到資料庫裡風險會比較高。如果他現在發了一個刪除表的SQL命令過來就有風險,我們的DAL就會把這類黑名單SQL給拒絕。
更高階一點的功能是多維分表以及全域性表MapTable功能。有些配置表希望在所有機房都有,DAL上就可以做GlobalTable的功能,可以保證在所有節點上都是同樣的資料。
當然,DAL做完這些功能後,對SQL也是有一些限制的。比方說事務,下單不能跨服務片去做事務。
很多傳統的應用業務邏輯會把很多東西包在一個事務裡完成,但網際網路業務應該儘量減少這種應用,在底層分片後,業務事務並不能完全通過資料庫裡的事務來保障。
可能每個表分片維度不一樣,會導致資料分佈到不同的機器上,這樣就需要跨伺服器事務一致性的保障,所以業務就不能再依賴於資料庫的事務,需要通過其他機制的來保證。
還有Order by 、Group by會受到限制,如果你查Top10的話,DAL只會在一個分片上把Top10給到你,但並非是全域性的。雖然有這些限制,但是與DAL帶來的好處比是完全可以接受的。
2)DRC
資料同步元件DRC,實現的功能是在一邊機房接受變更日誌,並把變更日誌傳遞到其他的機房去,其他機房再能把這個變更應用上。
為什麼用DRC元件而不用MySQL原生複製呢?
因為我們的鏈路是跨機房跨地域的,上海和北京遠距離的傳輸下,使用原生複製的話缺乏靈活性。
比方MySQL會產生各種各樣的訊息,尤其是做維護操作時要加欄位的話,會產生大量的變更日誌,這時直接傳遞就會導致網路直接堵死,在北京和上海的頻寬就5~10G的情況下,一個DDL變更100G的表,會把頻寬打滿,這樣很容易造成大的故障。
而且用DRC還可以做很多事情:
-
比如說無用訊息的過濾,MySQL平時會產生很多通知訊息,但我們只需要資料變更的訊息,就只需要傳遞變更資訊;
-
可以做資料包的壓縮,還可以做維護操作的過濾。維護操作可以在兩個機房同時進行,並且不希望用複製的方式來傳遞,這樣的話避免了在維護上產生大量的變更訊息,導致網路阻塞等問題;
-
再比如說資料發生衝突了該怎麼處理?還有怎麼避免資料的環路。如果變更日誌A寫在上海機房,但是A變更傳遞到北京機房後,又會更新北京機房的日誌,A又會通過北京機房的變更重新傳回到上海機房,這樣就是環路了;DRC會對相應的變更來源打上標籤,這樣資料就可以控制不回到自己產生的機房裡。
二、可用性
下一步是怎麼提高資料庫的可用性。
整個網站的可用性是由多部分完成的,資料庫只是其中的一塊,所以資料庫可用性要做到比整體可用性更高,比如做三個九的網站可用性,那底層需要四個九,甚至五個九的可用性來保證。
1、 架構
我們都知道物理上的故障是不可避免的,任何一臺機器都有可能出現故障,任何一個裝置都有可能故障,所以我們需要針對可能出現故障的地方都有相應的高可用方案。
EMHA
一臺Master機器出故障的時候我們的HA基於開源MHA改造的EMHA;在每個機房裡EMHA管理每個機房Master出現故障時的切換,也不光是隻負責出故障的切換,還要求控制切換時間在30s左右,同時要把故障拋給其他需要通知到的地方。
比如代理就要知道這臺Master已經掛了後新的Master是誰,所以EMHA切換時需要把訊息擴散出去,讓所有需要資訊的元件、環節都能接受到資訊。
這樣就能達到主庫掛的時候對業務的影響非常小(可能業務都沒有感知),DB切換同時自動完成切元件的對接,由此來提高可用性。
多分片方案
如果對下單業務沒有辦法做到機器不出故障,但希望出故障時影響非常小,可以做分片方案。
比如說分成了10個片放10臺機器上,這個時候一臺機器出故障影響的是1個片,整體只會影響十分之一的業務。如果你把片分得足夠小的話影響的範圍會變得更小,我們對關鍵的業務會進行更細的分片,一個片壞了也只能影響1/n的業務。
異地多活
異地多活後一個機房出問題不會受到多大影響,因為機房間切換的時間就在幾分鐘內能完成,這就能讓系統Online的時間大大提高。
另外,做重要維護的時候可以把一個機房的流量全切走,在沒有流量的機房做相應的維護動作,維護完成之後再把流量切過來,然後操作另外的機房,這樣風險特別高的維護操作也不用做關站處理。
一般大型一點的網站做一次關站維護需要的時間很長;以上這些點是從架構上能把可用性一層一層往上提。
下面我們再看下從故障發現和處理的角度怎麼提高可用性。
2、 故障
可用性還有很重要的點——既然故障不可避免,那我們就要追求如何快速地發現問題,解決問題。
Trace
-
全鏈路跟蹤從應用(appid)一直下串到DB,包括有接入層、應用層、中間層、服務層、代理層、快取層、資料庫層等串聯起來;
-
TraceID能提供正反向異常互推能力:ID會從上往下串,不管你在哪一層發現的問題,拿到ID就可以檢視鏈路上哪些環節有問題(哪個環節耗時最長或者出異常),這樣就可以及時地定位問題。
如果每個地方各查各的話,時間消耗是很長的,有Trace系統後,定位問題的效率會提高很多。
還有在資料庫層面來看80%~90%的問題都是SQL問題,如果能及時獲取有問題SQL,判斷這個SQL的來源,並對某些非關鍵的問題SQL進行限流或者攔截訪問的話,就能隔離問題SQL的影響,減少DB故障。
VDBA
我們在資料庫層開發了一個VDBA的自動處理程式,它會不停地對所有的資料庫進行掃描,根據我們制定的規則判斷狀態,如果發現有問題的SlowSQL會根據引起異常的程度進行限流、查殺、拒絕等操作。
當然VDBA能處理的不僅僅是SlowSQL,還有系統出現堵塞了,有未提交的事務、複製中斷、Blocked、bionlog太大了需要清理等都能處理。很多事情讓VBDA自動處理後,不僅效率提高了,也大大減少人操作的風險。
在故障處理時加快故障的定位時間和故障自動處理的機制後,可用性會得到明顯的提升。
三、資料流
資料流控制也依賴於剛剛所說的一些組建。
作為資料的管理人員,理論上應該有自己的手段來控制什麼樣的資料能進入,什麼樣的SQL能通過,要以什麼樣的方式來儲存等。把控不是說你寫寫文件就能把控住的,需要有相應強制的手段和工具。
每個業務訪問資料庫能使用多少連線、帳號許可權是什麼樣的都需要有比較標準的控制,這樣能夠讓所有資料在進來的時候就能夠在DBA的掌控當中。
資料進來以後需要生產落地儲存,落地後的資料也需要再傳遞到其他地方,這些都需要有相應的控制; 比如說現在大資料要拿資料,我們就可以通過drc的訊息來推送給大資料,這樣就不需要再掃描資料庫來拿資料了;原來的大資料通過sqoop任務都是隔天隔小時拉取資料,但現在可以做到實時的資料傳遞,做營銷活動時可以實時看到營銷的效果。
資料產生後還可能需要對外提供,如要把生產的資料同步到測試環境和開發環境;這個時候可以由DataBus來幫你同步資料,生產資料外傳需要做資料脫敏和清洗操作(尤其是手機號、身份證號)。原來是比較麻煩的,現在研發只需要管同步的配置資訊就可以了,元件會自動脫敏和清晰,非常方便,也符合安全的規範。
四、運維提效
重點講一下關於運維提效:在一個有上千號研發人員公司,如果只有一堆規範文件之類的來維護規則是很難把控的,因為人員有離職的、新進入的,不可能跟每個人都去宣傳,所以必須要有平臺來管控。
1、SQL治理
首先在SQL釋出的時候,我們平臺上的釋出工具裡面會內嵌需要遵循的標準,如果表建的時候不符合標準是沒法生產提交的,這樣就強制地把規則和標準變成硬性要求,SQL還可以自動實現稽核也節省了DBA很多時間。
另外,生產一旦出現變慢的SQL後,監控系統會馬上把訊息push給研發,如果影響到生產運作的話會直接拒掉、查殺掉。比方我們定義超過30秒的SQL是不允許上產生的,這類SQL會被直接殺掉,這樣可以大大減少生產的風險。
2、自助釋出
很多公司的DBA大部分時間在稽核SQL和釋出SQL,而我們的SQL都是研發自助釋出的,不需要DBA操心。
我們平臺支援原生、PT執行、mm-ost執行(餓了麼自行改造的資料庫多機房同步釋出工具),釋出平臺會幫他們計算好你的釋出大概需要多長時間,甚至會給你判斷什麼時候是業務低峰(那個時候會發布比較好),這樣研發對自己的釋出也是比較有把控力的。
3、自助歸檔
歸檔操作也是個比較頻繁的需求,一旦生產產生大量資料後,就需要做冷熱資料分離,要把不需要經常用的資料搬走。原來這個操作比較費勁的,需要DBA跟在後面做很多事情,而現在只需要研發自助解決。
如果你的表超過1000萬就需要部署歸檔任務了,這個時候會推送訊息給研發告訴他你的表已經超過標準了,需要部署歸檔任務,研發自己就可以在平臺上把表的歸檔規則填上去,完成審批後後臺幫你自動地做這件事情了。
還有關於DB的備份和恢復,一旦資料庫部署到生產後,在後臺的系統裡會幫你自動地部署備份和恢復任務和自動校驗可用性,你還可以在平臺上完成資料的回檔,一旦資料刷錯了、寫錯了通過平臺就能找回。
4、資料保障和遷移
對DBA來講需要把一個數據庫從這臺機器搬到另外的機器上,需要把一個大表拆分成多張小表,類似的動作就需要搬資料。
我們做了資料搬遷的工具,你只需要做配置就可以了,配置完成之後可以自動搬資料了,也會減少DBA很多工作量。
5、雲實踐
現在餓了麼所有的開發測試環境都是在雲上的,效率比自己做環境高很多,隨時需要隨時拿,用完隨時釋放。
另外還可以做彈性,彈性伸縮比較難,現在我們也沒有完全實現,但正在朝著這個方向努力;我們業務的曲線是午高峰和晚高峰,這個時候流量很大,彈性排程需要在業務高峰的時候把機器加上,在業務低峰的時候把機器回收回去,提高機器的利用率。
雲機房後面會承載我們主要的流量,雲機房的好處是底層管理不需要自己負責,擴容資源比較方便,這樣能提高交付的效率。
在雲上的機房可以灰度引流,剛開始可以很少的流量去做,當我們覺得它很穩健之後就可以把流量逐步往上遷,這樣能逐步把雲平臺的優勢利用起來,把資源動態伸縮的環境利用起來,同時也能控制風險。
所以,現在利用雲來提高運維效率是很好的手段。
五、建議原則
總結一下,從我們做這些事情裡面抽取我個人感覺比較重要的點是什麼呢?
最小可用性原則
不管是對帳號的處理、連線的處理、SQL的標準都應該有比較嚴格的限制,不能使用太多的資源,也不應該佔用太多的資源。
最小可用性原則就是你的連線數平時只用20個,那我給你40個,有一倍波動的空間就可以了。還有帳號許可權只需要增、改、查的許可權,這樣就不會給你刪除的許可權。
Design for Failure
這是我們CTO經常講的,設計環節不管是在運維規劃還是程式碼的環節都應該考慮接受失敗的情況。
不管是物理層面還是架構層面的基礎設施一定會出現問題,這個時候優良的架構必須要考慮應對錯誤情況,確保這類波動和短暫的問題能做到容錯和隔離,不至於導致整體的崩潰,同時具備快速恢復的能力。
標準、流程、自動(助)、量化
一開始應該設定好標準,接著把標準拆解成流程,再把流程做成自動化、自助化的處理,進而達到維持整體標準的不變形,同時提高效率的目的,最好能做到可量化。
比如去年我們維護100個DB例項需要兩個DBA,今年效率提升後也許一個就可以了,量化反過來也能促進運維效率的提升(可以知道哪些環節最消耗人力和資源,針對性的優化後效率就提高了)。
灰度、限流、熔斷、隔離
變更是系統穩定性的很大變數,想要提高整體的可用性必須對變更環節有苛刻的限制要求,比方我們要求所有的釋出必須先灰度,灰度完成之後在發一邊的機房,然後再全量化,要有快速回退手段;然後程式要求有過載保護處理,具備限流、熔斷和隔離等兜底措施。
穩定、效率、成本
這三點應該是企業對技術部門的核心訴求,也是有追求的技術團隊不斷努力的方向。
要方向,更要落地
今天介紹的內容經歷過的人其實都知道每一步都不容易,對於基礎設施還很薄弱的公司來講,最重要的還是考慮自己能夠用得上的,先要有落腳點,哪怕從最基礎的問題開始,把問題一項一項解決。
然後再逐步完善,一步步的改變才能真正讓使用者、公司感覺到團隊的價值。所以講了這麼多,最重要的還是要落地。
今天我的分享就到這裡,謝謝大家!
Q&A
Q1: 有一個細節我想諮詢一下,DRC北京和上海是同步,如果造成兩邊資料不一致怎麼辦?因為同步肯定有時間的延遲,這種問題是怎麼解決的?
A1: 之前我也有專門講過多活情況下資料庫的方案,那裡會說的比較詳細一點。具體來講在怎麼同步資料、處理資料衝突是多活很重要的前提,那怎麼樣讓資料不衝突,即使衝突了怎麼受理?
我們多活流量分配原則是根據你所在的地理位置,同一個人在下單的時候在同一地方只會打到同一機房,所以下單當時產生的資料是在一個點一個機房的,而且其他操作我們就把使用者放到這個機房裡面,不可能說在這邊下完單在另外一邊支付,這在業務設計規則上是不允許的。業務設計規則上做到限制,下單、支付必須在一個機房完成。
之後在底層會做相應的保護,資料庫會設計每個機房的自身因子一樣但起始值不一樣,比方一個機房是1,一個機房是2,那邊永遠是單數,這邊永遠是雙數,這樣資料庫自己產生的主鍵值是不會衝突的。
還有像搶紅包這種事情在兩個機房都會搶,這樣的場景可能會造成衝突。這個時候可以根據最後修改時間做為有效值覆蓋另外的值。
所以首先是有設計原則,原則被突破後會針對衝突有相應的技術處理標準;兩個機房還會有元件保護機制,還有資料校驗,一旦發現有資料衝突的話會告警;有一些衝突系統可以自動處理,還有有些衝突必須要業務識別,因為不排除業務有違反設計的情況出現,這樣的衝突會拋給業務來處理,一旦大家通過沖突告警梳理後都按標準遵循這些規則,有衝突的概率是非常小的。
之前我們發現有衝突的情況大部分是業務違反了設計原則,比如說UK的表唯一值在這邊產生也在那邊產生,這樣的話資料就衝突了;如果業務能夠接受也可以做過濾,不能接受就會要求改造。
Q2: 如果我在上海下單,現在我去北京查不到單,這種情況下會有延遲嗎?
A2: 這個情況一般不會出現,我們的流量分流機制會保證使用者當前的所有操作只會在一個機房發生,而且正常DRC的延遲一般是秒級別,跨機房延遲現在基本在一秒之內,你從上海去北京肯定操作這個時間。
還有使用者在一個機房下單一般只需要一個機房的資料就足夠了,我們會在底層保證資料一致的;資料校驗是分鐘級別的,資料發生問題的話會馬上發現。
Q3: 像點餐也就3、4個小時的高峰,能介紹一下這樣的業務彈性場景嗎?
A3: 目前我們在資料層並不能做到彈性,但是在其他無狀態業務資源上是可以的,我們也還在研究當中。比方說現在有一套承載業務的叢集,我們的業務高峰在10點開始,在9點的時候會把資源加上去,原來有10臺,為了滿足業務高峰會加到50臺,在9點之前把資源加進叢集裡去。用完之後到下午3點可以再退出去。
Q4: 閒置的時候做什麼其他利用?每天只買雲資源的時間段計費?
A4: 這就是利用雲的好處,退出來以後雲就不會計費了,可以讓雲回收。但如果是自有機房自己的機房的話要看自己的需求,像阿里現在有在做類似的方案,會在業務低峰時候在業務機器上跑大資料計算提高資源利用率。可以每天只在買雲資源的時間段計費,但是控制需要做得比較好,需要的時候能加上去,不需要的時候能退出來。