12-如何抗住雙11一天幾十億的訂單量?JVM該如何設(shè)置內(nèi)存?

通過之前相關(guān)JVM的基礎(chǔ)知識學(xué)習我們可以結(jié)合一些實際生產(chǎn)案例來進行結(jié)合鞏固和說明,我們在上線一個生產(chǎn)系統(tǒng)的時候,針對預(yù)估的并發(fā)壓力,到底應(yīng)該如何合理的給出一個未經(jīng)過調(diào)優(yōu)的比較合理的初始值。

另外我們會分析各種參數(shù)在設(shè)置的時候有哪些考慮的點,Java堆內(nèi)存到底需要多大?新生代和老年代的內(nèi)存分別需要多大?永久代和虛擬機棧分別需要多大?這些我們都會結(jié)合案例來一步一步的分析。

注意:JVM參數(shù)到底該如何設(shè)置,一定是根據(jù)不同的業(yè)務(wù)系統(tǒng)具體的一些場景來調(diào)整的,不是說有一個通用的配置和模板,照著設(shè)就沒問題了,這個思路是肯定不對的,一定要結(jié)合案例和業(yè)務(wù)場景來分析。

1.如何抗住雙11一天幾十億的訂單量?JVM該如何設(shè)置內(nèi)存?

我們先來看一個數(shù)據(jù),2020天貓雙11全球狂歡季實時物流訂單總量定格在23.21億。這是什么概念!一天成交23.21億個訂單!更夸張的是天貓訂單在2020年創(chuàng)建峰值達58.3萬筆/秒!

image
54.4 萬筆/秒訂單背后的秘密

雙11前兩個月,阿里巴巴完成了將數(shù)以十萬計的物理服務(wù)器從線下數(shù)據(jù)中心遷移到云上。這是一個浩大的工程,但前端的消費者毫無感知。

阿里云近三年投入巨大資源研發(fā)出來的神龍服務(wù)器,是54.4萬筆/秒訂單的峰值能夠平穩(wěn)度過的保障。54.4 萬筆/秒訂單是什么概念?阿里云智能基礎(chǔ)產(chǎn)品事業(yè)部研究員張獻濤表示,其他公司可能還在為1000筆/秒的訂單做斗爭。

不可忽視的算力

雙11當天,阿里巴巴處理了970PB的數(shù)據(jù)。一個可以對比的數(shù)字是,央視拍了幾十年的節(jié)目,存下來的數(shù)據(jù)是80PB。

支撐雙11大規(guī)模算力的是流計算系統(tǒng)和飛天大數(shù)據(jù)平臺。在系統(tǒng)和商家調(diào)度上,流計算系統(tǒng)發(fā)揮了重要作用。比如,雙11當天商家會提前備貨,當預(yù)測商家主推的商品賣得太快時,飛天大數(shù)據(jù)平臺會給商家提示改變一下策略,不要開場就缺貨;當預(yù)測主推的商品銷量達不到預(yù)期時,飛天大數(shù)據(jù)平臺會提醒考慮商家發(fā)優(yōu)惠券拉動銷量。

不一樣的雙11

在今年雙11的媒體溝通會上,阿里巴巴集團CTO張建鋒表示,阿里云在技術(shù)上完成了四個方面核心突破:

第一、在核心虛擬機系統(tǒng)上,自研神龍架構(gòu),用自研的服務(wù)器來做虛擬化。神龍服務(wù)器在壓力很大的情況下,輸出也是非常線性的。

第二、自研了云原生的數(shù)據(jù)庫,今年雙11上,沒有任何問題。

第三、計算與存儲做了分離,數(shù)據(jù)都是從遠端存取的,存儲可以很方便的擴容。

第四、做了RDMA網(wǎng)絡(luò),能夠做到在遠端存儲,能夠比本地讀寫磁盤更快。

雙11期間,近200萬個容器支撐著電商的核心系統(tǒng),在商家側(cè)阿里巴巴的技術(shù)團隊為商家快速的擴容了5.4萬核,峰值每秒幫助商家處理87萬筆訂單,向商家提供了410億次的調(diào)用。

這些都是雙十一背后的技術(shù)力量。

2.每日百萬的支付系統(tǒng)應(yīng)該如何設(shè)置JVM內(nèi)存?

現(xiàn)在的系統(tǒng)基本很多都離不開支付,那么支付系統(tǒng)的開發(fā)也幾乎是我們必須掌握的一個技能,這里我們以一個電商系統(tǒng)的開發(fā)為背景,針對一個日交易量在百萬的支付系統(tǒng)作為一個實戰(zhàn)案例來進行分析。

針對雙11這樣一天的訂單量顯然不僅僅是靠控制JVM內(nèi)存和服務(wù)器臺數(shù)就能解決的,這里筆者以平均每日百萬量的交易支付訂單來做實戰(zhàn)案例分析,注意:每日支付訂單量能達到百萬的也基本上是現(xiàn)在國內(nèi)最大的互聯(lián)網(wǎng)公司,或者是一個通用型第三方支付平臺,對接各種APP的支付交易。

進入正題分析:

首先大家正常上網(wǎng)購物的流程是:添加商品到購物車 → 下單 → 結(jié)算支付 → 顯示支付結(jié)果

而對于我們的系統(tǒng)開發(fā)來講整個過程應(yīng)該如何進行呢?我們先來看一張之前開發(fā)我做的一張微信支付的全流程圖:

image

是不是感覺有點復(fù)雜?而且這里出現(xiàn)了三個系統(tǒng)的交互,我們將上圖再精簡一下,那么其實整個過程就是如下這樣的:

image

這樣一提取是不是感覺非常清晰了?

訂單系統(tǒng)你可以理解為就是我們的電商后臺系統(tǒng),而我們的支付系統(tǒng)也可以看做是電商系統(tǒng)中的一部分,不過這部分卻非常重要,通常我們提取出來單獨作為一個獨立的系統(tǒng)進行開發(fā)和維護。

支付系統(tǒng)是連接消費者、商家(或平臺)和金融機構(gòu)的橋梁,管理支付數(shù)據(jù),調(diào)用第三方支付平臺接口,記錄支付信息(對應(yīng)訂單號,支付金額等),金額對賬等功能。

我們把整個流程從用戶到訂單系統(tǒng)到支付系統(tǒng)以及三方支付系統(tǒng)的流程先梳理下,大家先有個整體的支付邏輯:

image
  1. 用戶提交訂單支付到我們的訂單系統(tǒng)
  2. 訂單系統(tǒng)將該支付請求提交給支付系統(tǒng)
  3. 支付系統(tǒng)生成一個支付訂單,此時訂單狀態(tài)是“待支付“狀態(tài),返回用戶跳轉(zhuǎn)到付款頁面,選擇支付方式
  4. 用戶選擇微信or支付寶確定付款方式
  5. 支付系統(tǒng)把實際支付請求提交到第三方支付渠道:處理請求、資金轉(zhuǎn)移
  6. 返回處理結(jié)果,支付系統(tǒng)修改訂單為“已完成"

以上僅僅是我們簡化的一個簡單支付流程,實際一個完整支付系統(tǒng)還包含很多東西(比如賬戶管理、對賬管理、清算管理、結(jié)算管理等),我們重點關(guān)注核心的支付流程即可。

一個每日百萬交易的支付系統(tǒng)壓力在哪里?

首先通過上述的流程圖我們知道,用戶提交支付請求,到訂單系統(tǒng)提交真正的支付訂單到支付系統(tǒng),那么這個時候支付系統(tǒng)才算是真正開始工作以及處理,那么每天有一百萬個支付請求對應(yīng)著支付系統(tǒng)就會接收到一百萬個支付訂單,從而要去存儲和處理這一百萬個支付訂單,那么說的更直白點就是我們的JVM內(nèi)存中每天會有百萬個支付訂單對象需要創(chuàng)建(每個訂單對象包含用戶信息、商品信息、支付渠道信息、支付時間、價格等各類信息的匯總),因此我們聚焦在JVM的管理中來看,每一天我們的JVM內(nèi)存中就會有上百萬個支付訂單對象的創(chuàng)建和銷毀,那么我們需要思考以下幾個核心問題:

  1. 我們的JVM內(nèi)存空間需要多大才能支撐起這么多訂單對象的創(chuàng)建?堆內(nèi)存空間是關(guān)鍵,又該分配多少?
  2. 每臺機器需要多大的內(nèi)存空間,以及需要部署多少臺機器?

明確了兩個核心問題后,我們想要去分析和確定內(nèi)存的分配,就必須知道我們的系統(tǒng)高峰期在哪兒?因為一般來講用戶在購物的時候都會有個峰值進行購買,比如中午和晚上,統(tǒng)計在一起也就大概幾個小時,也就是說在幾個小時內(nèi)就能產(chǎn)生差不多一百萬個訂單,我們按照4個小時來計算差不多在60~70筆訂單/秒,這里我們直接取整,按照每秒有100筆訂單產(chǎn)生來進行計算和處理。

一個支付訂單的處理需要多久以及占用多大空間

接下來我們必須要清楚的知道一個訂單大概要處理的時間,當用戶點擊提交訂單的時候,這時會攜帶訂單相關(guān)參數(shù)到電商后臺系統(tǒng),由電商系統(tǒng)創(chuàng)建訂單,并做移除購物車商品的操作,以及保存訂單到數(shù)據(jù)庫的操作等,接著才會向支付系統(tǒng)發(fā)送當前訂單,整個過程從發(fā)起請求到創(chuàng)建訂單到支付系統(tǒng)中,我們粗略計算為1秒差不多了。

那一個訂單所占據(jù)的對象大小是多少呢?一般一個訂單對象中核心的實例變量也就20多個差不多了,根據(jù)基本數(shù)據(jù)類型所對應(yīng)的字節(jié)大小來計算,一般一個訂單對象也就差不多在500字節(jié)的大小。那每秒100筆訂單到來,也就是差不多一秒能產(chǎn)生 100*500 = 50000大概也就50KB而已,其實非常的小。

那么結(jié)合以上兩點分析我們可以知道,系統(tǒng)每1秒會來100個支付訂單,而每個支付訂單的創(chuàng)建需要1秒,那也就是1秒過后,就會在內(nèi)存中產(chǎn)生50KB的垃圾對象,因為1秒過后這100個對象就沒人引用了,成為新生代中的垃圾對象了。

image

下一秒過后又會持續(xù)產(chǎn)生100個訂單對象,那么接著又繼續(xù)產(chǎn)生50KB的垃圾對象,如此一來新生代里就會持續(xù)的產(chǎn)生堆積垃圾對象,直到裝滿為止觸發(fā)Minor GC進行回收。

支付系統(tǒng)內(nèi)存占用預(yù)估

按照上述所分析,1秒產(chǎn)生50KB垃圾對象,那么100秒就有差不多5MB垃圾對象了,可能大家覺得有點不足為懼,但是我們以上僅僅只是分析了一個支付訂單對象的占用大小,實際運行中每秒還會產(chǎn)生其他大量的對象(系統(tǒng)本身的+我們攜帶關(guān)聯(lián)的各種對象),所以我們真正要估算內(nèi)存占用的話,還得將之前的計算結(jié)果放大10~20倍!

那這樣估算的話,我們每秒鐘創(chuàng)建的對象大概就在500KB~1MB之間。按最大1MB來計算好了,1秒產(chǎn)生1MB垃圾對象,那100秒就能產(chǎn)生出來100MB垃圾對象,按新生代內(nèi)存為1個G來計算,Eden區(qū)分配800MB,那也就是800秒就得觸發(fā)一次Minor GC了,如果頻繁的觸發(fā)Minor GC肯定不是一個好事!會影響我們線上的性能穩(wěn)定。

支付系統(tǒng)JVM內(nèi)存如何設(shè)置?

那我們在真正系統(tǒng)上線的時候應(yīng)該如何進行部署以及分配JVM內(nèi)存呢?這里假如我們經(jīng)濟有限僅僅分配一臺2核4G的機器來部署,4G的內(nèi)存能真正分配到JVM上的也就最多2G,而這2G還不能全都給堆內(nèi)存,還有方法區(qū)、棧內(nèi)存等區(qū)域,堆內(nèi)存最多也就能分配到個1G左右,而且堆內(nèi)存還分新生代和老年代,這樣算下來我們的新生代最多也就幾百Mb大小了,根據(jù)我們之前的分析,1秒就能消耗1MB左右的內(nèi)存,幾百秒就能撐滿導(dǎo)致垃圾回收,影響我們系統(tǒng)的性能穩(wěn)定性。(一旦觸發(fā)垃圾回收就會導(dǎo)致STW,系統(tǒng)線程停止,這塊我們后續(xù)會講解)

那么如何解決和優(yōu)化呢?

  1. 可以考慮提升成本,使用4核8G的機器來進行部署,那么我們的JVM至少可以分配到4G以上內(nèi)存,新生代也至少能分配到2G內(nèi)存,那么可以將Minor GC的觸發(fā)時間由幾百秒提升到半小時~1小時觸發(fā),降低GC的頻率
  2. 擴展服務(wù)器數(shù)量,我們可以部署3~5臺機器來進行橫向擴展,當然機器數(shù)量越多,每天機器處理的請求就更少,這樣對JVM內(nèi)存的壓力就更小。

當然實際需要根據(jù)各位自己的業(yè)務(wù)量以及系統(tǒng)性能進行合理配置,針對每個系統(tǒng)上線前都要做一次JVM內(nèi)存的模擬估算(如何通過工具來查看實際JVM內(nèi)存的變化過程后續(xù)我們再講解)并且是多次測試得出一個合理的數(shù)據(jù)再通過預(yù)估的用戶請求量來進行模擬估算,提前設(shè)置有一個合理的值,減少GC的頻繁觸發(fā),保障系統(tǒng)的穩(wěn)定運行。

3.雙11大促,瞬時訪問量增加10倍

除了日常的平均支付交易量需要預(yù)估設(shè)置以外,還需要思考的就是大促的時候如何保障服務(wù)器的穩(wěn)定。比如雙11來臨,很可能導(dǎo)致服務(wù)器壓力瞬間增大10倍,都在這一時段或這一天來買東西了,那么這個時候可能計算出來的就不是每秒100筆支付訂單的問題了,可能是每秒1000筆訂單甚至更大!這個時候就不光是我們的內(nèi)存壓力大,特別是線程資源,CPU資源幾乎都會占滿,內(nèi)存也是岌岌可危!

之前我們計算過每一秒產(chǎn)生的對象是在1MB,那遇到大促的時候,每一秒的內(nèi)存占用有可能就能達到10MB甚至幾十MB(得往大一點預(yù)估不要考慮剛剛好),并且這個時候還有個問題就是,以前差不多1秒能處理完我們100個訂單,但是現(xiàn)在1000個訂單1秒是肯定處理不完的,剛才也分析過,CPU、線程、內(nèi)存都吃緊,系統(tǒng)性能也會跟著不穩(wěn)定,那1000個訂單至少需要幾秒甚至幾十秒才可能處理完畢。

那么當我們的新生代快滿的時候,這個時候還在往里進對象就會出現(xiàn)問題,因為上一波的對象可能還未處理完這時有來一波對象,而新生代中也被垃圾對象給填滿了,那么就會觸發(fā)Minor GC,假設(shè)我們的新生代和老年代內(nèi)存分配分別為1G,現(xiàn)在的情況如下:

image

新的請求過來分配空間不足觸發(fā)MinorGC,回收部分對象,而我們的少部分對象由于系統(tǒng)處理較慢還在引用,而每秒還在產(chǎn)生大量對象不斷進來,假如我們預(yù)估每秒創(chuàng)建新對象100MB,1個G的新生代中Eden區(qū)占800MB,不到8S就會觸發(fā)一次MinorGC,那么這么大量頻繁的觸發(fā)MinorGC,加上少數(shù)對象處理較慢就會導(dǎo)致部分對象由于多次經(jīng)歷Minor GC后依然存活,最終進入老年代:

image

而當那部分對象處理完畢后失去引用就成為垃圾對象了,但是已經(jīng)存在于我們的老年代了。

image

那么按照這個頻率老年代被占滿的速度也很快!而一旦老年代被占滿就會觸發(fā)Full GC,這個比Minor GC更恐怖,導(dǎo)致系統(tǒng)暫停的時長更久!你試想下,在大促秒殺搶單的過程中你的系統(tǒng)卡死,正在執(zhí)行垃圾回收,而用戶這邊一直無法進入付款頁面是什么感受? 等系統(tǒng)恢復(fù),再進行付款這時也過秒殺時段或商品已售空,嚴重影響用戶體驗。

至于新生代和老年代的垃圾回收規(guī)則以及如何優(yōu)化我們放在后續(xù)講解。

因此大家在公司進行項目開發(fā)上線的時候一定要結(jié)合JVM內(nèi)存進行思考和預(yù)估,特別是用戶量大的項目,不合理的預(yù)估業(yè)務(wù)系統(tǒng)壓力,等真正壓力來臨的時候,系統(tǒng)隨時面臨崩盤。這也是為什么很多大廠面試都要考核JVM這塊的原因,考核你是否真正做到對你自己的系統(tǒng)足夠了解,對線上的內(nèi)存預(yù)估是否準確。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容