Twitter工程師談JVM調優
原文:http://www.slideshare.net/aszegedi/everything-i-ever-learned-about-jvm-performance-tuning-twitter/2-Everything_I_everlearned_about_JVMperformance
一、調優需要關注的幾個方面
內存調優
CPU 使用調優
鎖競爭調優
I/O 調優
二、Twitter 最大的敵人:延遲
導致延遲的幾個原因?
最大影響因素是 GC
其他的有:鎖和線程調度、I/O、演算法數據結構選取不當效率低
三、內存性能調優
(1)內存佔用調優
OutOfMemoryError 異常原因:可能真的數據量太大、可能要數據顯示的太多、可能內存泄露
數據量太大觀察及解決:
查看 GC 日誌, 看 Full GC 前後內存變化, 變化不大說明確實數據量太大
嘗試增加 JVM 的內存使用
考慮這些數據是否真的需要都在內存中嗎? 可以考慮使用: LRU 演算法換入換出等, 弱引用(Soft References)
數據臃腫(Fat data)
當你想做一些奇怪的事情時候回發生數據佔用太大問題,比如:把整個社交圖譜載入到單個 JVM 實例上、載入全部用戶的元數據到單個 JVM 實例上
在 Twitter 這樣大的規模下減少內部數據呈現工作
數據臃腫原因:
(2)填充補全
看個例子
public static class D {
byte d1;
}
public static class E extends D {
byte e1;
}
現在一般是 64-bit 的 JVM,64-bit 的指針會導致 CPU 緩存相比 32-bit 指針減少很多, 所以建議 JVM 參數加入 -XX:+UseCompressedOops 採用指針壓縮將 64-bit 指針壓縮為 32-bit, 但是卻又能使用 64-bit 的內存空間, 達到一舉兩得的作用。另外,建議最大堆小於 30G。
盡量別使用原始類型對象的包裝類
在 Scala 2.7.7 中:Seq[Int] 存 Integer,Array[Int] 存 int, 第一個空間佔用 (24 + 32*length) bytes,第二個空間佔用 (24 + 4*length) bytes。
在 Scala 2.8 中修復了這個問題, 從這我們可以看出:
你不清楚你所使用類庫的性能特徵(比如能用 int 就用 int)
除非在性能分析工具下運行, 否則你可能永遠不知道這個問題
Map 空間佔用(Map footprints)
Guava MapMaker.makeMap() 佔用 2272 bytes
MapMaker.concurrencyLevel(1).makeMap() 佔用 352 bytes
小心使用 Thread Local
典型的問題在線程池 m*n 的資源相關,如 200 線程池使用了 50 個連接,最終有 10000 個連接緩存
考慮使用同步對象或者每次新建一個對象
四、與延遲做鬥爭
性能三角
圖1:內存佔用下降,延遲下降,吞吐量上升
圖2:壓縮(Compactness,即減小內存佔用)率上升,吐量上升,響應速度上升
新生代是如何工作的?
所有新對象分配在 Eden 代,因為新生代 GC 有壓縮,所以內存分配用指針碰撞
當 Eden 滿的時候,進行一次 stop-the-world 的 Minor GC,存活下來的放到 Survivor
經過幾次 Minor GC,還存活下來的對象會被提升(tenured)到老年代
理想化得新生代操作
Eden 代足夠容納超過一組並發的請求和響應對象(這樣沒有 stop-the-world,吞吐量會比較高)
每個 Survivor 空間足夠容納活躍對象和有年齡的對象(減少過早提升到老年代)
提升閾值正好能讓存活時間長的對象早點提升到老年代(給 Survivor 騰出空間)
從新生代開始調優
列印詳細 GC 日誌, 如開啟 JVM 參數:-XX:+PrintGCDetails,-XX:+PrintGCDateStamps,-XX:+PrintHeapAtGC,-XX:+PrintTenuringDistribution 等等...
關注 Survivor 大小,設置合適的 Survivor 大小
關注提升閾值,使長期存活對象快速提升到老年代
(1)-XX:+PrintHeapAtGC
Heap after GC invocations=1 (full 0):
}
(2)-XX:+PrintTenuringDistribution
CMS 調優
CMS 收集器需要更多的內存, 盡量多分配就對了
減少碎片、避免 Full GC
-XX:CMSInitiatingOccupancyFraction=n n一般設置為 75-80(太早啟動降低吞吐量,太晚啟動導致 concurrent mode failed)
響應速度還是太慢?
Minor GC 時有太多存活對象,嘗試減少新生代空間,減少 Survivor 空間,減少晉陞閾值
太多線程。嘗試找到最小的並發層次或者增加更多 JVM 實例
嘗試使用 volatile 而不是 synchronized 減少鎖競爭,嘗試使用 Atomic* 的原子類
用分配 slab 應對 CMS 的碎片問題
Apache 的 Cassandra 內部使用 slab 分配。每個 slab 大小為 2MB,使用 CAS 複製 byte[] 到裡面,使用 Cassandra 前開銷為 30-60 秒每小時, 使用後在3天零十小時開銷 5 秒。
使用分配 slab 的方式有一些局限性:在緩存滿的時候才把緩存內容寫進磁碟,而且對象需要轉化為二進位等問題
智商題:你能在60秒內找出誰放的火嗎?
請返回對話框發送「放火」獲取答案。
小獵推薦
優質IT工作推薦渠道
點擊展開全文


※MVC 動態註冊HttpModule詳解
※JVM 診斷調優 CheatSheet
※妹子:為什麼我要找個程序員做老公?
TAG:程序源 |
※DDN收購Intel Lustre系統業務,詳解Lustre系統架構、配置和調優
※Instagram的Python性能調優方法介紹
※前端學Serverless系列-性能調優
※利用Kubernetes和Helm進行高效的超參數調優
※3M 反光鞋面!低調優雅的 Air Jordan 1 「Rox Brown」 即將上架
※Tomcat 調優測試
※Spark調優的關鍵—RDD Cache緩存使用詳解
※詳解Linux性能調優之tuned特性
※低調優雅!近觀全新配色Nike Premier II足球鞋
※keras參數調優
※Tomcat 運維常用調優方式
※Spark 數據傾斜調優
※如何對分散式 NewSQL 資料庫 TiDB 進行性能調優
※Kafka參數調優實戰
※Python 環境下的自動化機器學習超參數調優
※Hadoop虛擬化的性能對比和調優經驗
※MySQL 性能調優的10個方法
※阿里P8架構師談:資料庫、JVM、緩存、SQL等性能調優方法和原則
※通向架構師的道路(第二十四天)之 Oracle 性能調優
※Sql性能調優