杰瑞科技汇

Python用rrdtool如何高效绘制动态图表?

  1. 创建 RRD 数据库:定义数据结构,例如数据如何被存储、如何聚合(如平均值、最大值)。
  2. 更新 RRD 数据库:定期将新的数据点存入数据库。
  3. 从 RRD 数据库生成图表:将存储的数据可视化,生成 PNG、SVG 等格式的图片。

第零步:安装 rrdtool

你需要确保系统上安装了 rrdtool 的命令行工具和 Python 的绑定库。

Python用rrdtool如何高效绘制动态图表?-图1
(图片来源网络,侵删)

安装 rrdtool 命令行工具

  • 在 Debian/Ubuntu 上:

    sudo apt-get update
    sudo apt-get install rrdtool
  • 在 CentOS/RHEL/Fedora 上:

    sudo yum install rrdtool
    # 或者对于较新的系统
    sudo dnf install rrdtool
  • 在 macOS 上 (使用 Homebrew):

    brew install rrdtool

安装 Python 绑定库

Python 的 rrdtool 库通常通过 pip 安装。

Python用rrdtool如何高效绘制动态图表?-图2
(图片来源网络,侵删)
pip install rrdtool

第一步:创建 RRD 数据库 (rrdtool.create)

在存储任何数据之前,你必须先创建一个 RRD 文件,这个文件定义了你的数据结构,核心概念包括:

  • DS (Data Source): 数据源,定义了你存储的数据的类型,最常用的是 GAUGE(瞬时值,如温度)、COUNTER(计数器,如网络字节数,只会增加)、DERIVE(导出值,如速度,可以增加或减少)。
  • RRA (Round Robin Archive): 存储数据的方式,它定义了数据点如何被聚合和存储,你可以存储每5秒一个原始数据点,持续1小时;然后存储每5分钟的平均值,持续1天;再存储每小时的平均值,持续一个月。

示例代码:创建一个用于存储 CPU 使用率的 RRD 数据库

假设我们想每分钟记录一次 CPU 使用率(百分比),并保留以下数据:

  • 每分钟的平均值,保留 1 天 (1440 个点)。
  • 每小时的最大值,保留 1 周 (168 个点)。
  • 每天的平均值,保留 1 年 (365 个点)。
import rrdtool
import os
# 定义 RRD 文件名
rrd_file = 'cpu_usage.rrd'
# 如果文件已存在,先删除它以便于测试
if os.path.exists(rrd_file):
    os.remove(rrd_file)
# 定义创建 RRD 的参数
# 'start': 时间戳,表示数据库的起始时间,我们使用当前时间减去10秒,以确保第一个数据点能被接受。
# '--step': 默认的数据收集间隔,这里是60秒。
# 'DS:cpu_usage:GAUGE:120:0:100': 定义数据源
#   - DS:cpu_usage: 数据源的名称是 "cpu_usage"
#   - GAUGE: 数据类型是瞬时值
#   - 120: 心跳时间,如果在120秒内没有收到新数据,该数据点将被标记为未知 (U)。
#   - 0:100: 最小值和最大值,超出这个范围的数据将被视为无效。
# 'RRA:AVERAGE:0.5:1:1440': 定义归档
#   - AVERAGE: 聚合类型是平均值
#   - 0.5: xff (x-file factor),当在聚合窗口内未知数据点的比例超过这个值时,结果将是未知。
#   - 1: 聚合因子,将 1 个基本数据点(60秒)聚合成 1 个数据点。
#   - 1440: 保留的归档数据点数量,1分钟一个点 * 1440点 = 1440分钟 = 1天。
# 'RRA:MAX:0.5:60:168': 每小时的最大值 (60分钟聚合,保留168小时)
# 'RRA:AVERAGE:0.5:1440:365': 每天的平均值 (1440分钟=24小时聚合,保留365天)
rrdtool.create(
    rrd_file,
    '--start', 'now-10s',
    '--step', '60',
    'DS:cpu_usage:GAUGE:120:0:100',
    'RRA:AVERAGE:0.5:1:1440',  # 1天, 每分钟平均值
    'RRA:MAX:0.5:60:168',     # 1周, 每小时最大值
    'RRA:AVERAGE:0.5:1440:365' # 1年, 每天平均值
)
print(f"RRD 文件 '{rrd_file}' 创建成功。")

运行这段代码后,你会在当前目录下看到一个名为 cpu_usage.rrd 的文件,这个文件现在是一个空的、结构化的数据库。

Python用rrdtool如何高效绘制动态图表?-图3
(图片来源网络,侵删)

第二步:更新 RRD 数据库 (rrdtool.update)

我们需要模拟数据并定期更新到 RRD 文件中,在实际应用中,这部分代码会由你的监控脚本定时执行(使用 cronschedule 库)。

示例代码:更新 CPU 使用率数据

import rrdtool
import time
import random
rrd_file = 'cpu_usage.rrd'
# 模拟更新10次,每次间隔60秒
for i in range(10):
    # 获取当前时间戳 (格式: N)
    current_time = 'N'
    # 生成一个随机的 CPU 使用率 (0-100之间)
    cpu_value = random.uniform(10, 90)
    # 构建更新命令
    # 'update <rrd_file> <timestamp>:<value>'
    update_string = f"{current_time}:{cpu_value:.2f}"
    try:
        # 执行更新
        rrdtool.update(rrd_file, update_string)
        print(f"更新成功: 时间={current_time}, CPU使用率={cpu_value:.2f}%")
    except rrdtool.error as e:
        print(f"更新失败: {e}")
    # 等待60秒
    time.sleep(60)
print("数据更新完成。")

运行这个脚本后,你的 cpu_usage.rrd 文件就填充了10个数据点。


第三步:生成图表 (rrdtool.graph)

这是最有趣的部分——将数据可视化。rrdtool.graph 函数非常强大,可以生成各种复杂的图表。

示例代码:生成一个简单的 CPU 使用率折线图

import rrdtool
import os
rrd_file = 'cpu_usage.rrd'
output_png = 'cpu_usage_graph.png'
# 检查RRD文件是否存在
if not os.path.exists(rrd_file):
    print(f"错误: RRD 文件 '{rrd_file}' 不存在,请先创建并更新它。")
    exit()
# 定义图表参数
# 'graph <output_file> <options> <definition> <instruction>'
# <options>: 全局选项,如标题、大小、单位等
# <definition>: 定义图表中要显示的数据(从哪个RRA中取什么数据)
# <instruction>: 定义图表中的线条、区域等元素
graph_args = [
    output_png,
    # --- 全局选项 ---
    '--title', 'CPU 使用率监控',
    '--width', '800',
    '--height', '400',
    '--start', '-1h',  # 图表显示从1小时前开始的数据
    '--end', 'now',    # 到现在为止
    '--vertical-label', 'CPU 使用率 (%)',
    '--rigid',         # Y轴不会根据数据动态伸缩,而是固定在0-100
    '--upper-limit', '100', # Y轴上限
    '--lower-limit', '0',   # Y轴下限
    '--alt-autoscale', # 当数据范围不满足 --upper/--lower-limit 时,自动调整
    # --- 数据定义 ---
    # 'DEF:<name>=<rrd_file>:<ds_name>:< consolidation_function>'
    # DEF:my_cpu_data=cpu_usage.rrd:cpu_usage:AVERAGE
    #   - 定义一个名为 'my_cpu_data' 的数据,它从 'cpu_usage.rrd' 文件的 'cpu_usage' 数据源中,
    #     取 'AVERAGE' (平均值) 类型的数据。
    'DEF:my_cpu_data=' + rrd_file + ':cpu_usage:AVERAGE',
    # --- 图表元素 ---
    # 'LINE1/2/3:<data_source>#<color>:<label>'
    # 'AREA:<data_source>#<color>:<label>'
    'LINE1:my_cpu_data#00FF00:CPU使用率', # 绿色实线
    'GPRINT:my_cpu_data:LAST:当前值: %5.2lf %%', # 在图上打印最后一个值
    'GPRINT:my_cpu_data:AVERAGE:平均值: %5.2lf %%', # 打印平均值
    'GPRINT:my_cpu_data:MAX:最大值: %5.2lf %%\n' # 打印最大值并换行
]
try:
    # 生成图表
    rrdtool.graph(*graph_args)
    print(f"图表已成功生成并保存为 '{output_png}'")
except rrdtool.error as e:
    print(f"生成图表失败: {e}")

运行这段代码后,你会得到一个名为 cpu_usage_graph.png 的图片,显示过去一小时的 CPU 使用率折线图,并在图上标注了当前值、平均值和最大值。


高级示例:组合多个数据源

假设我们不仅监控 CPU,还监控内存使用率,并将它们画在同一个图表上进行对比。

创建一个包含两个数据源的 RRD 文件

# (创建数据库的代码)
rrdtool.create(
    'system_stats.rrd',
    '--start', 'now-10s',
    '--step', '60',
    # CPU 数据源
    'DS:cpu_usage:GAUGE:120:0:100',
    # 内存数据源 (假设总内存为16GB,使用百分比)
    'DS:mem_usage:GAUGE:120:0:100',
    # ... RRAs ...
    'RRA:AVERAGE:0.5:1:1440',
    'RRA:MAX:0.5:60:168',
    'RRA:AVERAGE:0.5:1440:365'
)

更新两个数据源

# (更新数据的代码)
for i in range(10):
    current_time = 'N'
    cpu_value = random.uniform(10, 90)
    mem_value = random.uniform(30, 80)
    # 一次性更新多个数据源
    update_string = f"{current_time}:{cpu_value:.2f}:{mem_value:.2f}"
    rrdtool.update('system_stats.rrd', update_string)
    time.sleep(60)

生成组合图表

# (生成图表的代码)
rrdtool.graph(
    'system_stats_graph.png',
    '--title', '系统资源监控',
    '--width', '800',
    '--height', '400',
    '--start', '-1h',
    '--end', 'now',
    '--vertical-label', '使用率 (%)',
    '--rigid',
    '--upper-limit', '100',
    '--lower-limit', '0',
    # 定义两个数据源
    'DEF:cpu_data=system_stats.rrd:cpu_usage:AVERAGE',
    'DEF:mem_data=system_stats.rrd:mem_usage:AVERAGE',
    # CPU 用绿色实线表示,并填充半透明区域
    'LINE1:cpu_data#00FF00:CPU',
    'AREA:cpu_data#00FF0033:CPU', # #33 是 20% 的透明度
    # 内存用蓝色虚线表示
    'LINE1:mem_data#0000FF:内存',
    # 添加图例
    'HRULE:50#FF000050:"警告线"', # 添加一条50%的红色虚线作为警告
)

这个高级示例展示了如何处理多个指标,并通过不同的线条样式和颜色来区分它们,甚至可以添加参考线。

功能 rrdtool 函数 描述
创建 rrdtool.create() 定义数据库结构 (DS, RRA)
更新 rrdtool.update() 向数据库中插入新的数据点
查询 rrdtool.fetch() 从数据库中提取原始数据(用于程序处理)
画图 rrdtool.graph() 将数据渲染成图片 (PNG, SVG 等)

rrdtool 的核心优势在于其高效的存储引擎(固定大小的环形数据库,不会无限增长)和强大的内置聚合功能,使其成为网络和系统监控领域的黄金标准,通过 Python 绑定,你可以轻松地将 rrdtool 集成到你的自动化监控和运维脚本中。

分享:
扫描分享到社交APP
上一篇
下一篇