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