2026-05-24 11:42:38 +08:00
|
|
|
|
---
|
|
|
|
|
|
tags: [Redis, 缓存, 运维, 性能调优]
|
|
|
|
|
|
create time: 2026-05-15 18:16
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
# Redis 运维与性能调优
|
|
|
|
|
|
|
|
|
|
|
|
## 概述
|
|
|
|
|
|
|
|
|
|
|
|
生产环境的 Redis 不是一装就跑——你需要持续监控、定期清理大 Key、合理配置连接池、分析慢查询。本节覆盖日常运维中最常见的问题和调优方法。
|
|
|
|
|
|
|
|
|
|
|
|
## 一、监控指标体系
|
|
|
|
|
|
|
|
|
|
|
|
### INFO 命令分级
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# ──── 核心指标 ────
|
|
|
|
|
|
INFO server # 版本、进程 ID、启动时间、运行天数
|
|
|
|
|
|
INFO clients # 连接数、阻塞客户端数、写入缓冲区
|
|
|
|
|
|
INFO memory # 内存使用量、峰值、碎片率 ← **必看**
|
|
|
|
|
|
INFO stats # 命中率、命令数、fork 耗时 ← **必看**
|
|
|
|
|
|
INFO persistence # RDB/AOF 状态 ← **必看**
|
|
|
|
|
|
INFO replication # 主从关系、延迟 ← **必看**
|
|
|
|
|
|
INFO commandstats # 各命令调用量和耗时排名
|
|
|
|
|
|
|
|
|
|
|
|
# ──── 辅助指标 ────
|
|
|
|
|
|
INFO keyspace # 每个 DB 的 key 数量和 TTL 统计
|
|
|
|
|
|
INFO cpu # CPU 消耗
|
|
|
|
|
|
INFO errorstats # 错误统计
|
|
|
|
|
|
INFO cluster # 集群拓扑(仅 Cluster)
|
|
|
|
|
|
INFO sentinel # Sentinel 信息(仅 Sentinel)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 关键指标解读
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# 从 INFO stats 提取的核心指标
|
|
|
|
|
|
keyspace_hits: 987654 # 缓存命中次数
|
|
|
|
|
|
keyspace_misses: 12346 # 缓存未命中次数
|
|
|
|
|
|
# → 命中率 = 987654 / (987654 + 12346) = 98.76%
|
|
|
|
|
|
|
|
|
|
|
|
used_memory_human: 1.23G # 已用内存
|
|
|
|
|
|
used_memory_rss_human: 1.35G # OS 感知内存
|
|
|
|
|
|
mem_fragmentation_ratio: 1.09 # RSS / used = 碎片率
|
|
|
|
|
|
|
|
|
|
|
|
# ──── 健康标准 ────
|
|
|
|
|
|
| 指标 | 正常范围 | 警告阈值 |
|
|
|
|
|
|
|------|---------|---------|
|
|
|
|
|
|
| 命中率 | > 90% | < 80% 需排查 |
|
|
|
|
|
|
| mem_fragmentation_ratio | 1.0 ~ 1.5 | > 1.5 内存浪费,< 1.0 swap 风险 |
|
|
|
|
|
|
| rejected_connections | 0 | > 0 说明 maxclients 不够 |
|
|
|
|
|
|
| total_commands_processed/s | 平稳增长 | 断崖式下跌说明异常 |
|
|
|
|
|
|
| connected_slaves | ≥ 预期 | 0 = 全部分离 |
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 副本延迟监控
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# 从节点查看主从状态
|
|
|
|
|
|
INFO replication
|
|
|
|
|
|
# role:slave / master_host / master_port / master_link_status(up/down)
|
|
|
|
|
|
# master_last_io_seconds_ago, master_sync_in_progress
|
|
|
|
|
|
|
|
|
|
|
|
# 关键指标:master_repl_offset - slave_repl_offset
|
|
|
|
|
|
# → 差值即为延迟字节数,超过 1MB 需关注
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
> [!WARNING] 副本延迟常见原因
|
|
|
|
|
|
> - **单线程写放大**:主库高并发写入时,从库网络 IO 成为瓶颈
|
|
|
|
|
|
> - **大 Key 持久化**:BGSAVE/BGREWRITEAOF 期间从库全量同步会短暂中断服务
|
|
|
|
|
|
> - **解决方案**:配置多个从库分担读取流量 + 使用 `replica-read-only yes`(Redis 5.0+)禁止从库写入
|
|
|
|
|
|
|
|
|
|
|
|
### 实时监控脚本
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
#!/bin/bash
|
|
|
|
|
|
HOST=${1:-127.0.0.1}
|
|
|
|
|
|
PORT=${2:-6379}
|
|
|
|
|
|
|
|
|
|
|
|
echo "=== Memory ==="
|
|
|
|
|
|
redis-cli -h $HOST -p $PORT INFO memory \
|
|
|
|
|
|
| grep -E "used_memory_human|maxmemory_human|mem_fragmentation_ratio"
|
|
|
|
|
|
|
|
|
|
|
|
echo "=== Stats ==="
|
|
|
|
|
|
redis-cli -h $HOST -p $PORT INFO stats \
|
|
|
|
|
|
| grep -E "keyspace_hits|keyspace_misses|instantaneous_ops_per_sec"
|
|
|
|
|
|
|
|
|
|
|
|
echo "=== Clients ==="
|
|
|
|
|
|
redis-cli -h $HOST -p $PORT INFO clients \
|
|
|
|
|
|
| grep -E "connected_clients|blocked_clients"
|
|
|
|
|
|
|
|
|
|
|
|
echo "=== Persistence ==="
|
|
|
|
|
|
redis-cli -h $HOST -p $PORT INFO persistence \
|
|
|
|
|
|
| grep -E "aof_enabled|rdb_last_bgsave_status"
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## 二、慢查询日志
|
|
|
|
|
|
|
|
|
|
|
|
### 配置与分析
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# 默认配置
|
|
|
|
|
|
CONFIG GET slowlog-log-slower-than # 默认 10000 μs (10ms)
|
|
|
|
|
|
CONFIG GET slowlog-max-len # 默认 128 条
|
|
|
|
|
|
|
|
|
|
|
|
# 调整为 5ms 阈值
|
|
|
|
|
|
CONFIG SET slowlog-log-slower-than 5000
|
|
|
|
|
|
|
|
|
|
|
|
# 扩大存储容量
|
|
|
|
|
|
CONFIG SET slowlog-max-len 2048
|
|
|
|
|
|
|
|
|
|
|
|
# 查看慢查询
|
|
|
|
|
|
SLOWLOG GET 10
|
|
|
|
|
|
|
|
|
|
|
|
# 重置
|
|
|
|
|
|
SLOWLOG RESET
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 典型慢查询根因
|
|
|
|
|
|
|
|
|
|
|
|
| 慢查询 | 根因 | 修复方案 |
|
|
|
|
|
|
|--------|------|---------|
|
|
|
|
|
|
| `KEYS *` | 全库扫描 O(N) | 改用 SCAN |
|
|
|
|
|
|
| `HGETALL large_hash` | 大 Hash 全量返回 | HSCAN 分页 |
|
|
|
|
|
|
| `SMEMBERS huge_set` | 大集合全量遍历 | SSCAN 分页 |
|
|
|
|
|
|
| `LRANGE 0 -1` (百万条 List) | 全列表拉取 | LRANGE 指定范围 |
|
|
|
|
|
|
| 无索引的 DB 查询(在 Lua 中) | DB 层问题 | 加 DB 索引 |
|
|
|
|
|
|
|
2026-05-25 23:50:33 +08:00
|
|
|
|
```bash
|
|
|
|
|
|
# SLOWLOG GET 输出字段说明
|
|
|
|
|
|
1) (integer) 14 # 慢查询 ID(递增)
|
|
|
|
|
|
2) (integer) 1716620400 # 发生时间(Unix 时间戳)
|
|
|
|
|
|
3) (integer) 13456 # 耗时(微秒)
|
|
|
|
|
|
4) 1) "KEYS" # 命令及参数
|
|
|
|
|
|
2) "*"
|
|
|
|
|
|
5) "127.0.0.1:53412" # 客户端地址
|
|
|
|
|
|
6) "" # 客户端名称
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-05-24 11:42:38 +08:00
|
|
|
|
```go
|
|
|
|
|
|
// go-redis 中的 SlowLog 接口
|
2026-05-25 23:50:33 +08:00
|
|
|
|
entries, err := rdb.SlowLogGet(ctx, 10).Result()
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
log.Fatal(err)
|
|
|
|
|
|
}
|
2026-05-24 11:42:38 +08:00
|
|
|
|
for _, e := range entries {
|
|
|
|
|
|
fmt.Printf("ID: %d, Time: %s, Cmd: %s, Duration: %v\n",
|
2026-05-25 23:50:33 +08:00
|
|
|
|
e.ID, e.Time.Format(time.RFC3339), e.Args, e.Duration)
|
2026-05-24 11:42:38 +08:00
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-05-25 23:50:33 +08:00
|
|
|
|
### 延迟诊断工具
|
|
|
|
|
|
|
|
|
|
|
|
Redis 提供了内建的延迟诊断能力,定位"客户端感知慢"但服务端 CPU 并不繁忙的场景:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# ──── 实时延迟采样(排查首选) ────
|
|
|
|
|
|
redis-cli --latency # 持续输出 min/avg/max(ms)
|
|
|
|
|
|
redis-cli --latency-history -i 5 # 每 5 秒输出一次统计
|
|
|
|
|
|
|
|
|
|
|
|
# ──── 延迟分布直方图 ────
|
|
|
|
|
|
redis-cli --latency-dist # 交互式彩色直方图,快速定位延迟区间
|
|
|
|
|
|
|
|
|
|
|
|
# ──── 事件驱动延迟监控(需服务端配置) ────
|
|
|
|
|
|
# 在 redis.conf 中配置延迟阈值(微秒)
|
|
|
|
|
|
# latency-monitor-threshold 10
|
|
|
|
|
|
|
|
|
|
|
|
# 之后查看:
|
|
|
|
|
|
LATENCY LATEST # 最近的延迟事件
|
|
|
|
|
|
LATENCY HISTORY command # 某命令的延迟历史
|
|
|
|
|
|
LATENCY RESET # 重置统计数据
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
> [!TIP] 延迟排查三板斧
|
|
|
|
|
|
> 1. `redis-cli --latency` — 先看基线是否正常(正常 P99 < 1ms)
|
|
|
|
|
|
> 2. `LATENCY LATEST` — 看是否有异常事件(fork、大 Key 删除、AOF fsync)
|
|
|
|
|
|
> 3. `INFO commandstats` — 按命令耗时排序,定位慢命令
|
|
|
|
|
|
|
2026-05-24 11:42:38 +08:00
|
|
|
|
## 三、大 Key 治理
|
|
|
|
|
|
|
|
|
|
|
|
### 什么是大 Key?
|
|
|
|
|
|
|
|
|
|
|
|
通常指超过 **5KB** 的单个 Key(字符串除外,字符串可达数百 MB)。
|
|
|
|
|
|
|
|
|
|
|
|
> [!WARNING] 大 Key 的危害
|
|
|
|
|
|
> - **网络阻塞**:SET/GET 一个 1MB 的值占满一条 TCP 连接
|
|
|
|
|
|
> - **过期事件堆积**:大量大 key 同时过期时一次性触发删除,阻塞主线程
|
|
|
|
|
|
> - **分片迁移卡顿**:Cluster 迁移 slot 时需要复制整个值
|
|
|
|
|
|
> - **RDB/AOF 膨胀**:持久化文件急剧增大
|
|
|
|
|
|
|
|
|
|
|
|
### 检测工具
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# 方式 1: redis-cli --bigkeys(采样扫描)
|
|
|
|
|
|
redis-cli --bigkeys -n 1000
|
|
|
|
|
|
|
|
|
|
|
|
# 输出示例:
|
|
|
|
|
|
# --- SUMMARY ---
|
|
|
|
|
|
# Size Count Type Keys
|
|
|
|
|
|
# 1.23MB 1 string user:avatar:big_image
|
|
|
|
|
|
# 456KB 3 hash order:items:*
|
|
|
|
|
|
# ...
|
|
|
|
|
|
|
|
|
|
|
|
# 方式 2: redis-rdb-tools (RDB 离线分析)
|
|
|
|
|
|
rdb -c memory dump.rdb | sort -k2 -rn | head -20
|
|
|
|
|
|
|
|
|
|
|
|
# 方式 3: RedisInsight / AnotherRedisDesktopManager GUI
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 拆分策略
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
原始大 Key:
|
|
|
|
|
|
order:12345 -> hash{ item1, item2, ..., item5000 } ← 5000 个订单项
|
|
|
|
|
|
|
|
|
|
|
|
拆分后:
|
|
|
|
|
|
order:12345:id -> order_main_12345 ← 订单元数据
|
|
|
|
|
|
order:12345:items:page:1 -> list[ item1~item100 ] ← 按页拆分
|
|
|
|
|
|
order:12345:items:page:2 -> list[ item101~item200 ]
|
|
|
|
|
|
|
|
|
|
|
|
读取时拼接 pages 即可
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### DEL 大 Key 的风险
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# ⛔ 直接 DEL 大 key 会阻塞主线程!
|
|
|
|
|
|
DEL big_key
|
|
|
|
|
|
|
|
|
|
|
|
# ✅ 渐进式删除(SCAN + UNLINK)
|
|
|
|
|
|
UNLINK big_key # 异步删除(Redis 4.0+),立即返回
|
|
|
|
|
|
# 后台线程回收内存
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
> [!TIP] UNLINK vs DEL
|
|
|
|
|
|
> - `DEL`:同步删除,大 key 可能阻塞数十毫秒甚至秒级
|
|
|
|
|
|
> - `UNLINK`:异步删除,立即返回,后台回收(类似 GC)
|
|
|
|
|
|
> - 生产环境优先使用 `UNLINK`
|
|
|
|
|
|
|
|
|
|
|
|
## 四、连接池调优
|
|
|
|
|
|
|
|
|
|
|
|
### Go go-redis 连接池配置
|
|
|
|
|
|
|
|
|
|
|
|
```go
|
|
|
|
|
|
rdb := redis.NewClient(&redis.Options{
|
2026-05-25 23:50:33 +08:00
|
|
|
|
Addr: "localhost:6379",
|
|
|
|
|
|
Password: "",
|
|
|
|
|
|
DB: 0,
|
|
|
|
|
|
|
|
|
|
|
|
// ──── 连接池参数(go-redis v9) ────
|
|
|
|
|
|
PoolSize: 100, // 连接池最大连接数(= 旧 MaxActive)
|
|
|
|
|
|
MinIdleConns: 10, // 最小空闲连接数,启动时预热
|
|
|
|
|
|
ConnMaxIdleTime: 5 * time.Minute, // 空闲连接存活上限,超时关闭
|
|
|
|
|
|
ConnMaxLifetime: 0, // 连接最大存活时长,0 = 不限制
|
|
|
|
|
|
|
2026-05-24 11:42:38 +08:00
|
|
|
|
// ──── 超时参数 ────
|
2026-05-25 23:50:33 +08:00
|
|
|
|
DialTimeout: 5 * time.Second, // 建立 TCP 连接超时
|
|
|
|
|
|
ReadTimeout: 3 * time.Second, // 读超时
|
|
|
|
|
|
WriteTimeout: 3 * time.Second, // 写超时
|
|
|
|
|
|
PoolTimeout: 1 * time.Second, // 获取连接的等待超时
|
|
|
|
|
|
|
|
|
|
|
|
// ──── 重试策略 ────
|
|
|
|
|
|
MaxRetries: 3,
|
|
|
|
|
|
MinRetryBackoff: 200 * time.Millisecond,
|
|
|
|
|
|
MaxRetryBackoff: 1 * time.Second,
|
2026-05-24 11:42:38 +08:00
|
|
|
|
})
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-05-25 23:50:33 +08:00
|
|
|
|
> [!NOTE] go-redis v8 → v9 参数变化
|
|
|
|
|
|
> - `MaxIdle` / `MaxActive` → 合并为 `PoolSize`,`MinIdleConns` 控制预热
|
|
|
|
|
|
> - `IdleTimeout` → `ConnMaxIdleTime`
|
|
|
|
|
|
> - `PingPeriod` 无对应字段,go-redis 内部通过健康检查自动保活
|
|
|
|
|
|
> - `RetryDelay` → `MinRetryBackoff` + `MaxRetryBackoff`(指数退避)
|
|
|
|
|
|
|
2026-05-24 11:42:38 +08:00
|
|
|
|
### 连接池选型决策树
|
|
|
|
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
|
|
graph TD
|
2026-05-25 23:50:33 +08:00
|
|
|
|
A["预估 QPS"] -->|"< 500"| S["PoolSize: 20, MinIdleConns: 5"]
|
|
|
|
|
|
A -->|"500 ~ 5000"| M["PoolSize: 50, MinIdleConns: 20"]
|
|
|
|
|
|
A -->|"> 5000"| L["PoolSize: 100~200, MinIdleConns: 30~50"]
|
|
|
|
|
|
|
2026-05-24 11:42:38 +08:00
|
|
|
|
B{"有无 Pipeline?"}
|
2026-05-25 23:50:33 +08:00
|
|
|
|
B -->|"是"| C["增加 30% 连接数"]
|
2026-05-24 11:42:38 +08:00
|
|
|
|
B -->|"否"| D["保持上述配置"]
|
2026-05-25 23:50:33 +08:00
|
|
|
|
|
2026-05-24 11:42:38 +08:00
|
|
|
|
style L fill:#fdd,stroke:#900
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-05-25 23:50:33 +08:00
|
|
|
|
> [!TIP] PoolSize 计算公式
|
2026-05-24 11:42:38 +08:00
|
|
|
|
> ```
|
2026-05-25 23:50:33 +08:00
|
|
|
|
> PoolSize = N × (1 + CPU等待时间/CPU计算时间)
|
2026-05-24 11:42:38 +08:00
|
|
|
|
> ```
|
|
|
|
|
|
> 其中 N 为 Goroutine 数量。对于大多数 Web 应用,**50~100** 已经足够——如果频繁出现 PoolTimeout,优先考虑排查慢查询或大 Key 问题。
|
|
|
|
|
|
|
|
|
|
|
|
> [!WARNING] 连接池常见问题
|
2026-05-25 23:50:33 +08:00
|
|
|
|
> - **PoolSize 太小**:`context deadline exceeded`(PoolTimeout)频繁出现
|
|
|
|
|
|
> - **PoolSize 太大**:创建过多 TCP 连接,文件描述符耗尽
|
2026-05-24 11:42:38 +08:00
|
|
|
|
> - **ReadTimeout 太短**:大数据量操作(如 HGETALL 大 hash)被误杀
|
|
|
|
|
|
> - **不设 DialTimeout**:Redis 宕机时请求永远挂起
|
|
|
|
|
|
|
|
|
|
|
|
## 五、内存管理与淘汰策略
|
|
|
|
|
|
|
|
|
|
|
|
### maxmemory 设置
|
|
|
|
|
|
|
|
|
|
|
|
```conf
|
|
|
|
|
|
maxmemory 2gb
|
|
|
|
|
|
maxmemory-policy allkeys-lru
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 淘汰策略详解
|
|
|
|
|
|
|
|
|
|
|
|
> [!QUESTION] 没有永不超限的策略?
|
|
|
|
|
|
> 如果你不想数据丢失,应该设 `noeviction`——但这意味着写操作会失败。更好的做法是:**合理设置 maxmemory + 选择合适的淘汰策略**,而不是等到满了再处理。
|
|
|
|
|
|
|
|
|
|
|
|
| 策略 | 作用范围 | 淘汰算法 | 适用场景 |
|
|
|
|
|
|
|------|---------|---------|---------|
|
|
|
|
|
|
| **allkeys-lru** | 所有 key | LRU(近似) | 通用缓存 ✅ 最常用 |
|
2026-05-25 23:50:33 +08:00
|
|
|
|
| allkeys-lfu | 所有 key | LFU(频次统计) | Redis 4.0+,热点数据语义更强的场景 |
|
2026-05-24 11:42:38 +08:00
|
|
|
|
| volatile-lru | 仅设 TTL 的 key | LRU(近似) | 混合存储:永不过期的配置 + 可淘汰的缓存 |
|
2026-05-25 23:50:33 +08:00
|
|
|
|
| volatile-lfu | 仅设 TTL 的 key | LFU(频次统计) | 混合存储 + 频次敏感淘汰 |
|
2026-05-24 11:42:38 +08:00
|
|
|
|
| volatile-ttl | 仅设 TTL 的 key | TTL 最短优先 | 让数据自然死亡的场景 |
|
|
|
|
|
|
| noeviction | — | — | 数据不可丢失,超限返回错误(如配置中心) |
|
|
|
|
|
|
|
|
|
|
|
|
> [!NOTE] LRU vs LFU
|
|
|
|
|
|
> - **LRU**:基于时间,维护一个候选池近似实现,内存开销小
|
|
|
|
|
|
> - **LFU**:基于访问频率,每 key 额外消耗 2 bit 计数器,更精准但略贵
|
|
|
|
|
|
> - 实际选型:不确定时先用 `allkeys-lru`;如果存在明显"二八定律"(20% 数据占 80% 访问),考虑 `allkeys-lfu`
|
|
|
|
|
|
|
|
|
|
|
|
### 内存碎片治理
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# 查看碎片率
|
|
|
|
|
|
memfragmentationratio = used_memory_rss / used_memory
|
|
|
|
|
|
# 正常范围: 1.0 ~ 1.5
|
|
|
|
|
|
|
|
|
|
|
|
# 配置激活碎片整理(Redis 4.0+,仅在 Linux 上有效)
|
|
|
|
|
|
activedefrag yes
|
|
|
|
|
|
active-defrag-threshold-lower 10 # 碎片率 > 10% 时启动
|
|
|
|
|
|
active-defrag-threshold-upper 50 # 碎片率 > 50% 时全力清理
|
|
|
|
|
|
active-defrag-cycle-min 5 # 每次最多占 CPU 5%
|
|
|
|
|
|
active-defrag-cycle-max 25 # 最高占 CPU 25%
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
> [!QUESTION] 为什么 fragmentation ratio < 1.0?
|
|
|
|
|
|
> 表示 RSS < used_memory——这意味着发生了 **swap**。操作系统把 Redis 的物理内存换出到磁盘,灾难性后果——延迟飙升到秒级。
|
|
|
|
|
|
>
|
|
|
|
|
|
> ```bash
|
|
|
|
|
|
> # 检查是否开启了 swap
|
|
|
|
|
|
> free -m
|
|
|
|
|
|
> # 如果 swapped > 0 → 立即处理!
|
|
|
|
|
|
> ```
|
|
|
|
|
|
|
|
|
|
|
|
## 六、备份与灾难恢复
|
|
|
|
|
|
|
|
|
|
|
|
### 定时备份方案
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
#!/bin/bash
|
|
|
|
|
|
# backup.sh — 每天凌晨 2 点执行
|
|
|
|
|
|
BACKUP_DIR="/backup/redis"
|
|
|
|
|
|
DATE=$(date +%Y%m%d_%H%M%S)
|
|
|
|
|
|
|
|
|
|
|
|
# 触发 BGSAVE
|
|
|
|
|
|
redis-cli BGSAVE
|
|
|
|
|
|
|
|
|
|
|
|
# 等待完成(轮询 LASTSAVE)
|
|
|
|
|
|
sleep 5
|
|
|
|
|
|
cp /var/lib/redis/dump.rdb "$BACKUP_DIR/dump_$DATE.rdb"
|
|
|
|
|
|
gzip "$BACKUP_DIR/dump_$DATE.rdb"
|
|
|
|
|
|
|
|
|
|
|
|
# 保留最近 30 天的备份
|
|
|
|
|
|
find $BACKUP_DIR -mtime +30 -delete
|
|
|
|
|
|
|
|
|
|
|
|
# 上传到对象存储
|
|
|
|
|
|
aws s3 cp "$BACKUP_DIR/dump_$DATE.rdb.gz" "s3://your-bucket/redis-backup/"
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Crontab:
|
|
|
|
|
|
```
|
|
|
|
|
|
0 2 * * * /path/to/backup.sh >> /var/log/redis-backup.log 2>&1
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 灾难恢复流程
|
|
|
|
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
|
|
flowchart TD
|
2026-05-25 23:50:33 +08:00
|
|
|
|
A["数据异常或丢失"] --> B{"可用最近的备份?"}
|
2026-05-24 11:42:38 +08:00
|
|
|
|
B -->|"是"| C["停止写入,防止覆盖"]
|
|
|
|
|
|
C --> D["恢复 RDB/AOF 备份"]
|
|
|
|
|
|
D --> E["检查数据完整性"]
|
|
|
|
|
|
E --> F{"数据是否完整?"}
|
|
|
|
|
|
F -->|"是"| G["恢复写入,观察指标"]
|
|
|
|
|
|
F -->|"否"| H{"有增量日志?"}
|
|
|
|
|
|
H -->|"AOF"| I["附加修复 AOF 文件<br/>redis-check-aof --fix"]
|
|
|
|
|
|
H -->|"无"| J["从主库全量同步"]
|
|
|
|
|
|
I --> E
|
|
|
|
|
|
J --> E
|
|
|
|
|
|
B -->|"否"| K["从主库重新同步"]
|
|
|
|
|
|
K --> E
|
|
|
|
|
|
|
|
|
|
|
|
style A fill:#fdd,stroke:#900
|
|
|
|
|
|
style G fill:#dfd,stroke:#090
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 云厂商迁移工具
|
|
|
|
|
|
|
|
|
|
|
|
| 来源 | 目标 | 工具 |
|
|
|
|
|
|
|------|------|------|
|
|
|
|
|
|
| 自建 Redis | AWS ElastiCache | `elasticache-migration-tool` |
|
|
|
|
|
|
| 自建 Redis | Aliyun ApsaraDB | `redis-shake` |
|
|
|
|
|
|
| Redis Cluster | 云 Redis | 云控制台导入功能 |
|
|
|
|
|
|
| Redis to Redis | 任意 | `redis-shake` |
|
|
|
|
|
|
|
|
|
|
|
|
## 七、安全加固清单
|
|
|
|
|
|
|
|
|
|
|
|
> [!CHECKLIST] 生产环境安全核对
|
|
|
|
|
|
|
|
|
|
|
|
- [ ] `requirepass` 已设置强密码
|
|
|
|
|
|
- [ ] `rename-command FLUSHALL ""` — 重命名危险命令(或设为空禁用)
|
|
|
|
|
|
- [ ] `rename-command DEBUG ""` — 禁用 debug 命令
|
|
|
|
|
|
- [ ] 绑定内网 IP 而非 `0.0.0.0`
|
|
|
|
|
|
- [ ] TLS/SSL 加密传输(Redis 6.0+ 支持)
|
|
|
|
|
|
- [ ] 定期更新版本号,修复已知 CVE
|
|
|
|
|
|
- [ ] ACL 用户权限控制(Redis 6.0+ 支持多用户角色)
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# ACL 示例(Redis 6.0+)
|
2026-05-25 23:50:33 +08:00
|
|
|
|
ACL SETUSER readonly on >readOnlyPass123 ~cached:* &* +get +mget +scan +ping
|
|
|
|
|
|
ACL SETUSER writer on >writePass123 ~* &* +set +add +incr +del +ping
|
2026-05-24 11:42:38 +08:00
|
|
|
|
ACL LIST # 查看所有用户
|
|
|
|
|
|
ACL WHOAMI # 当前用户
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## 关联笔记
|
|
|
|
|
|
|
|
|
|
|
|
- [[hhs/Redis/04-RDB持久化]] — RDB 快照与备份
|
|
|
|
|
|
- [[hhs/Redis/05-AOF持久化]] — AOF 文件大小管理
|
|
|
|
|
|
- [[hhs/Redis/07-集群方案]] — 集群运维注意事项
|
|
|
|
|
|
- [[hhs/Redis/README]] — 知识索引总览
|