第一次當架構師,我設計高并發架構發現了N個痛點......
一、寫在前面
之前更新過一個“億級流量系統架構”系列,主要講述了一個大規模商家數據平臺的如下幾個方面:
- 如何承載百億級數據存儲
- 如何設計高容錯的分布式架構
- 如何設計承載百億流量的高性能架構
- 如何設計每秒數十萬并發查詢的高并發架構
- 如何設計全鏈路99.99%高可用架構
接下來,我們將會繼續通過幾篇文章,對這套系統的可擴展架構、數據一致性保障等方面進行探討。
如果沒看過本系列文章的同學可以先回過頭看看之前寫的幾篇文章:
億級流量系統架構
- 別光看NB的Github開源項目,你得參考他們去設計自己的架構!
- 為什么有些看起來很厲害的技術高手,設計的架構都很垃圾?
- 為什么每個程序員都必須堅持寫博客?這篇文章教你怎么寫!
- 同事老是吐槽我的接口性能差,原來真兇就在這里!
- 2022經歷裁員之后,我總結了程序員必備的架構能力!
二、背景回顧
如果大家看過之前的一系列文章,應該依稀還記得上一篇文章最后,整個系統架構大致演進到了如下圖的一個狀態。
如果沒看過之前的系列文章,上來猛一看下面這個圖,絕對一臉懵逼,就看到一片“花花綠綠”。這個也沒辦法,復雜的系統架構都是特別的龐雜的。
三、實時計算平臺與數據查詢平臺之間的耦合
好,咱們正式開始!這篇文章咱們來聊聊這套系統里的不同子系統之間通信過程的一個可擴展性的架構處理。
這里面蘊含了線上復雜系統之間交互的真實場景和痛點,相信對大家能夠有所啟發。
我們就關注一下上面的架構圖里左側的部分,處于中間位置的那個實時計算平臺在完成了每一個數據分片的計算過后,都會將計算結果寫入到最左側的數據查詢平臺中。
出于種種考量,因為計算結果的數據量相比于原始數據的數據量,實際上已經少了一個數量級了。
所以,我們選擇的是實時計算平臺直接將數據寫入到數據查詢平臺的MySQL數據庫集群中,然后數據查詢平臺基于MySQL數據庫集群來對外提供查詢請求。
此外,為了保證當天的實時計算結果能夠高并發的被用戶查詢,因此當時采取的是實時計算平臺的計算結果同時雙寫緩存集群和數據庫集群。
這樣,數據查詢平臺可以優先走緩存集群,如果找不到緩存才會從數據庫集群里回查數據。
所以上述就是實時計算平臺與數據查詢平臺之間在某一個時期的一個典型的系統耦合架構。
兩個不同的系統之間,通過同一套數據存儲(數據庫集群+緩存集群)進行了耦合。
大家看看下面的圖,再來清晰的感受一下系統之間耦合的感覺。
系統耦合痛點1:被動承擔的高并發寫入壓力
大家如果仔細看過之前的系列文章,大概就該知道,在早期主要是集中精力對實時計算平臺的架構做了大量的演進,以便于讓他可以支撐超高并發寫入、海量數據的超高性能計算,最后就可以抗住每秒數萬甚至數十萬的數據涌入的存儲和計算。
但是因為早期采用了上圖的這種最簡單、最高效、最實用的耦合交互方式,實時計算平臺直接把每個數據分片計算完的結果寫入共享存儲中,就導致了一個很大的問題。
實時計算平臺能抗住超高并發寫入沒問題了,而且還能快速的高性能計算也沒問題。
但是,他同時會隨著數據量的增長,越來越高并發的將計算結果寫入到一個數據庫集群中。而這個數據庫集群在團隊劃分的時候,實際上是交給數據查詢平臺團隊來負責維護的。
也就是說,對實時計算平臺團隊來說,他們是不care那個數據庫集群是什么狀態的,而就是不停的把數據寫入到那個集群里去。
但是,對于數據查詢平臺團隊來說,他們就會被動的承擔實時計算平臺越來越高并發壓力寫入的數據。
這個時候數據查詢平臺團隊的同學很可能處于這樣的一種焦躁中:本來自己這塊系統也有很多架構上的改進點要做,比如說之前提到的冷數據查詢引擎的自研。
但是呢,他們卻要不停的被線上數據庫服務器的報警搞的焦頭爛額,疲于奔命。
因為數據庫服務器單機寫入壓力可能隨著業務增長,迅速變成每秒5000~6000的寫入壓力,每天到了高峰期,線上服務器的CPU、磁盤、IO、網絡等壓力巨大,報警頻繁。
此時數據查詢平臺團隊的架構演進節奏就會被打亂,因為必須被動的去根據實時計算平臺的寫入壓力來進行調整,必須立馬停下手中的工作,然后去考慮如何對數據庫集群做分庫分表的方案,如何對表進行擴容,如何對庫進行擴容。
同時結合分庫分表的方案,數據查詢平臺自身的查詢機制又要跟著一起改變,大量的改造工作,調研工作,數據遷移工作,上線部署工作,代碼改造工作。
實際上,上面說的這種情況,絕對是不合理的。
因為整個這套數據平臺是一個大互聯網公司里核心業務部門的一個核心系統,他是數十個Java工程師與大數據工程師通力合作一起開發,而且里面劃分為了多個team。
比如說數據接入系統是一個團隊負責,實時計算平臺是一個團隊負責,數據查詢平臺是一個團隊負責,離線數據倉庫是一個團隊負責,等等。
所以只要分工合作了以后,那么就不應該讓一個團隊被動的去承擔另外一個團隊猛然增長的寫入壓力,這樣會打破每個團隊自己的工作節奏。
導致這個問題的根本原因,就是因為兩個系統間,沒有做任何解耦的處理。
這就導致數據查詢平臺團隊根本無法對實時計算平臺涌入過來的數據做任何有效的控制和管理,這也導致了“被動承擔高并發寫入壓力”問題的發生。
這種系統耦合導致的被動高并發寫入壓力還不只是上面那么簡單,實際在上述場景中,線上生產環境還發生過各種奇葩的事情:
某一次線上突然產生大量的熱數據,熱數據計算結果涌入數據查詢平臺,因為沒做任何管控,幾乎一瞬間導致某臺數據庫服務器寫入并發達到1萬+,DBA焦急的擔心數據庫快宕機了,所有人也都被搞的焦頭爛額,心理崩潰。
系統耦合痛點2:數據庫運維操作導致的線上系統性能劇烈抖動
在這種系統耦合的場景下,反過來實時計算平臺團隊的同學其實心里也會吶喊:我們心里也苦啊!
因為反過來大家可以思考一下,線上數據庫中的表結構改變,那幾乎可以說是再正常不過了,尤其是高速迭代發展中的業務。
需求評審會上,要是不小心碰上某個產品經理,今天改需求,明天改需求。工程師估計會怒火沖天的想要砍人。但是沒辦法,最后還是得為五斗米折腰,該改的需求還是得改。該改的表結構也還是要改,改加的索引也還是要加。
但是大家考慮一個點,如果說對上述這種強耦合的系統架構,單表基本都是在千萬級別的數據量,同時還有單臺數據庫服務器每秒幾千的寫入壓力。
在這種場景下,在線上走一個MySQL的DDL語句試一試?奉勸大家千萬別胡亂嘗試,因為數據查詢團隊里的年輕同學,干過這個事兒。
實際的結果就是,DDL咔嚓一執行,對線上表結構進行修改,直接導致實時計算平臺的寫入數據庫的性能急劇下降10倍以上。。。
然后連帶導致實時計算平臺的數據分片計算任務大量的延遲。再然后,因為實時計算之后的數據無法盡快反饋到存儲中,無法被用戶查詢到,導致了大量的線上投訴。
并且,DDL語句執行的還特別的慢,耗時數十分鐘才執行完畢,這就導致數十分鐘里,整套系統出現了大規模的計算延遲,數據延遲。
一直到數十分鐘之后DDL語句執行完畢,實時計算平臺才通過自身的自動延遲調度恢復機制慢慢恢復了正常的計算。
orz......于是從此之后,數據查詢平臺的攻城獅,必須得小心翼翼的在每天凌晨2點~3點之間進行相關的數據庫運維操作,避免影響線上系統的性能穩定性。
但是,難道人家年輕工程師沒有女朋友?難道年長工程師沒有老婆孩子?經常在凌晨3點看看窗外的風景,然后打個滴滴回家,估計沒任何人愿意。
其實上述問題,說白了,還是因為兩套系統直接通過存儲耦合在了一起,導致了任何一個系統只要有點異動,直接就會影響另外一個系統。耦合!耦合!還是耦合!
系統耦合痛點N。。。
其實上面只不過是挑了其中兩個系統耦合痛點來說明而已,文章篇幅有限,很難把上述長達數月的耦合狀態下的各種痛點一一說明,實際線上生產環境的痛點還包括不限于:
- 實時計算平臺自身寫入機制有bug導致的數據丟失,結果讓數據查詢平臺的同學去排查
- 實時計算平臺對緩存集群和數據庫集群進行雙寫的時候,雙寫一致性的保證機制,居然還需要自己來實現,直接導致自己的代碼里混合了大量不屬于自己的業務邏輯
- 數據查詢平臺有時候做了分庫分表運維操作之后,比如擴容庫和表,居然還得讓實時計算平臺的同學配合著一起修改代碼配置,一起測試和部署上線
- 數據查詢平臺和實時計算平臺兩個team的同學在上述大量耦合場景下,經常天天一起加班到凌晨深夜,各自的女朋友都以為他們打算在一起了,但實際情況是一堆大老爺兒們天天被搞的焦頭爛額,苦不堪言,都不愿意多看對方一眼
- 因為系統耦合導致的各種問題,兩個team都要抽時間精力來解決,影響了自己那套系統的架構演進進度,沒法集中人力和時間做真正有價值和意義的事情?