# redis-memory-stat **Repository Path**: chazzorg/redis-memory-stat ## Basic Information - **Project Name**: redis-memory-stat - **Description**: 零依赖 Go 小工具:通过 SCAN + MEMORY USAGE 统计 Redis 各 DB 与键前缀的内存占用,输出 TOP N(支持并发、.env、文件输出)。 - **Primary Language**: Go - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-12-15 - **Last Updated**: 2025-12-15 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # redis-memory-stat 一个**零第三方依赖**的小工具:使用 **Redis RESP 协议**连接 Redis,通过 `SCAN` + `MEMORY USAGE` 统计**各 DB**与**键前缀**的内存占用,并将结果同时输出到终端与指定文件。 > 适用场景:快速定位「哪个 DB / 哪些业务前缀」占用内存最多。 ## 功能 - 按 DB 汇总内存占用,并标出占用最大的 DB。 - 按键前缀(可配置截取长度)聚合统计:占用、键数量、主要分布 DB,并输出 TOP N。 - 支持自动读取 `INFO keyspace` 获取 DB 列表,或手动指定 DB。 - 通过协程并发扫描多个 DB(可配置 worker 数量)。 - `expire` 模式:为指定 DB 下、匹配前缀的所有键批量设置过期时间。 - `ttlstat` 模式:统计长有效期/永久 key 的分布(DB、前缀)、TTL 分桶,并可选统计对应内存。 - 配置可来自 `.env`,命令行参数可覆盖 `.env` 默认值。 - 输出同时写入 stdout 与文件(可关闭文件输出)。 ## 快速开始 项目仅使用 Go 标准库,无需额外依赖。 在项目根目录直接运行(默认模式 `stat`): ```bash go run . ``` 示例:连接远程 Redis,仅扫描 DB 0 和 1,输出前缀 TOP 50: ```bash go run . stat \ -host 10.0.0.12 -port 6379 -password '***' \ -dbs 0,1 -prefixLen 6 -limit 50 \ -workers 4 -scanCount 500 -timeout 5s \ -output redis_memory_stat.out ``` 示例:为 DB 2 下 `sess:` 前缀的所有键设置 24 小时过期: ```bash go run . expire \ -host 10.0.0.12 -port 6379 -password '***' \ -db 2 -prefix sess: -ttl 24h -scanCount 500 -pipeSize 500 ``` 示例:统计 DB 0、1 下前缀截断 6 的长 TTL/永久 key 分布(长 TTL 定义为 TTL >= 7d): ```bash go run . ttlstat \ -host 10.0.0.12 -port 6379 -password '***' \ -dbs 0,1 -prefixLen 6 -ttlMin 168h \ -ttlBuckets "1h,6h,24h,168h,720h" \ -withMemory=false -workers 4 -scanCount 500 -pipeSize 500 ``` ### 编译 在项目根目录执行: - 当前系统:`go build -o redis-memory-stat .` - Linux amd64:`GOOS=linux GOARCH=amd64 go build -o redis-memory-stat-linux .` - macOS arm64 (Apple Silicon):`GOOS=darwin GOARCH=arm64 go build -o redis-memory-stat-macos-arm64 .` - Windows amd64:`GOOS=windows GOARCH=amd64 go build -o redis-memory-stat.exe .` ### 常用参数(stat 模式) 命令行参数均有 `.env` 对应项,**命令行优先级更高**: | 参数 | 说明 | 默认值 | |---|---|---| | `-host` | Redis 地址 | `127.0.0.1` | | `-port` | Redis 端口 | `6379` | | `-password` | Redis 密码 | 空 | | `-timeout` | 连接/读写超时 | `5s` | | `-limit` | 前缀输出条数(TOP N) | `1000` | | `-scanCount` | `SCAN COUNT` 提示值 | `500` | | `-pattern` | `SCAN MATCH` 模式(可选),例如 `user:*` | 空 | | `-dbs` | DB 列表,如 `0,1,59`;空或 `all` 表示自动从 keyspace 获取(忽略 `keys=0`) | 空 | | `-prefixLen` | 前缀截取长度 | `4` | | `-debug` | 调试日志开关(`true/false`) | `false` | | `-output` | 输出文件路径;空字符串表示只写 stdout | `redis_memory_stat.out` | | `-workers` | 并发 worker 数量(最小 1,最大不超过 DB 数) | `4` | ### 常用参数(expire 模式) 同样支持 `.env`,常用选项如下: | 参数 | 说明 | 默认值 | |---|---|---| | `-host` | Redis 地址 | `127.0.0.1` | | `-port` | Redis 端口 | `6379` | | `-username` | Redis ACL 用户名(可选) | 空 | | `-password` | Redis 密码 | 空 | | `-timeout` | 连接/读写超时 | `5s` | | `-db` | 目标 DB,必填 | 无 | | `-prefix` | 要匹配的键前缀(会自动补 `*`),`-pattern` 为空时必填 | 空 | | `-pattern` | 自定义 `SCAN MATCH` 模式,可替代 `-prefix` | 空 | | `-ttl` | 过期时间,必填(如 `24h`) | 无 | | `-scanCount` | `SCAN COUNT` 提示值 | `500` | | `-pipeSize` | `EXPIRE` pipeline 批次大小 | `500` | | `-debug` | 调试日志开关 | `false` | ### 常用参数(ttlstat 模式) 同样支持 `.env`,常用选项如下: | 参数 | 说明 | 默认值 | |---|---|---| | `-host` | Redis 地址 | `127.0.0.1` | | `-port` | Redis 端口 | `6379` | | `-username` | Redis ACL 用户名(可选) | 空 | | `-password` | Redis 密码 | 空 | | `-timeout` | 连接/读写超时 | `5s` | | `-dbs` | DB 列表,空或 `all` 自动从 keyspace 获取 | 空 | | `-pattern` | `SCAN MATCH` 模式 | 空 | | `-ttlMin` | 认定为「长 TTL」的阈值 | `168h` | | `-includePersist` | 是否把永久 key(-1) 计入长 TTL 统计 | `true` | | `-ttlBuckets` | TTL 分桶边界(逗号分隔 duration) | `1h,6h,24h,168h,720h` | | `-prefixLen` | 前缀截取长度 | `4` | | `-limit` | 前缀 TOP N | `1000` | | `-withMemory` | 是否对长 TTL/永久 key 额外统计内存 | `false` | | `-scanCount` | `SCAN COUNT` 提示值 | `500` | | `-pipeSize` | `PTTL/MEMORY` pipeline 批次大小 | `500` | | `-workers` | 并发 worker 数量 | `4` | | `-debug` | 调试日志开关 | `false` | | `-output` | 输出文件;空表示仅 stdout | `redis_memory_stat.out` | ## 配置文件 支持在当前目录的 `.env` 中提供默认配置(示例如下;自行修改即可): ``` REDIS_HOST=127.0.0.1 REDIS_PORT=6379 REDIS_PASSWORD= REDIS_TIMEOUT=5s REDIS_LIMIT=1000 REDIS_SCAN_COUNT=500 REDIS_DBS= REDIS_PATTERN= REDIS_PREFIX_LEN=4 REDIS_DEBUG=false REDIS_OUTPUT=redis_memory_stat.out REDIS_WORKERS=4 # expire 模式 REDIS_EXPIRE_DB= REDIS_EXPIRE_PREFIX= REDIS_EXPIRE_PATTERN= REDIS_EXPIRE_TTL= # ttlstat 模式 REDIS_TTL_MIN=168h REDIS_TTL_INCLUDE_PERSIST=true REDIS_TTL_BUCKETS=1h,6h,24h,168h,720h REDIS_TTL_WITH_MEMORY=false ``` > 提示:如果同时设置了命令行参数与 `.env`,将以命令行参数为准。 ## 输出说明 - 终端与输出文件会同时写入结果(`-output ""` 可关闭文件输出)。 - 输出主要包含两部分: 1) **各 DB 内存占用** 2) **前缀 TOP N**(按占用降序) - 每条记录会显示人类可读的尺寸(B/KB/MB/GB/...)。 示例(节选): ```text [DB] 0 used=1.23GB [DB] 1 used=256.00MB [DB] max=0 used=1.23GB [PREFIX TOP] user: used=512.00MB keys=120034 db=0 order: used=320.00MB keys=80321 db=0 sess: used=64.00MB keys=900000 db=1 ``` > 当 pipeline 批次失败时,程序会自动降级为逐条 `MEMORY USAGE` 并在末尾打印 `[WARN]` 统计(失败批次/失败键数量)。 ## 注意事项 - 工具通过 `MEMORY USAGE` 获取键大小,需要 Redis 支持该命令(通常为 Redis 4.0+)。 - 扫描使用 `SCAN`,对线上实例相对友好,但仍会产生额外开销;建议在低峰期、合理设置 `-workers` 与 `-scanCount`。 - 并发 worker 会为每个并发 DB 建立独立连接,请确保 Redis 实例的连接上限足够。 - 生产环境请谨慎操作,优先在只读/从库或备库上执行(如果可用)。 - 统计结果可能是近似值:`SCAN` 为增量迭代,线上键可能变化;此外当出现网络/命令错误导致部分键跳过时,结果会略有低估(末尾会输出 `[WARN]` 供参考)。