引言
我们上篇文章讲解了如何生成 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/