控實戰(zhàn):從JMX Exporter到Prometheus告警)
前陣子線上服務連續(xù)兩個晚上報警一次是容器被 OOM Kill另一次是 Full GC 直接把接口拖到大面積超時。兩次排查下來我最大的感受是容器里的 JVM 監(jiān)控跟物理機時代完全不是一個套路。我見過不少團隊把 Java 應用容器化之后第一反應是進容器敲 jstat結果發(fā)現(xiàn)基礎鏡像里根本沒有這些工具也見過堆內(nèi)存參數(shù)不調(diào)整容器明明只有 4G 內(nèi)存JVM 卻按宿主機幾十G來算最后 Pod 直接被系統(tǒng)殺死。這篇文章我會把線上 Docker 容器里 JVM 監(jiān)控的完整鏈路拆開講清楚重點說三件事一是為什么容器場景不能照搬老一套二是怎么用 Prometheus 這套生態(tài)把指標采上來三是這幾年我踩過的坑和排障方法。適合正在給線上 Java 服務做容器化監(jiān)控、或者正被 GC 和 OOM 問題折騰的開發(fā)和運維朋友內(nèi)容不挑團隊規(guī)模哪怕你只有一臺服務器也能落地。1. 容器場景下 JVM 監(jiān)控的難點與整體思路1.1 容器里的 JVM 為什么那么難監(jiān)控先說一個很反直覺的點JVM 本身是自帶監(jiān)控能力的JMXJava Management Extensions就是它的“體檢接口”可以暴露堆內(nèi)存、GC、線程、類加載等一系列指標。問題在于容器化之后這個接口變得非常難用。原因有三個。第一容器有獨立的網(wǎng)絡命名空間JVM 的 JMX 服務如果監(jiān)聽了某個端口外部訪問時需要做端口映射而 JMX 內(nèi)部的 RMI 協(xié)議還會隨機開端口經(jīng)常出現(xiàn)“端口明明映射了指標就是拉不到”的情況。第二生產(chǎn)環(huán)境的基礎鏡像為了精簡體積很多用的是裁剪版 JRE連 jps、jstat、jcmd 這些 JDK 自帶工具都沒有你想進去看一眼“現(xiàn)場”都無從下手。第三JVM 對容器資源限制的感知能力是拆分 JDK 版本演進的早一點的版本根本不知道 cgroup 的存在會按宿主機物理內(nèi)存來算最大堆這一條直接引發(fā)了我開頭說的容器被殺死的事故。用一句生活化的話來理解JVM 像一個租客容器是它租的單間。以前租整棟樓的時候租客知道整棟樓有多大想怎么用都行現(xiàn)在住進單間如果不明確告訴它房間的實際面積它還按照整棟樓的標準來布置家具結果必然把房間拆了。1.2 我把監(jiān)控體系拆成了四層解決容器監(jiān)控問題首先要建立分層思維不要一上來就糾結用哪個工具。一套完整的 JVM 監(jiān)控體系我習慣拆成四層采集層負責從 JVM 進程里把指標“掏”出來比如 JMX Exporter、Micrometer。存儲層負責把這些帶時間戳的指標存下來生產(chǎn)里幾乎都是時序數(shù)據(jù)庫Prometheus 是事實標準。展示層把指標畫成圖最常用的是 Grafana。告警層基于指標閾值或趨勢觸發(fā)通知對應 Prometheus 的 Alertmanager。這四層更像是一條流水線每一層的選擇都影響上下游。不過這里我不建議一開始就追求大而全很多人第一步就想去搞 APM應用性能監(jiān)控那是另一套復雜度。最務實的方法是先把采集層和存儲層做通讓指標在 Grafana 里能看到再逐步加告警規(guī)則。只要底層指標是準的后面加告警、做報表都只是配置的事。1.3 方案選型講究“夠用 好擴展”在選型上我踩過一次彎路最早在生產(chǎn)環(huán)境部署監(jiān)控時團隊選擇自己寫腳本定時執(zhí)行 jstat然后把輸出解析存進文本文件再用 Python 腳本畫圖。結果就是三天兩頭出問題——容器重建后腳本跑不起來、存量數(shù)據(jù)沒有時序、報警只能靠人工盯。后來換了 Prometheus 方案整個體系才算穩(wěn)定下來。那套臨時方案的問題在于jstat 本質上是“命令行的瞬時快照”適合人工看一眼不適合做長期數(shù)據(jù)積累。長期監(jiān)控必須解決三個問題指標怎么持續(xù)暴露、怎么被自動發(fā)現(xiàn)、怎么存得下。Prometheus 生態(tài)之所以能成為主流是因為它用 Pull 模型主動抓取目標容器無論漂移到哪臺機器只要服務發(fā)現(xiàn)能拿到地址指標就能持續(xù)入庫不需要像 Push 模式那樣時刻維護發(fā)送方和接收方的連接關系。2. 采集層方案選型四種方式各有各的適用場景2.1 首選方案JMX Exporter 以 Agent 方式注入采集層是整套監(jiān)控的地基我這里用的標配是 JMX Exporter更準確說是官方提供的 Java Agent 方式。原理很簡單啟動 JVM 時通過 -javaagent 參數(shù)把這個 jar 注入到應用進程里它通過 JMX 的 MXBean 讀取 JVM 運行數(shù)據(jù)再在本地暴露一個 HTTP 端口輸出 Prometheus 格式的指標。選擇 Agent 方式而不是獨立進程方式是因為 Agent 和業(yè)務進程同生命周期配置跟著鏡像走。應用發(fā)版監(jiān)控配置也跟著原子更新不存在“進程起來了但監(jiān)控進程掛了”的尷尬。而且它規(guī)避了 RMI 隨機端口問題——JMX Exporter 自己就是 Java 進程的一部分直接把數(shù)據(jù)轉成 HTTP 輸出Prometheus 只需要訪問一個固定端口。啟動方式非常直白在 JAVA_TOOL_OPTIONS 環(huán)境變量里加一行JAVA_TOOL_OPTIONS-javaagent:/path/to/jmx_prometheus_javaagent.jar9091:/path/to/config.yaml其中 9091 是監(jiān)控端口config.yaml 是采集規(guī)則配置用來過濾和裁剪指標。實際使用中千萬別小看這個配置文件默認全量抓取 JMX 域會導致指標爆炸后面我會講怎么收斂。2.2 備選方案Micrometer 直接暴露 Prometheus 指標如果你的服務已經(jīng)基于 Spring Boot 3.x 或 Cloud 全家桶還有一個更輕的接入方式引入 Micrometer 的 Prometheus 注冊表依賴。這樣應用直接通過 actuator 接口在 /actuator/prometheus 上暴露指標根本不需要額外掛 agent。這個方案的好處是侵入性小依賴一加、配置一開就能跑而且你能在同一端口同時拿到 HTTP 請求延遲、線程池狀態(tài)等應用層指標。但它也有一個坑actuator 接口本身是一個具有信息泄露風險的管理端點一旦暴露到公網(wǎng)等于把 JVM 內(nèi)部狀態(tài)拱手送人。我的安全基線是必須放到內(nèi)網(wǎng)網(wǎng)段并且通過網(wǎng)段限制或認證保護起來否則別開。從長期維護角度我并不認為 Micrometer 和 JMX Exporter 是二選一的關系。很多團隊兩個都用比如核心鏈路服務用 agent 拿 JVM 層指標輕量 Web 服務用 actuator 一筆帶過。這完全可行只要最終指標名能統(tǒng)一進 Prometheus 就行。2.3 應急方案jstat 和 Arthas 只能救急不能當長期依賴說一個容易被忽略的事實容器里靠 jstat 排查問題的時代已經(jīng)過去了主要原因不是命令不好用而是新版本的 JDK 對 attach 機制的限制越來越多容器里 PID 1 是 Java 進程時尤其麻煩。后來更多團隊轉向 Arthas一款 Java 診斷工具在 JVM 內(nèi)做線程棧、方法耗時、反編譯等操作確實方便像 watch 一個線上方法的入?yún)⒊鰠追昼娋湍芏ㄎ粏栴}。但 Arthas 的思路是“手動診斷”適合你在報警之后進去看現(xiàn)場不適合做持續(xù)監(jiān)控。你要是拿它監(jiān)控七天的心率曲線先不說數(shù)據(jù)怎么存光是每次連接一個生產(chǎn)容器這件事就有很高的操作風險。所以我的總結是長期監(jiān)控用 JMX Exporter 或 Micrometer應急排查用 Arthas兩者缺一不可但功能絕不能互相替代。2.4 四種方案橫向對比方案接入成本持續(xù)監(jiān)控適用場景注意風險JMX Exporter Agent引入 jar 改啟動參數(shù)強生產(chǎn)環(huán)境默認首選配置文件需裁剪指標量Micrometer Actuator添加依賴 配置強Spring Boot 應用管理端點需做安全收斂jstat 手動命令零接入弱臨時看現(xiàn)場JDK 工具鏈可能不存在Arthas 診斷按需啟動弱單次問題定位有侵入風險需謹慎使用方案這東西沒有絕對的好壞只有適不適合當前環(huán)境。我見過只靠 actuator 就跑了幾年的公司也見過所有非 Spring Boot 服務全掛 agent 的團隊。只要你能說得清每個方案解決了什么問題、犧牲了什么選哪個都說得過去。3. 實操落地從 JVM 參數(shù)到 Grafana 面板3.1 第一個坑就藏在鏡像構建里JVM 參數(shù)必須顯式設置真正動手搭建時第一件事不是裝 Grafana而是檢查 JVM 對容器內(nèi)存的感知。這里有一個很多教程不會重點提的版本分界線Java 8u191 之前的版本沒有開啟容器支持JVM 在容器里看到的內(nèi)存是宿主機內(nèi)存4G 的容器限額形同虛設堆會一直增長到宿主機物理內(nèi)存的 1/4 或更高最后的結果就是 Pod 被 OOM Killer 殺掉而你去看 Java 日志根本找不到 OutOfMemoryError——因為進程是被 CGroup 層直接殺的。Java 8u191 及以上版本默認開啟 -XX:UseContainerSupport但這并不意味著你什么參數(shù)都不用管。我推薦在啟動命令里顯式加上下面這組參數(shù)用百分比而不是固定大小這樣能應對容器內(nèi)存動態(tài)調(diào)整的場景java -XX:UseContainerSupport \ -XX:InitialRAMPercentage50.0 \ -XX:MaxRAMPercentage75.0 \ -XX:MinRAMPercentage50.0 \ -jar my-service.jar這里 MaxRAMPercentage 取 75.0 是有講究的。容器里除了 JVM 堆還有 Metaspace、線程棧、直接內(nèi)存Direct Buffer、JIT 編譯器內(nèi)存等一堆“堆外開銷”如果堆直接吃到 90%剩下的區(qū)域稍一波動就可能觸發(fā) OOM。留出大約 25% 給堆外和系統(tǒng)保留是經(jīng)歷多次事故后比較穩(wěn)妥的經(jīng)驗值。注意不要把 -Xmx 和 MaxRAMPercentage 混用一旦手動指定了 -Xmx容器感知和百分比配置就都會失效。3.2 把 JMX Exporter 裝進鏡像接下來把監(jiān)控探針打進鏡像。這里我會把步驟說細一點因為鏡像構建階段少一個文件后面調(diào)試成本會加倍。先在應用部署目錄下放好 agent jar 和配置文件我通常單獨建一個監(jiān)控目錄避免和其它文件混在一起# 目錄結構 /opt/app/ ├── my-service.jar ├── jmx/ │ ├── jmx_prometheus_javaagent.jar │ └── config.yaml └── start.shconfig.yaml 的關鍵作用是裁剪指標。官方默認配置會暴露所有 JMX 域量非常大我一般是把和故障排查強相關的指標全放行其它雜項過濾掉。一個可用的最小配置長這樣rules: - pattern: java.langtypeMemory(HeapMemoryUsage|NonHeapMemoryUsage)(committed|init|max|used) name: jvm_memory_$1_$2 - pattern: java.langtypeGarbageCollectorname(.*):(CollectionCount|CollectionTime) name: jvm_gc_$1_$2啟動腳本里直接讀取環(huán)境變量這樣同一份鏡像在測試環(huán)境和線上環(huán)境可以共用#!/bin/bash export JAVA_TOOL_OPTIONS${JAVA_TOOL_OPTIONS} \ -javaagent:/opt/app/jmx/jmx_prometheus_javaagent.jar9091:/opt/app/jmx/config.yaml exec java $JAVA_OPTS -jar /opt/app/my-service.jar啟動之后先在容器內(nèi)部驗證指標是否正常暴露docker exec -it container_id sh curl http://127.0.0.1:9091/metrics | head -20這一步非常關鍵。如果在容器內(nèi) curl 能看到 java_lang 前綴的指標說明 agent 注入成功如果看不到優(yōu)先檢查 JAVA_TOOL_OPTIONS 是否真的傳到了 Java 進程可以直接在啟動命令里加 -verbose:gc 看啟動日志驗證。提示jmx_prometheus 的指標名在不同版本之間兼容性很好但如果你以后在 Grafana 里用到別人的面板注意確認指標前綴和 label 是否匹配。3.3 配置 Prometheus 抓取容器指標指標已經(jīng)暴露出來了接下來讓 Prometheus 找到它。網(wǎng)絡拓撲上盡量保持簡單Prometheus 部署在和業(yè)務容器相同的網(wǎng)絡環(huán)境里。如果你用的是 Kubernetes想都不用想直接通過 Pod 注解做服務發(fā)現(xiàn)apiVersion: v1 kind: Pod metadata: annotations: prometheus.io/scrape: true prometheus.io/port: 9091 prometheus.io/path: /metrics然后在 prometheus.yml 里寫一段自動發(fā)現(xiàn)配置scrape_configs: - job_name: jvm-app kubernetes_sd_configs: - role: pod relabel_configs: - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape] action: keep regex: true - source_labels: [__address__] action: replace regex: ([^:])(?::\d)? target_label: __address__ replacement: $1:9091如果只是單機 Docker Compose 環(huán)境配置更簡單直接在 compose 里把 9091 端口映射到宿主機再用靜態(tài)配置scrape_configs: - job_name: jvm-app static_configs: - targets: [192.168.1.10:9091] labels: env: production配好后去 Prometheus 的 Targets 頁面看狀態(tài)Up 就代表連通了。如果顯示 Down先別急著懷疑 Prometheus去容器里 curl 一下地址大概率是網(wǎng)絡不通或者 agent 沒起來。排查時記住一句話永遠分步驗證每一層通了再往上走。3.4 用 Grafana 把數(shù)字變成圖Prometheus 只是把指標存下來了真正讓團隊愿意用的還是圖形化界面。Grafana 接入 Prometheus 數(shù)據(jù)源后在官方面板市場里搜 “JVM” 關鍵字找一個下載量最高的 Micrometer 或 JMX Exporter 面板導入就能直接看到堆內(nèi)存、GC 次數(shù)、線程數(shù)量這些圖。不過這里我必須提醒一句第三方面板導入后十有八九會有部分圖表無數(shù)據(jù)。原因不是面板有問題而是面板的變量名、指標前綴和你實際采集到的不一致。比如有人用 Micrometer 風格指標jvm_memory_used_bytes有人用 JMX Exporter 風格指標java_lang_memory兩個風格在面板里對應的 label 完全不一樣。正確的做法是先導入然后在 Grafana 的 Explore 頁面查一下實際指標名再手動改面板的 PromQL 查詢。我自己的習慣是不用第三方面板直接自己建幾個核心圖堆內(nèi)存使用率趨勢、GC 暫停時間、Full GC 次數(shù)、Old 區(qū)利用率、活躍線程數(shù)。五個圖足夠應對 90% 的排查場景圖畫得再漂亮關鍵看報警后能不能快速定位根因。4. 告警配置的實戰(zhàn)經(jīng)驗指標怎么選、閾值怎么定4.1 先把這幾個指標盯住監(jiān)控的目的是提前發(fā)現(xiàn)問題不是事后看報表。所以告警指標的選取必須和故障模式強相關。我根據(jù)自己的踩坑經(jīng)歷把優(yōu)先級排了一個序容器內(nèi)存 / 堆內(nèi)存使用率直接決定會不會 OOM最重要沒有之一。GC 暫停時間特別是 Full GC決定了接口會不會突然變慢、超時。Old 區(qū)/老年代使用率堆內(nèi)存問題的第二觀察窗口如果 Old 區(qū)持續(xù)上漲且回落不明顯大概率是內(nèi)存泄漏。線程數(shù)線程泄漏在高并發(fā)服務里很常見線程數(shù)持續(xù)增長且不回落需要立刻關注。Metaspace容器鏡像經(jīng)常動態(tài)生成類Metaspace 漲滿會觸發(fā) Full GC。判斷手段上Grafana 里“堆使用率”和“GC 耗時”這兩條曲線一定要放在同一個時間軸上。經(jīng)驗是如果 GC 變長時堆內(nèi)存使用率同時在爬升說明內(nèi)存壓力較大需要擴容或者排查泄漏如果 GC 變長但堆內(nèi)存很平穩(wěn)優(yōu)先級排在 Native 內(nèi)存或線程方面。4.2 閾值不能拍腦袋先跑一段基線告警閾值是我見過團隊分歧最大的一塊。有人喜歡拍一個固定數(shù)比如堆使用率超過 80% 就報警結果業(yè)務高峰每天例行報警最后大家把告警當成背景音真正出事反而沒人看。我的做法是分兩步走。第一步先讓監(jiān)控跑一到兩周把正常業(yè)務波峰波谷的基線記錄下來。不同服務的差異非常大一個是計算密集型服務堆使用率常年 70% 上下波動另一個是緩存型服務平時 20%促銷期直沖 90%套同一套閾值顯然不合理。第二步閾值設置要帶時間和趨勢維度不要做單點判斷。比如“堆使用率超過 80%”這個條件可以加上“持續(xù) 15 分鐘”避免瞬時抖動打擾Full GC 頻率可以按分鐘發(fā)生次數(shù)來算而不是看一次事件就報警。我自己的經(jīng)驗閾值僅供參考不同服務請自行調(diào)整是這樣的指標建議閾值持續(xù)時長級別堆內(nèi)存使用率 80%15 分鐘Warning堆內(nèi)存使用率 90%5 分鐘CriticalFull GC 次數(shù) 2 次/分鐘5 分鐘WarningGC 單次暫停時間 1000 ms1 分鐘Critical活躍線程數(shù)超過基線 2 倍10 分鐘Warning4.3 一套可以拿著改的 Prometheus 告警規(guī)則最后給出一套我在生產(chǎn)環(huán)境里實際用過的規(guī)則片段指標名以 JMX Exporter 風格為主。需要提醒的是不同 exporter 版本指標名會有細微差別務必先在自己環(huán)境里確認指標真實名稱再套用規(guī)則。具體的 PromQL 寫法如下groups: - name: jvm-alerts rules: - alert: JVM Heap Usage High expr: | sum(jvm_memory_used_bytes{areaheap}) by (instance) / sum(jvm_memory_max_bytes{areaheap}) by (instance) 0.8 for: 15m labels: severity: warning annotations: summary: JVM 堆內(nèi)存持續(xù)高位 description: 實例 {{ $labels.instance }} 堆內(nèi)存使用率超過 80% 已持續(xù) 15 分鐘 - alert: JVM Full GC Too Frequent expr: | increase(jvm_gc_collection_seconds_count{actionend of major GC}[5m]) 10 for: 5m labels: severity: warning annotations: summary: Full GC 過于頻繁 description: 實例 {{ $labels.instance }} 最近 5 分鐘內(nèi) Full GC 超過 10 次規(guī)則寫完之后可以在 Prometheus 的 Alerts 頁面看到觸發(fā)狀態(tài)。Alertmanager 再通過 Webhook 把消息推給釘釘或企業(yè)微信整條鏈路就閉環(huán)了。但記住規(guī)則不是越多越好。告警數(shù)量每增加一條就意味著有人要起來處理一次。寧缺毋濫先保住上面那幾條核心的再根據(jù)事故復盤逐步補充。5. 高頻問題與排障實錄5.1 容器里的監(jiān)控端口連不上怎么辦Prometheus 的 Targets 顯示 Down或者 Grafana 里全是“No data”這是最常遇到的情況。先按層排查我在現(xiàn)場一般按下面的順序操作第一步進容器里 curl http://127.0.0.1:9091/metrics確認 Agent 是否真的在監(jiān)聽。如果命令報 Connection refused問題出在 Java 進程層面去查啟動命令和日志。第二步如果容器內(nèi)正常再去宿主機 curl http://容器IP:9091/metrics這一層驗證網(wǎng)絡策略。在 Kubernetes 里尤其注意 NetworkPolicy 是否放行。第三步檢查 Prometheus 的 target 配置和 labels看 Job 名是否匹配服務發(fā)現(xiàn)是否拿到正確的地址。這層問題絕大多數(shù)出在“容器內(nèi)已通、容器外不通”基本就是端口映射漏了或網(wǎng)絡策略卡了沒什么玄學。只記一條不到最后一步不要去 Prometheus 里改來改去。5.2 容器被 OOM Kill 但應用日志沒有 OutOfMemoryError這是容器場景最恐怖的一個問題你的應用日志干干凈凈里面沒有任何 OOM 異常但容器重啟了。原因大概率不是 Java 堆內(nèi)存溢出而是進程占用內(nèi)存超過容器 CGroup 限制被內(nèi)核直接殺死JVM 根本沒有機會輸出任何日志?;仡^看 Java 進程默認最大堆是宿主機內(nèi)存的 1/4。如果你的容器只有 4G 而宿主機是 32GJVM 會認為堆上限是 8G實際內(nèi)存一逼近 4G 時CGroup 直接動刀。排查方法是先看容器狀態(tài)docker inspect container_id --format {{.State.OOMKilled}}如果返回 true說明就是這層原因。解決辦法就是我前面說的用 MaxRAMPercentage 把堆限制在容器內(nèi)存的 75% 以內(nèi)并同時盯容器整體內(nèi)存監(jiān)控曲線。記住一個原則容器里跑 JVM寧可讓 JVM 因為堆內(nèi)存不夠拋出 OutOfMemoryError也不要讓它被內(nèi)核無聲殺死前者至少能在日志里留下證據(jù)。5.3 GC 日志也能進 Docker 日志嗎可以而且強烈建議這么做。容器場景下日志采集都是圍繞 stdout 展開的docker logs、EFK、Loki 都是默認從標準輸出抓。如果你把 GC 日志寫到 /tmp/gc.log那它大概率會被日志系統(tǒng)忽略應用出問題時才發(fā)現(xiàn)缺少關鍵數(shù)據(jù)。Java 8 里這樣做java -XX:PrintGCDetails -XX:PrintGCDateStamps -Xloggc:/dev/stdout從 Java 11 開始日志參數(shù)做了統(tǒng)一化改造/dev/stdout 這個寫法失效了改用java -Xlog:gc*:stdout:time,uptime,level,tags這樣一個docker logs container_id就能直接看到 GC 詳細輸出配合監(jiān)控曲線的異常點復盤時信息非常完整。5.4 指標有數(shù)但 Grafana 面板空蕩蕩這個問題的根因大多是信息“型號”不匹配。Prometheus 里明確查得到 jvm_memory_used_bytes但 Grafana 面板硬是畫不出來十次有八次是面板里的 PromQL 用了另一個指標名。還有一個隱蔽原因是 label 不匹配面板用 jobxxx 過濾但你的采集配置里 job 叫 releases, 自然就查不到。排查路徑很明確在 Grafana Explore 里手動執(zhí)行指標查詢能查到數(shù)據(jù)說明存儲鏈路沒問題問題一定在面板變量層。依次檢查數(shù)據(jù)源、 panel 的 PromQL、變量里的 label 條件。第三方面板在容器環(huán)境里尤其容易踩這個坑所以我前面才建議大家干脆自己建面板。5.5 生產(chǎn)出問題時正確的排查順序是什么監(jiān)控裝好以后真正考驗人的是生產(chǎn)出問題時你能不能穩(wěn)住心態(tài)按順序排查。我的習慣是這樣的先看監(jiān)控大盤的“三件套”堆內(nèi)存、GC 耗時、容器內(nèi)存。十秒鐘內(nèi)判斷問題是內(nèi)存趨勢型持續(xù)上升、瞬時沖擊型流量突刺還是 GC 暫停型。如果內(nèi)存異常下一個動作是抓堆 dump 或用 jmap -histo 看對象分布目標行業(yè)是找實例數(shù)暴漲的對象類型。如果線程異常用 jstack 看線程狀態(tài)尤其關注 BLOCKED 和 WAITING 狀態(tài)占比。如果都不明確再上 Arthas 做在線診斷看請求鏈路里哪些方法耗時異常。這個順序的正確之處在于它把“成本從低到高”的操作排在最前??幢O(jiān)控是零成本的抓 dump 有停頓風險Arthas 在線診斷是侵入操作所以這些動作必須靠后在確認需要時再執(zhí)行。繞了這么大一圈最后分享一個我的個人習慣監(jiān)控系統(tǒng)做完之后一定要主動做一次演練——手動把堆內(nèi)存調(diào)小幾個百分點或者模擬一次內(nèi)存泄漏看看告警會不會在五分鐘內(nèi)響起來。只有真的把你叫醒過這套系統(tǒng)才不算白裝。容器里跑 JVM 并不玄核心就是把資源邊界告訴它把指標通道打開再把日志交出來剩下的事就是不斷在實戰(zhàn)里修正閾值和規(guī)則。這套鏈路你按上面步驟搭完基本就比大多數(shù)團隊的監(jiān)控體系要靠譜了。