突破性能瓶頸!Grafana 自動生成圖表的深度優化實戰
引言
我們上篇文章講解了如何生成 Grafana Dashboard 的 PDF 文檔,這篇文章我們來討論和實施下我們的相關優化,這個對于我們后面的自動化生成 PDF 很重要。
開始
Grafana Image Renderer 插件依賴 Chromium 來渲染圖像,渲染每張圖片時會啟動一個 Chromium 實例,這些實例可能會占用較多的 CPU 和內存資源。當多個渲染任務同時進行時,如果服務器的資源不足,就可能導致渲染失敗。
我們先簡單了解下什么是 Chromium:
什么是 Chromium?
? Chromium 是由 Google 維護的一個開源項目,最初發布于 2008 年。
? 它是一個瀏覽器內核和平臺,提供了網頁渲染和瀏覽的核心功能。
? Chromium 的目標:提供一個快速、穩定和安全的瀏覽體驗。
就比如這個,當時做好之后,把鏈接給同事們訪問體驗下,結果訪問量太大,直接給它干不行了,對于這樣的結果,我肯定不滿意,所以,就直接給它上優化方案!!!
圖片
圖片
那么在這之前,這個問題到底是誰引發的呢,是 Grafana 呢,還是 Grafana-image-render 呢,還是 Grafana-reporter 呢?
大家可以提前思考下這個問題。
揭秘環節
你需要修改 Grafana 的配置,而不是 Grafana Image Renderer 插件本身的配置。因為 "Concurrent server side render limit reached" 錯誤是由 Grafana 的渲染請求并發限制引起的,而這個限制是通過 Grafana 主配置來管理的。
Grafana 控制并發渲染請求
? Grafana 處理圖像渲染時,會限制同時發起的渲染任務數量,這個限制通過 grafana.ini 或環境變量進行管理。
? Grafana Image Renderer 插件只是負責處理具體的渲染任務,但受 Grafana 的限制約束。
Image Renderer 插件無獨立配置
? Image Renderer 插件本身不對并發請求施加額外限制,它只在收到 Grafana 發起的請求時開始渲染任務。
具體的原因
并發渲染限制
? Grafana Image Renderer 默認有并發渲染限制(通常是 5 個并發任務),超過限制后會拋出此錯誤。
? 在渲染多個報告或多個圖表時,如果任務數超過限制,就會導致渲染失敗。
系統資源不足
? Grafana Image Renderer 插件依賴 Chromium 運行環境,它可能占用較多的 CPU 和內存資源。如果資源不足,也可能出現渲染失敗。
長時間任務或延遲
? 渲染時間過長(復雜的儀表板或大數據量)可能導致 Grafana 達到超時,無法繼續處理后續任務。
開始解決
這邊直接修改 Grafana 的配置文件,添加優化環境變量:
k edit sts kube-prometheus-stack-grafana -nmonitoring
·····
env:
- name: GF_RENDERING_CONCURRENT_RENDER_REQUEST_LIMIT
value: "10"
·····
我們再看一下:
圖片
圖片
可以看到,這個優化參數給的有點少,這回直接加到 70 :
k edit sts kube-prometheus-stack-grafana -nmonitoring
·····
env:
- name: GF_RENDERING_CONCURRENT_RENDER_REQUEST_LIMIT
value: "70"
·····
但是這顯然不夠的,只優化 Grafana,對于之后的訪問量是不夠的,所以,這邊又參考了很多的資料,對 Grafana-image-render 和相關組件進行了更深層次的優化:
分為四部分:
? Grafana-image-render Resources 的優化
? Grafana-image-render 配置文件的優化
? Grafana-image-render 副本的優化
? 相關組件的 Ingress 的優化
Grafana-image-render 的 Resources 的優化
k edit sts grafana-image-renderer -nmonitoring
·····
resources:
limits:
cpu: "2" # 限制 CPU 使用的上限
memory: "2Gi" # 限制內存使用的上限
requests:
cpu: "1" # 最低需要的 CPU
memory: "1Gi" # 最低需要的內存
·····
副本的優化
k edit sts grafana-image-renderer -nmonitoring
·····
spec:
replicas: 3
·····
Ingress 的優化
這邊的 Ingress 也嘗試優化下,優化的有 Grafana 還有 Grafana-image-render 的 Ingress 配置文件,都加上:
nginx.ingress.kubernetes.io/proxy-read-timeout: "300"
nginx.ingress.kubernetes.io/proxy-send-timeout: "300"
nginx.ingress.kubernetes.io/limit-connections: "50"
Grafana-image-render 的參數優化
啟用 Chromium 的無沙盒模式
禁用 Chromium 的沙盒模式。這可以減少權限問題和資源使用,同時加速渲染進程,但需要確保你的環境是可信任的:
args:
- "--no-sandbox"
但是這邊的這個參數優化失敗了
圖片
錯誤信息表明:--no-sandbox 參數可能被傳遞到了容器內部,但由于路徑或參數格式錯誤導致無法識別。
所以這邊這個優化參數,需要改進下了,這邊去了 Grafana 的官網[1]。
就找到了這個配置文件,既然不能直接在 YAML 文件添加,那就把文件掛載進去:
{
"service": {
"host": null,
"port": 8081,
"protocol": "http",
"certFile": "",
"certKey": "",
"metrics": {
"enabled": true, // 啟用性能指標,便于監控性能瓶頸
"collectDefaultMetrics": true,
"requestDurationBuckets": [1, 5, 7, 9, 11, 13, 15] // 精簡桶數,減少不必要的性能開銷
},
"logging": {
"level": "info",
"console": {
"json": true,
"colorize": false
}
},
"security": {
"authToken": "-" // 保持默認值,但可以根據需要加強認證
}
},
"rendering": {
"chromeBin": null,
"args": ["--no-sandbox", "--disable-gpu", "--disable-dev-shm-usage"], // 添加 --disable-dev-shm-usage 以優化內存
"ignoresHttpsErrors": false,
"timezone": null, // 設置為您實際應用的時區以減少渲染時間問題
"acceptLanguage": "en-US", // 設置默認語言以避免語言渲染問題
"width": 1200, // 根據實際需要調整默認寬度
"height": 800, // 根據實際需要調整默認高度
"deviceScaleFactor": 2, // 提升分辨率,但保持適當值,避免性能損失
"maxWidth": 3840, // 增加最大寬度以支持高分辨率渲染
"maxHeight": 2160, // 增加最大高度
"maxDeviceScaleFactor": 3, // 減小 scale factor,避免超高分辨率導致性能問題
"pageZoomLevel": 1, // 保持默認值
"headed": false, // 保持 headless 模式
"mode": "default",
"emulateNetworkConditions": false, // 保持默認值,不模擬網絡條件
"clustering": {
"monitor": true, // 啟用監控集群,以便檢測集群性能
"mode": "browser", // 使用 browser 模式
"maxConcurrency": 10, // 提升最大并發數(根據服務器性能調整)
"timeout": 60 // 增加超時時間以處理復雜圖表
},
"verboseLogging": false,
"dumpio": false,
"timingMetrics": true // 啟用時間指標以分析性能瓶頸
}
}
1.服務端優化
? 啟用性能監控 (metrics.enabled: true): 開啟服務端性能監控,可以通過 Grafana 或其他工具查看渲染器的性能表現,識別瓶頸。
2.渲染器參數調整
? 禁用 GPU (--disable-gpu): 對于 headless 模式的 Chromium,GPU 通常沒有意義,禁用它可以節省資源。
? 啟用 --disable-dev-shm-usage: 此參數可以解決共享內存不足的問題,尤其是當容器在 Kubernetes 中運行時。
? 合理調整 maxWidth 和 maxHeight: 避免渲染過大的圖表分辨率,過高的值可能導致渲染時間過長。
? 提升并發 (maxConcurrency): 在 clustering 配置中提升并發上限,視服務器性能(CPU 和內存)增加值,例如 5 → 10。
? 增加超時 (timeout): 對于復雜圖表,可能需要更長時間完成渲染,因此增加超時時間到 60 秒。
3.時間和語言設置
? 明確時區 (timezone): 如果您的圖表涉及時間數據,指定一個明確的時區(如 "timezone": "UTC" 或 "Asia/Shanghai") 以減少渲染時間的不確定性。
? 默認語言 (acceptLanguage): 指定默認語言,如 en-US,減少渲染器加載不必要語言資源的時間。
4.內存與分辨率
? 默認分辨率優化 (width, height): 根據實際需求調整為 1200x800,避免渲染器超出必要范圍。
? maxDeviceScaleFactor 降低到 3: 將 scale factor 限制到 3,避免過高分辨率耗費過多資源。
5.調整日志與監控
? 啟用集群監控 (clustering.monitor: true): 啟用后可以幫助您監控渲染器的資源分配和性能表現。
? 啟用時間指標 (timingMetrics: true): 啟用后可以記錄任務的詳細耗時數據,便于優化。
注意,如果你這邊要把文件掛載進去的話,需要把相應的這些注釋和沒有用的去除掉,上面只是為了讓大家理解每一個參數的作用,我們這里需要用下面這個:
{
"service": {
"host": null,
"port": 8081,
"protocol": "http",
"certFile": "",
"certKey": "",
"metrics": {
"enabled": true,
"collectDefaultMetrics": true,
"requestDurationBuckets": [1, 5, 7, 9, 11, 13, 15]
},
"logging": {
"level": "info",
"console": {
"json": true,
"colorize": false
}
},
"security": {
"authToken": "-"
}
},
"rendering": {
"chromeBin": null,
"args": ["--no-sandbox", "--disable-gpu", "--disable-dev-shm-usage"],
"ignoresHttpsErrors": false,
"timezone": "Asia/Shanghai",
"acceptLanguage": "zh-CN",
"width": 1200,
"height": 800,
"deviceScaleFactor": 2,
"maxWidth": 3840,
"maxHeight": 2160,
"maxDeviceScaleFactor": 3,
"pageZoomLevel": 1,
"headed": false,
"mode": "default",
"emulateNetworkConditions": false,
"clustering": {
"monitor": true,
"mode": "browser",
"maxConcurrency": 70,
"timeout": 60
},
"verboseLogging": false,
"dumpio": false,
"timingMetrics": true
}
}
創建一個 ConfigMap:
k create cm grafana-image-render-config --from-file=config.json -nmonitoring
然后修改我們的部署文件,重新部署,以下的這個文件,也是我們最終的一個優化好的 YAML 文件:
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: grafana-image-renderer
namespace: monitoring
labels:
app: grafana-image-renderer
spec:
serviceName: grafana-image-renderer-headless
replicas: 3
selector:
matchLabels:
app: grafana-image-renderer
template:
metadata:
labels:
app: grafana-image-renderer
spec:
containers:
- name: renderer
image: grafana/grafana-image-renderer:latest
ports:
- containerPort: 8081
env:
- name: RENDERER_CALLBACK_URL
value: "https://grafana.example.com" # Grafana 服務地址
resources:
limits:
cpu: "2" # 限制 CPU 使用的上限
memory: "2Gi" # 限制內存使用的上限
requests:
cpu: "1" # 最低需要的 CPU
memory: "1Gi" # 最低需要的內存
volumeMounts: # 添加 volumeMount 掛載 ConfigMap
- name: renderer-config
mountPath: /usr/src/app/config.json # 掛載到容器內的路徑
subPath: config.json # 只掛載 ConfigMap 中的 config.json 文件
volumes: # 定義 ConfigMap volume
- name: renderer-config
configMap:
name: grafana-image-renderer-config # 引用 ConfigMap 的名稱
這一波優化,讓它從船員直接晉升到了船長。
總結
以上就是我們的本篇文章,希望大家多多支持,接下來還會出更多優質文章,大家敬請期待。
如果你這邊還有什么好玩的好用的想法,可以聯系我。
如果你這邊還有什么更好的優化方案或者……
引用鏈接
[1] 官網: https://grafana.com/docs/grafana/latest/setup-grafana/image-rendering/