日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

大型跨境电商 JVM 调优经历

發(fā)布時間:2025/4/16 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 大型跨境电商 JVM 调优经历 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

大型跨境電商 JVM 調優(yōu)經歷

前提:
某大型跨境電商業(yè)務發(fā)展非常快,線上機器擴容也很頻繁,但是對于線上機器的運行情況,特別是jvm內存的情況,一直沒有一個統(tǒng)一的標準來給到各個應用服務的owner。經過618大促之后,和運維的同學討論了下,希望將線上服務器的jvm參數標準化,可以以一個統(tǒng)一的方式給到各個應用,提升線上服務器的穩(wěn)定性,同時減少大家都去調整jvm參數的時間。
參考了之前在淘寶天貓工作的公司的經歷:經過大家討論,根據jdk的版本以及線上機器配置,確定了一個推薦的默認jvm模版:

最終推薦的jvm模版:
jdk版本 機器配置 建議jvm參數 備注
jdk1.7 6V8G -server -Xms4g -Xmx4g -Xmn2g -Xss768k -XX:PermSize=512m -XX:MaxPermSize=512m
-XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSClassUnloadingEnabled
-XX:+DisableExplicitGC -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=68
-verbose:gc -XX:+PrintGCDetails -Xloggc:{CATALINA_BASE}/logs/gc.log -XX:+PrintGCDateStamps
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath={CATALINA_BASE}/logs 前臺

jdk1.7 8V8G -server -Xms4g -Xmx4g -Xmn2g -Xss768k -XX:PermSize=512m -XX:MaxPermSize=512m
-XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSClassUnloadingEnabled
-XX:+DisableExplicitGC -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=68
-verbose:gc -XX:+PrintGCDetails -Xloggc:{CATALINA_BASE}/logs/gc.log -XX:+PrintGCDateStamps
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath={CATALINA_BASE}/logs 前臺

jdk1.7 4V8G -server -Xms4g -Xmx4g -Xmn2g -Xss768k -XX:PermSize=512m -XX:MaxPermSize=512m
-XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSClassUnloadingEnabled
-XX:+DisableExplicitGC -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=68
-verbose:gc -XX:+PrintGCDetails -Xloggc:{CATALINA_BASE}/logs/gc.log -XX:+PrintGCDateStamps
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath={CATALINA_BASE}/logs 前臺

jdk1.7 6V8G -server -Xms4g -Xmx4g -XX:MaxPermSize=512m
-verbose:gc -XX:+PrintGCDetails -Xloggc{CATALINA_BASE}/logs/gc.log -XX:+PrintGCTimeStamps \ 后臺

某互聯網(bat)公司的推薦配置:

配置說明:

  • 堆設置
    -Xms:初始堆大小
    -Xmx:最大堆大小
    -XX:NewSize=n:設置年輕代大小
    -XX:NewRatio=n:設置年輕代和年老代的比值。如:為3,表示年輕代與年老代比值為1:3,年輕代占整個年輕代年老代和的1/4
    -XX:SurvivorRatio=n:年輕代中Eden區(qū)與兩個Survivor區(qū)的比值。注意Survivor區(qū)有兩個。如:3,表示Eden:Survivor=3:2,一個Survivor區(qū)占整個年輕代的1/5
    -XX:MaxPermSize=n:設置持久代大小

  • 收集器設置
    -XX:+UseSerialGC:設置串行收集器
    -XX:+UseParallelGC:設置并行收集器
    -XX:+UseParalledlOldGC:設置并行年老代收集器
    -XX:+UseConcMarkSweepGC:設置并發(fā)收集器

  • 垃圾回收統(tǒng)計信息
    -XX:+PrintGC
    -XX:+PrintGCDetails
    -XX:+PrintGCTimeStamps
    -Xloggc:filename

  • 并行收集器設置
    -XX:ParallelGCThreads=n:設置并行收集器收集時使用的CPU數。并行收集線程數。
    -XX:MaxGCPauseMillis=n:設置并行收集最大暫停時間
    -XX:GCTimeRatio=n:設置垃圾回收時間占程序運行時間的百分比。公式為1/(1+n)

  • 并發(fā)收集器設置
    -XX:+CMSIncrementalMode:設置為增量模式。適用于單CPU情況。
    -XX:ParallelGCThreads=n:設置并發(fā)收集器年輕代收集方式為并行收集時,使用的CPU數。并行收集線程數。

  • 參數解釋:

    -Xms3072m -Xmx3072m
    針對JVM堆的設置,通過-Xms -Xmx限定其最小、最大值
    -Xmn1024m設置年輕代大小為1024m
    整個JVM內存大小=年輕代大小 + 年老代大小 + 持久代大小(perm)。

    -Xss768k 設置每個線程的堆棧大小。JDK5.0以后每個線程堆棧大小為1M,以前每個線程堆棧大小為256K。更具應用的線程所需內存大小進行調整。在相同物理內存下,減小這個值能生成更多的線程。但是操作系統(tǒng)對一個進程內的線程數還是有限制的,不能無限生成,經驗值在3000~5000左右。

    -XX:PermSize=512m -XX:MaxPermSize=512m
    持久代一般固定大小為64m,所以增大年輕代后,將會減小年老代大小。此值對系統(tǒng)性能影響較大,Sun官方推薦配置為整個堆的3/8。
    設置非堆內存初始值,默認是物理內存的1/64;由XX:MaxPermSize設置最大非堆內存的大小,默認是物理內存的1/4

    -XX:+UseConcMarkSweepGC
    CMS收集器也被稱為短暫停頓并發(fā)收集器。它是對年老代進行垃圾收集的。CMS收集器通過多線程并發(fā)進行垃圾回收,盡量減少垃圾收集造成的停頓。CMS收集器對年輕代進行垃圾回收使用的算法和Parallel收集器一樣。這個垃圾收集器適用于不能忍受長時間停頓要求快速響應的應用。

    -XX:+UseParNewGC對年輕代采用多線程并行回收,這樣收得快;

    -XX:+CMSClassUnloadingEnabled
    如果你啟用了CMSClassUnloadingEnabled ,垃圾回收會清理持久代,移除不再使用的classes。這個參數只有在 UseConcMarkSweepGC 也啟用的情況下才有用。

    -XX:+DisableExplicitGC禁止System.gc(),免得程序員誤調用gc方法影響性能;

    -XX:+UseCMSInitiatingOccupancyOnly
    標志來命令JVM不基于運行時收集的數據來啟動CMS垃圾收集周期。而是,當該標志被開啟時,JVM通過CMSInitiatingOccupancyFraction的值進行每一次CMS收集,而不僅僅是第一次。然而,請記住大多數情況下,JVM比我們自己能作出更好的垃圾收集決策。因此,只有當我們充足的理由(比如測試)并且對應用程序產生的對象的生命周期有深刻的認知時,才應該使用該標志。

    -XX:CMSInitiatingOccupancyFraction=68
    默認CMS是在tenured generation(年老代)占滿68%的時候開始進行CMS收集,如果你的年老代增長不是那么快,并且希望降低CMS次數的話,可以適當調高此值;

    -XX:+UseParNewGC:對年輕代采用多線程并行回收,這樣收得快;

    -XX:HeapDumpPath
    -XX:+PrintGCDetails
    -XX:+PrintGCTimeStamps
    -Xloggc:/usr/aaa/dump/heap_trace.txt
    上面的的參數打Heap Dump信息

    -XX:+HeapDumpOnOutOfMemoryError
    此參數可以控制OutOfMemoryError時打印堆的信息

    大家可能注意到了,這里推薦采用cms方式進行垃圾回收;
    CMS是一種以獲取最短回收停頓時間為目標的收集器,可以有效減少服務器停頓的時間;
    CMS的GC線程對CPU的占用率會比較高,但在多核的服務器上還是展現了優(yōu)越的特性,目前也被部署在國內的各大電商網站上。所以這里強烈推薦!

    cms的概念:
    CMS收集器也被稱為短暫停頓并發(fā)收集器。它是對年老代進行垃圾收集的。CMS收集器通過多線程并發(fā)進行垃圾回收,盡量減少垃圾收集造成的停頓。CMS收集器對年輕代進行垃圾回收使用的算法和Parallel收集器一樣。這個垃圾收集器適用于不能忍受長時間停頓要求快速響應的應用。CMS采用了多種方式盡可能降低GC的暫停時間,減少用戶程序停頓。停頓時間降低的同時犧牲了CPU吞吐量 。這是在停頓時間和性能間做出的取舍,可以簡單理解為"空間(性能)"換時間。

    調整的節(jié)奏:
    由于怕影響線上應用,所以調整的步驟分三步:
    第一步:部分影響少量機器試點,對比未調整的機器,觀察調整后的結果;
    第二步:調整部分應用的參數,進行壓測,觀察高并發(fā)壓測之后的效果;
    第三步:調整部分核心應用的jvm參數,通過818大促來實際檢驗效果;

    目前818大促已經結果。正好做一個個總結
    一. 長期表現
    第一個變化:fgc的次數減少,減少了大概一倍以上;
    mobile工程,調整前基本上一天1-2輛次,調整后基本上就是2-3天一次:

    online(另外一個工程):可以明顯看到fgc的統(tǒng)計頻率少了很多;

    第二個變化:fgc的時間減少

    原來一次fgc要將近500ms,現在只要100ms不到了。
    也證明了cms最大的好處就是減少fgc的停頓時間。

    二. 壓測及大促表現
    fgc的時間基本上是大大縮短,yanggc的時間變長,次數變化不大;
    數據來源:測試團隊的壓測總結

    xxxx-online4.server.org CMSxxxx-online1.server.org CMSxxxx-online34.server.org 默認垃圾收集器說明
    fullgc次數111
    fullgc總時間3432501219
    默認垃圾收集器/CMS fullgc 時間3.554.88CMS fullgc時間比默認垃圾收集器時間明顯要少。
    fullgc時間點2:48:363:14:365:30:36
    fullgc時使用率CPU%40%10%16%
    fullgc時的load Average1.190.491.21
    younggc總次數109410981078
    younggc總時間440934463230387
    younggc平均時間40.3040.6528.19
    younggc最大時間13321268928
    CMS/默認垃圾收集器(younggc總時間)1.451.47CMS younggc時間比默認垃圾收集器耗時
    CMS/默認垃圾收集器(younggc平均時間)1.431.44CMS younggc時間比默認垃圾收集器耗時
    CMS/默認垃圾收集器(younggc最大時間)1.441.37CMS younggc時間比默認垃圾收集器最差情況要差

    三. 關于哨兵上統(tǒng)計full gc的次數的解釋
    哨兵上我們可以安全的說:

  • Full GC == Major GC指的是對老年代/永久代的stop the world的GC
  • Full GC的次數 = 老年代GC時 stop the world的次數
  • Full GC的時間 = 老年代GC時 stop the world的總時間
  • CMS 不等于Full GC,我們可以看到CMS分為多個階段,只有stop the world的階段被計算到了Full GC的次數和時間,而和業(yè)務線程并發(fā)的GC的次數和時間則不被認為是Full GC
  • Full GC的次數說的是stop the world的次數,所以一次CMS至少會讓Full GC的次數+2,因為CMS Initial mark和remark都會stop the world,記做2次。而CMS可能失敗再引發(fā)一次Full GC
    如果CMS并發(fā)GC過程中出現了concurrent mode failure的話那么接下來就會做一次mark-sweep-compact的full GC,這個是完全stop-the-world的。

    正是這個特征,使得CMS的每個并發(fā)GC周期總共會更新full GC計數器兩次,initial mark與final re-mark各一次;如果出現concurrent mode failure,則接下來的full GC自己算一次。

    四. 遇到的幾個問題
    問題一:堆棧溢出;
    -Xss256k這個參數調整了,遠濤反饋可能會影響trace的調用。 報如下錯誤:

    Java.lang.StackOverflowError at net.sf.jsqlparser.util.deparser.ExpressionDeParser.visitBinaryExpression(ExpressionDeParser.java:278) at net.sf.jsqlparser.util.deparser.ExpressionDeParser.visit(ExpressionDeParser.java:246) at net.sf.jsqlparser.expression.operators.conditional.OrExpression.accept(OrExpression.java:37) at net.sf.jsqlparser.util.deparser.ExpressionDeParser.visitBinaryExpression(ExpressionDeParser.java:278) at net.sf.jsqlparser.util.deparser.ExpressionDeParser.visit(ExpressionDeParser.java:246)

    因為這個參數是設置每個線程的堆棧大小。JDK5.0以后每個線程堆棧大小為1M,以前每個線程堆棧大小為256K。在相同物理內存下,減小這個值能生成更多的線程。
    所以今天去掉某臺inventory機器的-Xss256k參數,看一下是不是這個導致的

    問題二:初始化標記階段耗時過長:
    一般的建議是cms階段兩次STW的時間不超過200ms,如果是CMS Initial mark階段導致的時間過長:
    在初始化標記階段(CMS Initial mark),為了最大限度地減少STW的時間開銷,我們可以使用:
    -XX:+CMSParallelInitialMarkEnabled
    開啟初始標記過程中的并行化,進一步提升初始化標記效率;
    問題三:remark階段stw的時間過長
    如下圖:

    可以采用的方式是:
    在CMS GC前啟動一次ygc,目的在于減少old gen對ygc gen的引用,降低remark時的開銷-----一般CMS的GC耗時 80%都在remark階段
    -XX:+CMSScavengeBeforeRemark
    jmap分析:

    問題四:nio框架占用DirectMemory導致的OutOfMemoryError
    處理方式:使用XX:+DisableExplicitGC
    增加DirectMemory的大小;
    1、DirectMemory不屬于java堆內存、分配內存其實是調用操作系統(tǒng)的Os:malloc()函數。
    2、容量可通過-XX:MaxDirectMemorySize指定,如果不指定,則默認與Java堆的最大值(-Xmx指定)一樣。注意 ibm jvm默認Direct Memory與-Xmx無直接關系。
    3、Direct Memory 內存的使用避免Java堆和Native堆中來回復制數據。從某些場景中提高性能。
    4、直接ByteBuffer對象會自動清理本機緩沖區(qū),但這個過程只能作為Java堆GC的一部分來執(zhí)行,因此它們不會自動響應施加在本機堆上的壓力。
    5、GC僅在Java堆被填滿,以至于無法為堆分配請求提供服務時發(fā)生,或者在Java應用程序中顯示調用System.gc()函數來釋放內存(一些NIO框架就是用這個方法釋放占用的DirectMemory)。
    6、該區(qū)域使用不合理,也是會引起OutOfMemoryError。
    7、在需要頻繁創(chuàng)建Buffer的場合,由于創(chuàng)建和銷毀DirectBuffer的代價比較高昂,是不宜使用DirectBuffer的,但是如果能將DirectBuffer進行復用,那么 ,在讀寫頻繁的情況下,它完全可以大幅改善性能。(對DirectBuffer的讀寫比普通Buffer快,但是對他的創(chuàng)建和銷毀比普通Buffer慢)。

    總結

    以上是生活随笔為你收集整理的大型跨境电商 JVM 调优经历的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。