突破性能瓶颈!Grafana 自动生成图表的深度优化实战

Grafana Image Renderer 插件依赖 Chromium 来渲染图像,渲染每张图片时会启动一个 Chromium 实例,这些实例可能会占用较多的 CPU 和内存资源。当多个渲染任务同时进行时,如果服务器的资源不足,就可能导致渲染失败。
首页 新闻资讯 行业资讯 突破性能瓶颈!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_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 的优化

Grafana-image-render 的 Resources 的优化

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 的优化

这边的 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: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/


43    2024-12-31 08:16:15    Grafana Chromium CPU