業務架構優化之路

2021-07-16 02:30:28 字數 3397 閱讀 8392

im系統,例如qq或者微博,每個人都讀自己的資料(好友列表、群列表、個人資訊)。

微博系統,每個人讀你關注的人的資料,乙個人讀多個人的資料。

秒殺系統,庫存只有乙份,所有人會在集中的時間讀和寫這些資料,多個人讀乙個資料。

例如小公尺手機每週二的秒殺,可能手機只有1萬部,但瞬時進入的流量可能是幾百幾千萬。又例如12306搶票,票是有限的,庫存乙份,瞬時流量非常多,都讀相同的庫存。讀寫衝突,鎖非常嚴重,這是秒殺業務難的地方。那我們怎麼優化秒殺業務的架構呢?

優化方向有兩個:

將請求盡量攔截在系統上游(不要讓鎖衝突落到資料庫上去)。傳統秒殺系統之所以掛,請求都壓倒了後端資料層,資料讀寫鎖衝突嚴重,併發高響應慢,幾乎所有請求都超時,流量雖大,下單成功的有效流量甚小。以12306為例,一趟火車其實只有2000張票,200w個人來買,基本沒有人能買成功,請求有效率為0。

充分利用快取,秒殺買票,這是乙個典型的讀多些少的應用場景,大部分請求是車次查詢,票查詢,下單和支付才是寫請求。一趟火車其實只有2000張票,200w個人來買,最多2000個人下單成功,其他人都是查詢庫存,寫比例只有0.1%,讀比例佔99.9%,非常適合使用快取來優化。好,後續講講怎麼個「將請求盡量攔截在系統上游」法,以及怎麼個「快取」法,講講細節。

常見的站點架構基本是這樣的(特別是流量上億的站點架構):

瀏覽器端,最上層,會執行到一些js**

站點層,這一層會訪問後端資料,拼html頁面返回給瀏覽器

服務層,向上游遮蔽底層資料細節,提供資料訪問

資料層,最終的庫存是存在這裡的,mysql是乙個典型(當然還有會快取)

這個圖雖然簡單,但能形象的說明大流量高併發的秒殺業務架構,大家要記得這一張圖。

後面細細解析各個層級怎麼優化。

如果均成功再放下一批,如果庫存不夠則佇列裡的寫請求全部返回「已售完」。

對於讀請求,怎麼優化?cache抗,不管是memcached還是redis,單機抗個每秒10w應該都是沒什麼問題的。如此限流,只有非常少的寫請求,和非常少的讀快取mis的請求會透到資料層去,又有99.9%的請求被攔住了。

當然,還有業務規則上的一些優化。回想12306所做的,分時分段售票,原來統一10點賣票,現在8點,8點半,9點,...每隔半個小時放出一批:將流量攤勻。

其次,資料粒度的優化:你去購票,對於餘票查詢這個業務,票剩了58張,還是26張,你真的關注麼,其實我們只關心有票和無票?流量大的時候,做乙個粗粒度的 「有票」「無票」快取即可。

第三,一些業務邏輯的非同步:例如 下單業務與 支付業務的分離。這些優化都是結合 業務 來的,我之前分享過乙個觀點「一切脫離業務的架構設計都是耍流氓」架構的優化也要針對業務。

瀏覽器攔截了80%,站點層攔截了99.9%並做了頁面快取,服務層又做了寫請求佇列與資料快取,每次透到資料庫層的請求都是可控的。db基本就沒什麼壓力了,閑庭信步,單機也能扛得住,還是那句話,庫存是有限的,小公尺的產能有限,透這麼多請求來資料庫沒有意義。

全部透到資料庫,100w個下單,0個成功,請求有效率0%。透3k到資料,全部成功,請求有效率100%。

上文應該描述的非常清楚了,沒什麼總結了,對於秒殺系統,再次重複下我個人經驗的兩個架構優化思路:

盡量將請求攔截在系統上游(越上游越好);

讀多寫少的常用多使用快取(快取抗讀壓力);問題1、按你的架構,其實壓力最大的反而是站點層,假設真實有效的請求數有1000萬,不太可能限制請求連線數吧,那麼這部分的壓力怎麼處理?

答:每秒鐘的併發可能沒有1kw,假設有1kw,解決方案2個:

站點層是可以通過加機器擴容的,最不濟1k臺機器來唄。

如果機器不夠,拋棄請求,拋棄50%(50%直接返回稍後再試),原則是要保護系統,不能讓所有使用者都失敗。

問題2、「控制了10w個肉雞,手裡有10w個uid,同時發請求」 這個問題怎麼解決哈?

答:上面說了,服務層寫請求佇列控制

問題3: 限制訪問頻次的快取,是否也可以用於搜尋?例如a使用者搜尋了「手機」,b使用者搜尋「手機」,優先使用a搜尋後生成的快取頁面?

問題4:如果佇列處理失敗,如何處理?肉雞把佇列被撐爆了怎麼辦?

答:處理失敗返回下單失敗,讓使用者再試。佇列成本很低,爆了很難吧。最壞的情況下,快取了若干請求之後,後續請求都直接返回「無票」(佇列裡已經有100w請求了,都等著,再接受請求也沒有意義了)。

問題5:站點層過濾的話,是把uid請求數單獨儲存到各個站點的記憶體中麼?如果是這樣的話,怎麼處理多台伺服器集群經過負載均衡器將相同使用者的響應分布到不同伺服器的情況呢?還是說將站點層的過濾放到負載均衡前?

答:可以放在記憶體,這樣的話看似一台伺服器限制了5s乙個請求,全域性來說(假設有10臺機器),其實是限制了5s 10個請求,解決辦法:

加大限制(這是建議的方案,最簡單)

在nginx層做7層均衡,讓乙個uid的請求盡量落到同乙個機器上

問題6:服務層過濾的話,佇列是服務層統一的乙個佇列?還是每個提供服務的伺服器各乙個佇列?如果是統一的乙個佇列的話,需不需要在各個伺服器提交的請求入佇列前進行鎖控制?

答:可以不用統一乙個佇列,這樣的話每個服務透過更少量的請求(總票數/服務個數),這樣簡單。統一乙個佇列又複雜了。

問題7:秒殺之後的支付完成,以及未支付取消佔位,如何對剩餘庫存做及時的控制更新 ?

答:資料庫裡乙個狀態,未支付。如果超過時間,例如45分鐘,庫存會重新會恢復(大家熟知的「回倉」),給我們搶票的啟示是,開動秒殺後,45分鐘之後再試試看,說不定又有票喲。

問題8:不同的使用者 瀏覽同乙個商品 落在不同的快取例項 顯示的庫存完全不一樣 請問老師怎麼做快取資料一致 或者是允許髒讀?

答:目前的架構設計,請求落到不同的站點上,資料可能不一致(頁面快取不一樣),這個業務場景能接受。但資料庫層面真實資料是沒問題的。

問題9:就算處於業務把優化考慮 「3k張火車票,只透3k個下單請求去db」那這3k個訂單就不會發生擁堵了嗎?

答:(1)資料庫抗3k個寫請求還是ok的;(2)可以資料拆分;(3)如果3k扛不住,服務層可以控制透過去的併發數量,根據壓測情況來吧,3k只是舉例;

問題10:如果在站點層或者服務層處理後台失敗的話,需不需要考慮對這批處理失敗的請求做重放?還是就直接丟棄?

答:別重放了,返回使用者查詢失敗或者下單失敗吧,架構設計原則之一是「fail fast」。

問題11:對於大型系統的秒殺,比如12306,同時進行的秒殺活動很多,如何分流?

答:垂直拆分

問題12:額外又想到乙個問題。這套流程做成同步還是非同步的?如果是同步的話,應該還存在會有響應反饋慢的情況。但如果是非同步的話,如何控制能夠將響應結果返回正確的請求方?

答:使用者層面肯定是同步的(使用者的http請求是夯住的),服務層面可以同步可以非同步。

問題13:秒殺群提問:減庫存是在那個階段減呢?如果是下單鎖庫存的話,大量惡意使用者下單鎖庫存而不支付如何處理呢?

答:資料庫層面寫請求量很低,還好,下單不支付,等時間過完再「回倉」,之前提過了。

秒殺業務 架構優化之路

im 系統,例如qq 微博,每個人都讀自己的資料 好友列表 群列表 個人資訊 微博系統,每個人讀你關注的人的資料,乙個人讀多個人的資料。秒殺系統,庫存只有乙份,所有人會在集中的時間讀和寫這些資料,多個人讀乙個資料。例如小公尺手機每週二的秒殺,可能手機只有1w,但是瞬時進入的流量可能是幾百幾千萬。又例...

再談企業架構 業務架構

再談企業架構 業務架構 人月神話 前面已經談到過企業架構的層次和維度方面的問題,在這裡簡單談下企業架構中的業務架構和業務價值鏈方面的內容。隨著企業不斷的發展和演進,各個業務功能單元會逐步成熟,也會形成多個端到端的流程,這些流程涉及到工程專案管理,鏈,財務,人力資源,產品研發等多個方面的內容。我們再進...

業務系統優化

簡單系統優化 專案描述 公司oms業務系統執行過程中突然出現cpu爆滿異常,導致業務無法正常訪問。業務部門要求馬上解決此問題,恢復生產,並同時反饋最近部分業務訪問十分緩慢,要求可以針對某些特定業務做優化調整,提高業務人員的工作效率。責任描述 檢視dbtime發現超過1500,生成awr報告發現,sq...