歡迎光臨
每天分享高質量文章

避免使用 -XX : +UseGCLogFileRotation

 

編譯:唐尤華

連結:dzone.com/articles/try-to-avoid-xxusegclogfilerotation

 

開發者透過 JVM 引數 `-XX:+UseGCLogFileRotation` 實現 GC 日誌輪轉。

 

像下麵這樣:

 

```shell
"-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/home/GCEASY/gc.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=20M"
```

 

指定上述引數,當日誌檔案大小增加到 20MB,JVM 會進行 GC 日誌輪轉生成最多5個檔案,副檔名分別為 `gc.log.0`、`gc.log.1`、`gc.log.2`、`gc.log.3` 和 `gc.log.4`。

 

這種做法會帶來以下問題:

 

1. 丟失舊的 GC 日誌

 

如果設定引數 `-XX:NumberOfGCLogFiles=5`,一段時間過後會建立5個 GC 日誌檔案:

 

  • gc.log.0 ← `最老的 GC 日誌內容`
  • gc.log.1
  • gc.log.2
  • gc.log.3
  • gc.log.4 ← `最新的 GC 日誌內容`

 

最新的 GC 日誌寫入 `gc.log.4`,而過去的 GC 日誌內容存入 `gc.log.0`。

 

使用 `-XX:NumberOfGCLogFiles` 配置時,如果應用不斷產生更多的 GC 日誌,`gc.log.0` 中的舊日誌內容會被刪除,新產生的 GC 事件將寫入 `gc.log.0`。這意味著日誌內容完整性早到破壞,即無法看到所有 GC 事件。

 

2. GC 日誌混合

 

假設某個應用建立了5個 GC 日誌檔案:

 

  • gc.log.0
  • gc.log.1
  • gc.log.2
  • gc.log.3
  • gc.log.4

 

接著,如果重啟這個應用,現在新 GC 日誌會寫入 `gc.log.0`。重啟前的日誌資訊儲存在 `gc.log.1`, `gc.log.2`, `gc.log.3`, `gc.log.4` 中。

 

  • gc.log.0 ← 重啟後的 GC 日誌檔案內容
  • gc.log.1 ← 重啟前的 GC 日誌檔案內容
  • gc.log.2 ← 重啟前的 GC 日誌檔案內容
  • gc.log.3 ← 重啟前的 GC 日誌檔案內容
  • gc.log.4 ← 重啟前的 GC 日誌檔案內容

 

因此,重啟後的 GC 新日誌與舊日誌混在一起。要解決這個問題,可以在重啟應用前把所有舊日誌移動到一個獨立的檔案夾中。

 

3. 將 GC 日誌轉發到中央儲存

 

採用這種方法,當前寫入的日誌檔案會標記 `.current` 擴充套件,例如當前寫入 `gc.log.3`,會命名為 `gc.log.3.current`。

 

如果要把 GC 日誌從單個伺服器彙總到中央儲存,大多數 DevOps 工程師會使用 `rsyslog`。然而,正如[這篇部落格][1]討論的那樣,這種命名方式給 `rsyslog` 帶來了巨大挑戰。

 

[1]:http://www.planetcobalt.net/sdb/forward_gc_logs.shtml

 

4. 工具

 

現在,有許多像 [GCeasy][2]、GCViewer 這樣的工具可以用來分析 GC 日誌,支援上傳多個日誌檔案。

 

[2]:https://gceasy.io/

 

5. 推薦的解決方案

 

當 JVM 重啟後可以為 GC 日誌加上時間戳作為字尾,這樣 GC 日誌檔案路徑能夠保持唯一。這樣,新日誌就不會改寫掉舊的 GC 日誌。透過為 GC 日誌檔案指定 `%t` 字尾可以實現,像下麵這樣:

 

```shell
"-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/home/GCEASY/gc-%t.log"
```

 

`%t` 字尾格式生成的時間戳格式為 `YYYY-MM-DD_HH-MM-SS`。因此,生成的日誌檔案名看起來像這樣 `gc-2019-01-29_20-41-47.log`。

 

這種簡單的方法解決了 `-XX:+UseGCLogFileRotation` 引數的所有缺點。

    贊(0)

    分享創造快樂