我们上篇文章讲解了如何生成 Grafana Dashboard 的 PDF 文档,这篇文章我们来讨论和实施下我们的相关优化,这个对于我们后面的自动化生成 PDF 很重要。
Grafana Image Renderer 插件依赖 Chromium 来渲染图像,渲染每张图片时会启动一个 Chromium 实例,这些实例可能会占用较多的 CPU 和内存资源。当多个渲染任务同时进行时,如果服务器的资源不足,就可能导致渲染失败。
我们先简单了解下什么是 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.ini 或环境变量进行管理。
• Grafana Image Renderer 插件只是负责处理具体的渲染任务,但受 Grafana 的限制约束。
• 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_LIMITvalue:"10"·····
我们再看一下:
图片
图片
可以看到,这个优化参数给的有点少,这回直接加到 70 :
k edit sts kube-prometheus-stack-grafana-nmonitoring ····· env:-name: GF_RENDERING_CONCURRENT_RENDER_REQUEST_LIMITvalue:"70"·····
但是这显然不够的,只优化 Grafana,对于之后的访问量是不够的,所以,这边又参考了很多的资料,对 Grafana-image-render 和相关组件进行了更深层次的优化:
分为四部分:
• Grafana-image-render Resources 的优化
• Grafana-image-render 配置文件的优化
• Grafana-image-render 副本的优化
• 相关组件的 Ingress 的优化
k edit sts grafana-image-renderer-nmonitoring ····· resources: limits: cpu:"2"# 限制 CPU 使用的上限memory:"2Gi"# 限制内存使用的上限requests: cpu:"1"# 最低需要的 CPUmemory:"1Gi"# 最低需要的内存·····
k edit sts grafana-image-renderer-nmonitoring ····· spec: replicas:3·····
这边的 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"
启用 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:3selector: matchLabels: app: grafana-image-renderer template: metadata: labels: app: grafana-image-renderer spec: containers:-name: renderer image: grafana/grafana-image-renderer:latest ports:-containerPort:8081env:-name: RENDERER_CALLBACK_URLvalue:"https://grafana.example.com"# Grafana 服务地址resources: limits: cpu:"2"# 限制 CPU 使用的上限memory:"2Gi"# 限制内存使用的上限requests: cpu:"1"# 最低需要的 CPUmemory:"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/