java互聯網架構三板斧之併發

java互聯網架構三板斧之併發

	由於營銷活動(創造營銷節點、擴大影響力的需要),總有很多產品策劃、運營樂此不疲的玩著一個game---在足夠集中的時間內比如秒級處理足夠多的用戶請求,讓世界為此狂歡,同時也是彰顯技術實力的一次大考。

小米賣著搶號的手機、天貓發明了雙11光棍節、微信和支付寶連續2年做著新春紅包。營銷活動的時候要使用前2板斧,保證可用性和簡單可擴展性,同時還要祭出第三板絕殺—攔河大壩、緩存為王、去熱點資源的併發。

為啥要攔?很簡單,用戶很熱情(感性),但系統必須得理性!就3個蘋果手機,憑啥讓幾十萬人都湧入櫃檯!在大秒系統一文中許同學就娓娓道來(省得少畫個圖)……

java互聯網架構三板斧之併發

對大流量系統的數據做分層校驗也是最重要的設計原則,所謂分層校驗就是對大量的請求做成“漏斗”式設計,如上圖所示:在不同層次儘可能把無效的請求過濾,“漏斗”的最末端才是有效的請求,要達到這個效果必須對數據做分層的校驗,下面是一些原則:

1.先做數據的動靜分離

2.將90%的數據緩存在客戶端瀏覽器

3.將動態請求的讀數據Cache在Web端

4.對讀數據不做強一致性校驗

5.對寫數據進行基於時間的合理分片

6.對寫請求做限流保護

7.對寫數據進行強一致性校驗

將90%的數據緩存在客戶端瀏覽器,將動態請求的讀數據cache在web端,還是不夠的。在大秒的過程中,存在極端情況,就是請求超過單key所在server的QPS能力。

數據訪問熱點,比如Detail中對某些熱點商品的訪問度非常高,即使是Tair緩存這種Cache本身也有瓶頸問題,一旦請求量達到單機極限也會存在熱點保護問題。有時看起來好像很容易解決,比如說做好限流就行,但你想想一旦某個熱點觸發了一臺機器的限流閥值,那麼這臺機器Cache的數據都將無效,進而間接導致Cache被擊穿,請求落地應用層數據庫出現雪崩現象。這類問題需要與具體Cache產品結合才能有比較好的解決方案,這裡提供一個通用的解決思路,就是在Cache的client端做本地Localcache,當發現熱點數據時直接Cache在client裡,而不要請求到Cache的Server。
數據更新熱點,更新問題除了前面介紹的熱點隔離和排隊處理之外,還有些場景,如對商品的lastmodifytime字段更新會非常頻繁,在某些場景下這些多條SQL是可以合併的,一定時間內只執行最後一條SQL就行了,可以減少對數據庫的update操作。另外熱點商品的自動遷移,理論上也可以在數據路由層來完成,利用前面介紹的熱點實時發現自動將熱點從普通庫裡遷移出來放到單獨的熱點庫中。 

心得體會

請允許筆者總結一下高併發方案的解決之道。

使用緩存,能越前端緩存的放在前端,
這樣調用鏈路最短。

這裡的緩存不僅僅是redis、或者memcached,而是local或者climatchent優先的思路,去除對併發資源的依賴。比如[揭秘微信搖一搖背後的技術細節]一文中提到:

按一般的系統實現,用戶看到的紅包在系統中是數據庫中的數據記錄,搶紅包就是找出可用的紅包記錄,將該記錄標識為match屬於某個用戶。在這種實現裡,數據庫是系統的瓶頸和主要成本開銷。我們在這一過程完全不使用數據庫,可以達到幾個數量級的性能提升,同時可靠性有了更好的保障。

1.支付系統將所有需要下發的紅包生成紅包票據文件;

2.將紅包票據文件拆分後放到每一個接入服務實例中;

3.接收到客戶端發起搖一搖請求後,接入服務裡的搖一搖邏輯拿出一個紅包票據,在本地生成一個跟用戶綁定的加密票據,下發給客戶端;

4.客戶端拿加密票據到後臺拆紅包,match後臺的紅包簡化服務通過本地計算即可驗證紅包,完成搶紅包過程。

分拆熱點

上文提到,在極端情況下大秒使用了二級緩存,通過拆分key來達到避免超過cache server請求能力的問題。在facebook有一招,就是通過多個key_index(key:xxx#N) ,來獲取熱點key的數據,其實質也是把key分散。對於非高一致性要求的高併發讀還是蠻有效的。如圖

java互聯網架構三板斧之併發

則解決之道是:

• Hot keys are published to all web-servers

• Each web-server picks an alias for gets

– get key:xxx => get key:xxx#N

• Each web-server deletes all aliases

微博團隊披露:服務端本地緩存,使用nginx本身緩存和服務器的L0緩存,來提升模塊的響應速度,做到了90%以上核心接口的響應時間在50ms以內,減少了進程等待時間,提升了服務器的處理速度。

解決併發有1種基本辦法: 分拆!而分拆有兩種拆法,

1.拆資源

一是把資源(resource)拆了,著名的比如ConcurrentHashMap,拆成了16個桶,併發能力大大提高。

2.拆基礎數據

在紅包應用中,如果還依賴一個共同的基礎數據,也可以把這個基礎數據拆成多個cell。

預處理

[互動1808億次,16倍的超越!談支付寶紅包的高併發挑戰

]一文中如此說:

在這次春晚活動中,涉及到大量的資源,包括圖片、拜年視頻等。圖片和視頻都比較大,十幾b到幾百kb不等。當在高峰期時,如果瞬間有海量的請求到CDN上,這麼大的請求帶寬根本扛不住。我們當時預估了大約有幾T的帶寬需求。

為了能有效地扛住瞬間峰值對CDN的壓力,我們對資源進行了有效的管理和控制。首先在客戶端預埋了幾個缺省資源,萬一真不行了,這幾個資源可以用。其次儘量提前打開入口,當用戶瀏覽過後,就將資源下載到本地。再次瀏覽時不再需要遠程訪問CDN。最後,做了應急預案,高峰期一旦發現流量告警,緊急從視頻切換到圖片,降低帶寬壓力,確保不出現帶寬不夠而發生限流導致的黑屏等體驗不好的問題。

最後的結果可以用完美來形容,由於預熱充分,帶寬雖然很高,但沒達到我們的告警值,應急預案也沒有使用。

在除夕,用戶通過搖一搖參與活動,可以搖到紅包或其他活動頁,這些頁面需要用到很多圖片、視頻或 H5 頁面等資源。在活動期間,參與用戶多,對資源的請求量很大,如果都通過實時在線訪問,服務器的網絡帶寬會面臨巨大壓力,基本無法支撐;另外,資源的尺寸比較大,下載到手機需要較長時間,用戶體驗也會很差。因此,

我們採用預先下載的方式,在活動開始前幾天把資源推送給客戶端,客戶端在需要使用時直接從本地加載。

異步化

江湖傳說中有一句話,叫能異步的儘量異步。做活動的時候,資源多寶貴啊,對C端無感但可以容忍的,就讓它慢慢做,而此種一般放入到隊列當中。

杭州的蘑菇街七公又名小白,是一個熱情的朋友。他提及交易服務依賴過多的解決之道。服務依賴過多,會帶來管理複雜性增加和穩定性風險增大的問題。試想如果我們強依賴10個服務,9個都執行成功了,最後一個執行失敗了,那麼是不是前面9個都要回滾掉?這個成本還是非常高的。所以在拆分大的流程為多個小的本地事務的前提下,對於非實時、非強一致性的關聯業務寫入,在本地事務執行成功後,我們選擇發消息通知、關聯事務異步化執行的方案。(看看下圖,那些可以異步化?)

java互聯網架構三板斧之併發

使用隊列

攔、攔、攔;之後緩存抗;緩存扛不住的併發分拆;但是還有一個問題,就是極端熱點資源在db裡,如果併發高還是會出問題。大秒一文中有較好的處理方案,就是排隊。Web服務器排隊,在db層還做了一個patch排隊,真心是業務是最好的老師,不得已何必祭大招!

應用層做排隊。按照商品維度設置隊列順序執行,這樣能減少同一臺機器對數據庫同一行記錄操作的併發度,同時也能控制單個商品佔用數據庫連接的數量,防止熱點商品佔用太多數據庫連接。關於詳情,可以閱讀大秒一文。


分享到:


相關文章: