高併發系列: 存儲優化之也許可能是史上最詳盡的分庫分表文章之一
趣味性不強,但知識性很強,建議耐心看或者先收藏
本文內容預覽:
庫表會在哪天到達瓶頸?
1.1 蘇寧拼購百萬級庫表拆分之前
1.2 京東配運平臺庫表拆分之前
1.3 大衆點評訂單庫拆分之前
1.4 小結:啥情況需要考慮庫表拆分
拆分庫表的目的和方案
2.1 業務數據解耦--垂直拆分
2.2 解決容量和性能壓力--水平拆分
2.3 分多少合適
2.4 怎麼分合適
拆分帶來新的問題
分區鍵/唯一ID/數據遷移/分佈式事務等
大廠案例,知識回顧擴展
4.1 螞蟻金服的庫表路由規則
4.2 大衆點評分庫分表的數據遷移
4.3 淘寶萬億級交易訂單的存儲引擎
Part1 庫表會在哪天到達瓶頸?
1.1 蘇寧拼購百萬級庫表拆分之前 [1]
蘇寧拼購,蘇寧易購旗下的電商 App,18 年 7 月累計用戶突破 3000 萬。
圖片來源於 QCon 大會 PPT
龐大的數據量,對數據庫壓力和數據運維成本造成了很大的困擾,並且,一旦有一條未命中緩存的 SQL,對於整個應用都是災難級的。
所以,不得不考慮系統的穩定性和長遠的業務支撐。
1.2 京東配運平臺庫表拆分之前 [2]
圖片來源於 QCon 大會 PPT
起初,用 SQL Server 存儲,⽀支撐每天 10 萬級別業務量。
扛不住後,採購了企業級 Oracle/IBM AIX ⼩型機,用 RAC + DataGuard 方式,支撐配送所有業務,到百萬級別單量。但是這種傳統的企業架構,對於複雜多變的業務、昂貴的硬件成本、服務的部署和維護成本等痛點,變得越來越突出。
15 年開始,京東配運平臺開始按業務對數據庫做垂直拆分,將存儲容器化,實現了方便的水平擴容、更精細的成本控制、更復雜的業務形態支持.
1.3 大衆點評訂單庫拆分之前 [3]
16 年前,點評的訂單庫已經超 200G 容量,面對的越來越複雜的查詢維度,爲實現平穩查詢,優化了索引並增加兩個從庫來分散數據庫壓力,但仍有很多效率不理想的數據庫請求出現。
而隨後而來的價格戰、大量搶購的活動開展,訂單數據庫很快難以支撐,只能用限流、消息隊列削峯填谷對其進行保護,才能勉強維持日常數據讀寫需求。
而隨着業務模式的增加,原訂單模型已經不能滿足,如果經常用 DDL 去建表,建索引對於如此龐大的庫表是非常喫力的,發生鎖庫鎖表會直接影響線上服務。
所以,點評團隊以未來十年不再擔心訂單容量爲目的,開始進行庫表切分。
1.4 小結:啥情況需要考慮庫表拆分
實際上,是沒有一個非常量化的指標來判定庫表瓶頸的,因爲每個系統的業務場景,查詢複雜度都有不同。
但力有窮盡時,我們雖然可以儘量的從加從庫讀寫分離、優化 sql、優化索引、複用連接等等方面進行優化,但總會有到達極限的時候的時候,量變引發質變。甚至,在真實生產環境,要更加未雨綢繆,不能等到崩了纔去考慮。那麼,應該怎麼去判斷已經到了庫表拆分的時機呢:
-
硬件性能瓶頸,如果是讀操作多,其實可以加多個從庫分擔主庫讀壓力;但如果是寫操作多,會因爲主庫磁盤 IO 增大,拖慢處理速度;另外,如果單表數據量過大,導致索引層級增多,掃描行增多,CPU 效率降低,影響 sql 執行效率,拖慢處理速度。而處理速度慢最終會導致連接數增加直至無連接可用。
-
日常運維投入,就如蘇寧拼購的情況,如果一個月就要搞一次數據遷移,這個人力的投入產出比,應該是完全不匹配的,那就不如一次性搞定它。
-
業務發展可支持程度、難度和風險,當數據增長到一定程度,雖然沒有達到極限,還能湊活,但是遇到活動型流量脈衝,無法完全支持業務需求;而業務需要進行迭代增加模式時,修改數據錶帶來的風險又比較大。就可以考慮重構數據模型,拆分庫表了。
Part2 拆分庫表的目的和方案
2.1 業務數據解耦 -- 垂直拆分
把不同的業務數據拆分到各自的數據庫中獨立維護,那麼最底層的原因是什麼呢?
是微服務下的上層服務拆分。爲了滿足快速迭代、安全發佈、鏈路降級、主次業務解耦等問題,去解決代碼大量衝突、小功能排隊等待大版本發佈等等問題,將業務按照一定邏輯進行拆解,形成一個個功能完備,獨立運行的服務。[4]
然而,如果數據庫層面不配合,就無法解決根本問題。當上層服務實例拆分後可以被大量橫向擴展,以應對高併發的流量衝擊,會導致底層數據庫的承載壓力和連接數急劇增加。
所以,通過垂直拆分將業務數據解耦,各管一事,以滿足微服務的效能最大化。
2.2 解決容量和性能壓力 -- 水平拆分
對某一業務庫,當數據增量達到了庫瓶頸,或者表瓶頸,就要進行庫表的水平拆分了。
我之前遇到的很多情況,總是先分表,解決單表的容量和讀寫性能問題,隨着業務發展,單庫也遇到瓶頸了再考慮分庫。
爲啥不一步到位?
就像之前在阿里,新應用上來搞個百庫百表?一來是因爲一些用戶規模和一些路由規則的問題;更重要的,不是所有公司其實不是所有的公司都和阿里一樣有錢,有限的資源要用在更重要的生存問題上。
如果你作爲一個初創公司的架構,給出了一套可能撐 10 年的存儲方案,感覺會被同事在心裏懟,公司能活 3 年麼就這麼浪費?
但肯定沒有人說這話,因爲我們還是希望所有公司都能蓬勃發展,蒸蒸日上的☺。
所以,拆分方法就很有講究了,怎麼分能讓後續迭代發展的代價最小呢?
2.3 分多少合適
表主要看容量,很多經驗表明 上千萬後性能會有顯著下降,因此,我們可以把表容量定在一半多一點,600w。
庫主要看的是連接數,我們以阿里對外售賣的雲存儲來大致估計,單庫的連接數定在 4000 左右。
抽象一個實際的評估案例來看:假如目前平臺每天產生 10w 訂單,峯值併發數 8000QPS,然後考慮業務擴展和增長的速率:
比如,業務是和銀行合作擴展業務,將大小銀行量級平均一下,估計每合作一家可以帶來多大的增長量,這裏假設是 5000 單 / 天 / 家,如果業務計劃是每年度合作 10 家,那就是 5w,5 年以後每天的單量,理論上可能會到 25w / 天。加上現有的 10w, 峯值 35w。
如果我們計劃系統的容量需要支撐 3 年,或者說,3 年之後的該業務擴展會趨於平緩,那麼我們可以大致的估計爲:
表:(3年 * 365天 * 35w=3.8億 )/600w = 63 約 64張表.
庫:10000併發 / 4000 = 2.5 ,可按4個庫來處理
當然,如果是 BAT 這種,不缺用戶,不缺錢,又有一些既定路由規則的情況,還是可以一步到位的。比如,我之前做過的項目就是按百庫百表來做。關於阿里的玩法後面再詳細介紹一下。
發現上述評估有問題的話,歡迎留言討論~
2.4 怎麼分合適
Hash 取模
優點:經過 hash 取模之後,分到庫和分到表中的數據,都是均衡的,所以,不會出現資源傾斜的問題。
缺點:如果後續遇到業務暴增,沒有在我們預估範圍內,則要涉及到數據遷移,那就需要重新 hash , 遷移數據,修改路由等等。
range 劃分
優點:不需要數據遷移,後續數據即時增長很多也沒問題。
缺點:數據傾斜嚴重,比如上圖,很長一段時間,都會只用到 1 個庫,幾個表。
一致性 hash
優點:更加均勻,並且在需要擴容時,數據遷移的量級更小,只需要遷移 1/N 的數據即可。
缺點:路由算法要複雜,但是對於能得到的好處,這點複雜度就可以忽略了
小結
那麼, 看起來,一致性 hash 的方法,是比較靠譜的了。但是隻是這樣就會對程序員很友好麼?
我不知道其他公司,呆過的某一家公司,的數據查詢後臺是純天然的,不帶任何修飾的,想要 check 下數據,得拿業務 ID 手動計算庫表的位置。沒經歷過的不知道,真的是要煩死了。
在技術設施方面,還是不得不佩服大公司的投入,阿里給工程師提供的數據查詢後臺,其實是一個邏輯庫,你可以用查詢單表的方式去查詢分庫分表,後臺會調用數據庫配置平臺的配置,自動計算庫表路由,人性化的很。就算不去計算路由,直接打包查詢多個庫也是很好的,畢竟界面查詢,能有多大併發呢。
還是那句話,沒有銀彈,其實除了這幾種方式,還見過不少變種,但都是結合本公司,本業務的特性進行的改良。
Part3 拆分帶來新的問題
分區鍵選取
分區鍵要足夠的均勻,比如,用戶表用 UID,訂單表可以用 UID,也可以用訂單 ID,商戶表用商戶 ID,問題表用會話 ID 等等,總之,一定可以找到業務上的唯一 ID。當然還有一些特殊的分區,比如,日表,月表,則要按時間來分,等等。
全局唯一主鍵 ID
實際我理解這個就是分佈式 ID 的生成問題,之前寫的一篇分佈式 ID 生成算法,有興趣可以瀏覽下。
數據平滑遷移
停機發布:好處是簡單,風險小;缺點是業務有損。那就看這個損能不能接受了
平滑遷移:平滑遷移就像是高速上換輪胎,要非常小心謹慎,也更復雜。思路可以類比快手 kafka 集羣的擴容:
雖然場景不一樣,但是思路使一致的。從某一點開始設置 checkpoint , 然後執行數據雙寫,最後修改路由,刪除舊數據,完成擴容。
事務問題
之前由於數據都在一個庫中,所以,只要保證一個本地事務就可以辦到。現在數據被分到了多個庫,那麼事務怎麼保證:
(1)分佈式事務。分佈式事務的方式很多,TCC、本地事務表 + 事務消息、最大努力通知,saga 等等,之前有篇寫我們自研的 saga 長事務引擎的文章,有興趣的可以看下。
(2)程序 + 業務邏輯。用業務邏輯 + 程序控制的方式,比如,之前文章中提到的微信紅包的系統設計,用 set 化將一個紅包的所有操作都落到同一個庫上,避免了數據庫鎖競爭和分佈式事務。而螞蟻的支付業務涉及了業務訂單庫、計收費庫、支付庫、積分庫等等,沒有辦法從業務邏輯層面進行完全串聯,並且由於金融屬性的強一致要求,採用了非常重的侵入式 TCC 來保證全局支付事務的一致。
查詢問題
之前一個庫就能搞定的 join,count 等各種聯合查詢,將不復存在,老老實實調接口在代碼層面實現吧。
Part4 大廠案例,知識回顧擴展
4.1 螞蟻金服的庫表路由規則
上文也提到過,螞蟻的分庫分表其實是獨樹一幟的。因爲,在螞蟻體系下,需要遵守 LDC 單元化部署,單元化的路由有用戶 ID 的倒數 2,3 位來決定。加上螞蟻的用戶規模,基本上大部分的應用都採用了百庫百表類的方式進行 (遇到定時任務的超大規模數據,還會千庫千表的存在)。用戶請求發起後的路由規則和數據庫的路由執行鏈路簡化如下:
螞蟻中間件產品介紹
這樣的機制保證生成的 ID 支持 10 萬億次獲取不重複。
有人可能會問,這個大的訂單量,一個庫也撐不了多久啊?
是的,比如之前搞的一個應用,其實是百庫百表 + 定時數據遷移來實現的。業務數據每固定時間進行歷史表遷移。而查詢的時候的庫表路由,都由中間件 ZDAL 從配置平臺拉取配置來決定,是走歷史庫還是走當前庫。
4.2 大衆點評分庫分表的數據遷移
-
階段一:數據雙寫,以老數據爲準。通過對賬補平差異
-
階段二:導入歷史數據,繼續雙寫,讀切到新數據。
-
階段三:停掉雙寫,刪除老數據完成遷移
4.3 淘寶萬億級交易訂單的存儲引擎 [6]
淘寶超級量級下的交易單是怎麼解決存儲性能等問題的:
Part5 總結
一篇文章不可能窮盡所有知識點,如有遺漏和錯誤,歡迎補充和指正,原創不易,歡迎轉發,留言討論~
參考資料
[1]
日均百萬訂單下的高可用蘇寧拼購系統架構設計. 朱羿全: QCon 技術峯會分享
[2]
支撐億級運單的配運平臺架構實踐. 趙玉開: QCon 技術峯會分享
[3]
大衆點評訂單系統分庫分表實踐: https://tech.meituan.com/2016/11/18/dianping-order-db-sharding.html
[4]
如何做好服務拆分: http://dockone.io/article/8241
[5]
螞蟻金融中間件產品介紹: https://tech.antfin.com/docs/2/46921
[6]
阿里雲數據庫 RDS 產品介紹: https://help.aliyun.com/document_detail/161461.html
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/q_MMXEphKl56ngLy8R6jmg