1 出入网流量统计与内存使用统计脚本明细

1.1 出入网流量统计

redis-cli -h 172.21.204.201 client list | awk '
{
    # 初始化变量
    ip = "";
    omem = 0;        # 出网:Redis→客户端的输出缓冲区(字节)
    argv_mem = 0;    # 入网1:客户端命令参数内存(字节)
    qbuf = 0;        # 入网2:客户端输入缓冲区(字节)
    
    # 解析每行字段(key=value 格式)
    for (i = 1; i <= NF; i++) {
        split($i, kv, "=");  # 分割键值对
        key = kv[1];
        value = kv[2];
        
        # 提取客户端IP(去掉端口,如 172.21.204.200:46102172.21.204.200if (key == "addr") {
            split(value, addr_parts, ":");
            ip = addr_parts[1];
        }
        # 提取出网相关字段(转为数值)
        else if (key == "omem") {
            omem = value + 0;
        }
        # 提取入网相关字段(转为数值)
        else if (key == "argv-mem") {
            argv_mem = value + 0;
        }
        else if (key == "qbuf") {
            qbuf = value + 0;
        }
    }
    
    # 按IP分组累加(跳过空IP)
    if (ip != "") {
        conn_count[ip]++;                  # 统计连接数
        in_traffic[ip] += (argv_mem + qbuf);# 累计入网流量(字节)= 命令参数+输入缓冲区
        out_traffic[ip] += omem;           # 累计出网流量(字节)= 输出缓冲区
    }
}

# 统计完成后输出(直接手动转换单位:字节→MB,避免函数)
END {
    # 打印表头(左对齐,确保格式整齐)
    printf "%-20s %-8s %-25s %-25s\n", 
           "客户端IP", "连接数", "入网流量(MB)", "出网流量(MB)";
    printf "%-20s %-8s %-25s %-25s\n", 
           "--------", "--------", "------------", "------------";
    
    # 遍历所有客户端IP,计算并输出结果(1MB = 1024*1024 字节)
    for (ip in conn_count) {
        in_mb = in_traffic[ip] / (1024 * 1024);  # 入网流量转MB
        out_mb = out_traffic[ip] / (1024 * 1024);# 出网流量转MB
        printf "%-20s %-8d %.6f                  %.2f\n", 
               ip, conn_count[ip], in_mb, out_mb;
    }
}
'

输出:

客户端IP                连接数      入网流量(MB)                  出网流量(MB)                 
--------             -------- ------------              ------------             
172.21.204.200       8        21.448511                  0.00
172.21.204.201       1        0.000034                  0.00

1.2 内存使用统计

redis-cli client list | awk '
# 1. 解析 client list 输出,提取 IP、omem、tot-mem、argv-mem
{
    # 初始化变量
    ip = ""; omem = 0; tot_mem = 0; argv_mem = 0;
    # 遍历每个字段(格式:key=value)
    for (i=1; i<=NF; i++) {
        split($i, kv, "=");  # 分割 key 和 value(如 "addr=172.21.204.200:46102" → kv[1]="addr", kv[2]="172.21.204.200:46102"if (kv[1] == "addr") {
            split(kv[2], addr, ":");  # 提取 IP(去掉端口,如 "172.21.204.200:46102" → addr[1]="172.21.204.200")
            ip = addr[1];
        } else if (kv[1] == "omem") {
            omem = kv[2];
        } else if (kv[1] == "tot-mem") {
            tot_mem = kv[2];
        } else if (kv[1] == "argv-mem") {
            argv_mem = kv[2];
        }
    }
    # 按 IP 分组累加(存储为字节)
    sum_omem[ip] += omem;
    sum_tot_mem[ip] += tot_mem;
    sum_argv_mem[ip] += argv_mem;
    # 统计每个 IP 的连接数
    conn_count[ip]++;
}

# 2. 处理完所有行后,格式化输出结果
END {
    # 打印表头(左对齐,占20字符)
    printf "%-20s %-8s %-20s %-20s %-20s\n", 
           "客户端IP", "连接数", "omem总和(MB)", "tot-mem总和(MB)", "argv-mem总和(MB)";
    printf "%-20s %-8s %-20s %-20s %-20s\n", 
           "--------", "--------", "------------", "--------------", "--------------";
    
    # 遍历所有 IP,输出统计结果(字节转 MB:除以 1024*1024,保留2位小数)
    for (ip in sum_omem) {
        omem_mb = sum_omem[ip] / (1024*1024);
        tot_mem_mb = sum_tot_mem[ip] / (1024*1024);
        argv_mem_mb = sum_argv_mem[ip] / (1024*1024);
        printf "%-20s %-8d %.2f               %.2f               %.6f\n", 
               ip, conn_count[ip], omem_mb, tot_mem_mb, argv_mem_mb;
    }
}
'

输出:

客户端IP                连接数      omem总和(MB)           tot-mem总和(MB)        argv-mem总和(MB)      
--------             -------- ------------         --------------       --------------      
172.21.204.200       10       108.00               108.20               0.000000
127.0.0.1            1        0.00               0.06               0.000010

1.3 两个脚本合一

#!/bin/bash
# Redis客户端全量指标单行统计脚本
# 功能:一次性统计客户端IP、连接数、内存指标(omem/tot-mem/argv-mem)、流量指标(入网/出网),并单行展示

redis-cli -h 172.21.204.201 client list | awk '
{
    # 初始化所有待解析的变量(避免空值影响计算)
    ip = "";
    omem = 0;    # 内存指标:Redis→客户端的输出缓冲区(字节)
    tot_mem = 0; # 内存指标:客户端总内存占用(字节)
    argv_mem = 0;# 内存指标:客户端命令参数占用内存(字节)
    qbuf = 0;    # 流量指标:客户端→Redis的输入缓冲区(字节)

    # 解析client list输出的key=value格式字段(逐字段处理)
    for (i = 1; i <= NF; i++) {
        split($i, kv, "=");  # 分割键值对(例:"addr=172.21.204.200:46102" → kv[1]="addr", kv[2]="172.21.204.200:46102")
        key = kv[1];
        value = kv[2];

        # 提取客户端IP(去除端口号,仅保留IP地址,避免同一IP不同端口重复统计)
        if (key == "addr") {
            split(value, addr_parts, ":");
            ip = addr_parts[1];
        }
        # 提取内存相关字段(转为数值类型,防止字符串累加导致计算错误)
        else if (key == "omem")      omem = value + 0;
        else if (key == "tot-mem")   tot_mem = value + 0;
        else if (key == "argv-mem")  argv_mem = value + 0;
        # 提取流量相关字段(输入缓冲区,用于计算入网总流量)
        else if (key == "qbuf")      qbuf = value + 0;
    }

    # 按IP分组累加指标(跳过空IP,避免无效数据干扰统计结果)
    if (ip != "") {
        conn_count[ip]++;                  # 统计每个IP的客户端连接数
        sum_omem[ip] += omem;              # 累加输出缓冲区内存(omem)
        sum_tot_mem[ip] += tot_mem;        # 累加客户端总内存(tot-mem)
        sum_argv_mem[ip] += argv_mem;      # 累加命令参数内存(argv-mem)
        in_traffic[ip] += (argv_mem + qbuf);# 计算入网流量:命令参数内存 + 输入缓冲区(字节)
        out_traffic[ip] += omem;           # 计算出网流量:输出缓冲区(omem,字节)
    }
}

# 最终输出逻辑:所有指标合并为一行展示,保持格式对齐
END {
    # 表头配置(左对齐,固定字段宽度,确保多IP场景下列对齐)
    printf "%-20s %-8s %-18s %-18s %-18s %-22s %-22s\n",
           "客户端IP", "连接数", "omem总和(MB)", "tot-mem总和(MB)", "argv-mem总和(MB)", "入网流量(MB)", "出网流量(MB)";
    # 表头分隔线(与表头字段宽度一一对应,提升可读性)
    printf "%-20s %-8s %-18s %-18s %-18s %-22s %-22s\n",
           "--------", "--------", "------------", "--------------", "--------------", "------------", "------------";

    # 遍历所有客户端IP,输出单行全量指标(保持与表头格式一致)
    for (ip in conn_count) {
        # 单位转换:字节 → MB(保留原统计精度,确保数据一致性)
        omem_mb = sum_omem[ip] / (1024 * 1024);       # omem:保留2位小数
        tot_mem_mb = sum_tot_mem[ip] / (1024 * 1024); # tot-mem:保留2位小数
        argv_mem_mb = sum_argv_mem[ip] / (1024 * 1024);# argv-mem:保留6位小数(适配小数值场景)
        in_mb = in_traffic[ip] / (1024 * 1024);       # 入网流量:保留6位小数
        out_mb = out_traffic[ip] / (1024 * 1024);     # 出网流量:保留2位小数

        # 数据行输出(格式与表头严格匹配,确保列对齐)
        printf "%-20s %-8d %.2f               %.2f               %.6f               %.6f                  %.2f\n",
               ip, conn_count[ip], omem_mb, tot_mem_mb, argv_mem_mb, in_mb, out_mb;
    }
}
'

 输出:

客户端IP                连接数      omem总和(MB)         tot-mem总和(MB)      argv-mem总和(MB)     入网流量(MB)               出网流量(MB)              
--------             -------- ------------       --------------     --------------     ------------           ------------          
172.21.204.200       8        0.00               92.16               0.000113               25.296741                  0.00
172.21.204.201       1        0.00               0.06               0.000010               0.000034                  0.00

2 核心联系:基础逻辑与数据源一致

两个脚本的底层实现和基础目标高度相似,都是针对 Redis 客户端连接的IP 级分组统计,具体共同点如下:

  1. 同一数据源:均基于redis-cli client list的输出(该命令返回所有 Redis 客户端的详细连接信息,格式为key=value键值对)。
  2. 同一分组维度:均按 “客户端 IP” 分组(从addr字段中提取 IP,剔除端口号,如172.21.204.200:46102172.21.204.200)。
  3. 共同统计项:均会统计 “每个 IP 的客户端连接数”(conn_count[ip]++)。
  4. 相同单位转换:均将 Redis 返回的 “字节(Byte)” 单位转换为 “兆字节(MB)”(除以1024*1024)。
  5. 相似输出格式:均用printf格式化输出表头和结果,确保可读性。

3 关键区别:统计目标与指标定义不同

两个脚本的核心差异在于 **“统计什么”**—— 第一个脚本聚焦 “出入网流量”,第二个脚本聚焦 “Redis 客户端的特定内存指标总和”,具体差异可通过下表清晰对比:

对比维度第一个脚本(出入网流量统计)第二个脚本(内存指标总和统计)
核心统计目标 量化客户端与 Redis 之间的数据传输流量(入网 / 出网) 量化客户端占用 Redis 的各类内存资源总和
提取的核心字段 1. addr(提 IP)
2. omem(输出缓冲区)
3. argv-mem(命令参数内存)
4. qbuf(输入缓冲区)
1. addr(提 IP)
2. omem(输出缓冲区)
3. tot-mem(客户端总内存)
4. argv-mem(命令参数内存)
指标定义逻辑 - 入网流量:argv-mem + qbuf(客户端发给 Redis 的数据总和)
- 出网流量:omem(Redis 发给客户端的数据总和)
- omem 总和:所有连接的omem累加(输出缓冲区总占用)
- tot-mem 总和:所有连接的tot-mem累加(客户端总内存占用)
- argv-mem 总和:所有连接的argv-mem累加(命令参数总内存)
输出结果列 客户端 IP、连接数、入网流量 (MB)、出网流量 (MB) 客户端 IP、连接数、omem 总和 (MB)、tot-mem 总和 (MB)、argv-mem 总和 (MB)
适用场景 排查 “客户端与 Redis 之间的流量瓶颈”(如哪个 IP 流量过大) 排查 “客户端占用 Redis 内存过高的原因”(如总内存 /tot-mem 异常)

4 关键字段含义补充(理解差异的核心)

要彻底区分两者,必须先明确redis-cli client list中关键字段的实际意义(这是两个脚本指标定义的基础):

字段名含义解释对应方向 / 用途
addr 客户端地址,格式为IP:端口 提取客户端 IP 的唯一来源
omem Redis 为客户端分配的输出缓冲区大小(字节),存储 Redis 待发给客户端的数据 对应 “出网流量”(Redis→客户端)
argv-mem 客户端发送的命令参数所占用的内存(字节) 对应 “入网流量” 的一部分(客户端→Redis)
qbuf Redis 为客户端分配的输入缓冲区大小(字节),存储客户端待处理的命令 对应 “入网流量” 的另一部分(客户端→Redis)
tot-mem 客户端占用 Redis 的总内存大小(字节),包含:输入缓冲区、输出缓冲区、命令队列等所有内存 客户端内存占用的 “总量” 指标

5 总结:何时用哪个脚本?

  1. 当你想知道 “哪个客户端 IP 与 Redis 之间的数据传输量最大”(比如排查带宽占用、网络瓶颈)→ 用第一个脚本(出入网流量统计)。
  2. 当你想知道 “哪个客户端 IP 占用 Redis 内存最多,以及具体占用在哪些部分”(比如 Redis 内存使用率过高,排查客户端内存泄漏)→ 用第二个脚本(内存指标总和统计)。

简单来说:流量脚本看 “数据传输量”,内存脚本看 “资源占用量”,二者从不同维度反映客户端与 Redis 的交互状态。
 posted on 2025-09-06 11:43  xibuhaohao  阅读(4)  评论(0)    收藏  举报