前言
Redis 是 PHP 项目中使用最广泛的 Nosql 缓存数据库,但很多团队在生产环境中部署 Redis 时存在诸多隐患:内存配置不当导致 OOM、持久化配置错误导致数据丢失、集群部署不合理导致性能下降、安全配置缺失导致被攻击。
本文从实际生产经验出发,详细讲解 Redis 在生产环境中的部署避坑指南,包括内存配置、持久化方案、集群架构、安全加固、监控告警等方面。
1 内存配置
1.1 最大内存配置
# 查看当前最大内存配置 redis-cli CONFIG GET maxmemory # 设置最大内存(字节) redis-cli CONFIG SET maxmemory 10737418240 # 10GB # 临时设置(重启失效) redis-server --maxmemory 10gb # 永久设置(配置文件) # redis.conf maxmemory 10gb
内存单位说明:
1k => 1000 bytes 1kb => 1024 bytes 1m => 1000000 bytes 1mb => 1024*1024 bytes 1g => 1000000000 bytes 1gb => 1024*1024*1024 bytes
1.2 内存淘汰策略
当 Redis 内存达到 maxmemory 时,会根据配置的淘汰策略删除键值。
# 查看当前淘汰策略 redis-cli CONFIG GET maxmemory-policy # 设置淘汰策略 redis-cli CONFIG SET maxmemory-policy allkeys-lru
可选策略:
| 策略 | 说明 | 适用场景 |
|---|---|---|
| noeviction | 不淘汰,返回错误 | 数据不允许丢失 |
| allkeys-lru | 所有键使用 LRU 淘汰 | 通用缓存场景 |
| allkeys-lfu | 所有键使用 LFU 淘汰 | 热点数据场景 |
| allkeys-random | 所有键随机淘汰 | 随机淘汰场景 |
| volatile-lru | 已设置 TTL 的键使用 LRU | 混合使用 |
| volatile-lfu | 已设置 TTL 的键使用 LFU | 混合使用 |
| volatile-random | 已设置 TTL 的键随机淘汰 | 混合使用 |
| volatile-ttl | 已设置 TTL 的键按 TTL 淘汰 | 保留热点数据 |
LRU vs LFU:
**LRU (Least Recently Used)**:最近最少使用,淘汰最久未访问的键
**LFU (Least Frequently Used)**:最不经常使用,淘汰访问频率最低的键
# volatile-lru 适合的场景: # 既有缓存数据又有持久数据的混合应用 # 设置了 TTL 的数据希望优先淘汰 # allkeys-lru 适合的场景: # 所有数据都是缓存,希望优先保留热点数据
1.3 内存碎片
Redis 使用 glibc 的内存分配器,会产生内存碎片。
# 查看内存碎片率 redis-cli INFO memory | grep mem_fragmentation_ratio # 手动整理碎片(Redis 4.0+) redis-cli MEMORY PURGE # 重启 Redis 也会清理碎片
内存碎片率说明:
1.0 ~ 1.5:正常范围
1.5:碎片较多,可能需要整理
< 1.0:使用了 swap 或物理内存不足
减少碎片的建议:
使用 Jemalloc 内存分配器(Redis 默认)
合理设置 maxmemory,避免频繁淘汰
使用 Redis 4.0+ 的主动碎片整理
# 启用主动碎片整理(Redis 4.0+) redis-cli CONFIG SET activedefrag yes # 查看碎片整理统计 redis-cli INFO memory | grep mem_fragmentation_ratio
1.4 内存监控
# 查看内存使用详情
redis-cli INFO memory
# 输出示例
# used_memory: 1073741824 # Redis 实际使用的内存
# used_memory_human: 1.00G
# used_memory_rss: 1258291200 # 操作系统实际分配的物理内存
# used_memory_rss_human: 1.17G
# used_memory_peak: 2147483648 # 内存使用峰值
# used_memory_peak_human: 2.00G
# mem_fragmentation_ratio: 1.17 # 内存碎片率
# mem_allocator: jemalloc-5.2.1 # 内存分配器
# 监控脚本
#!/bin/bash
USED=$(redis-cli INFO memory | grep used_memory | awk -F: '{print $2}')
PEAK=$(redis-cli INFO memory | grep used_memory_peak | awk -F: '{print $2}')
MAX=$(redis-cli CONFIG GET maxmemory | tail -1)
echo "Used: $((USED/1024/1024)) MB"
echo "Peak: $((PEAK/1024/1024)) MB"
echo "Max: $((MAX/1024/1024)) MB"
echo "Usage: $(echo "scale=2; $USED*100/$MAX" | bc)%"
2 持久化配置
2.1 RDB 持久化
RDB 是 Redis 的定时快照备份,生成紧凑的二进制文件。
# 手动触发 RDB redis-cli BGSAVE # 或 redis-cli SAVE # 同步保存,会阻塞 Redis # 查看最近一次 RDB 保存时间 redis-cli DEBUG SLEEP 1 && redis-cli LASTSAVE # 查看子进程状态 redis-cli INFO persistence # rdb_changes_since_last_save: 0 # rdb_last_save_time: 1609459200 # rdb_last_bgsave_status: ok # rdb_last_bgsave_time_sec: 1
RDB 配置:
# redis.conf # 多久触发一次 RDB # 900秒内至少1个key变化 save 900 1 # 300秒内至少10个key变化 save 300 10 # 60秒内至少10000个key变化 save 60 10000 # 关闭 RDB(如果只用作缓存) save "" # RDB 文件名 dbfilename dump.rdb # RDB 文件存放目录 dir /var/lib/redis # bgsave 失败时禁止写入 stop-writes-on-bgsave-error yes # 是否压缩 RDB 文件 rdbcompression yes # 是否校验 RDB 文件 rdbchecksum yes
RDB 优点:
文件紧凑,适合备份和灾难恢复
恢复大数据集时比 AOF 快
RDB 缺点:
可能丢失最后一次快照后的数据
fork() 操作在数据量大时可能导致 Redis 短暂卡顿
2.2 AOF 持久化
AOF 是 Redis 的增量日志,记录每个写操作。
# 查看 AOF 状态 redis-cli INFO persistence # aof_enabled: 1 # aof_current_size: 1048576 # aof_base_size: 1048576 # aof_pending_rewrite: 0 # aof_buffer_length: 0 # aof_rewrite_buffer_length: 0 # aof_pending_bio_fsync: 0 # aof_last_bgrewrite_status: ok # aof_last_write_status: ok
AOF 配置:
# redis.conf # 开启 AOF appendonly yes # AOF 文件名 appendfilename "appendonly.aof" # AOF 写入策略 appendfsync everysec # 每秒同步,最多丢失1秒数据(推荐) # appendfsync always # 每次写入同步,最安全但最慢 # appendfsync no # 由操作系统决定何时同步,最快但最不安全 # AOF 重写配置 auto-aof-rewrite-percentage 100 # 文件比上次重写大100%时触发 auto-aof-rewrite-min-size 64mb # 文件至少达到64MB才触发 # AOF 重写失败时停止写入 aof-load-truncated yes # 启用 RDB-AOF 混合持久化(Redis 7.0+) aof-use-rdb-preamble yes
AOF 优点:
数据安全性更高,最多丢失一个写入周期
AOF 文件是追加写入,不会产生随机写
AOF 缺点:
文件比 RDB 大
恢复数据时比 RDB 慢
2.3 混合持久化(Redis 4.0+)
# 启用混合持久化 aof-use-rdb-preamble yes
混合持久化会在 AOF 重写时使用 RDB 格式存储数据,然后在后面追加增量 AOF 指令。这样既保证了快速恢复,又保证了数据不丢失。
恢复优先级:
如果存在 AOF 文件,优先使用 AOF 恢复
如果 AOF 被关闭或不完整,使用 RDB 恢复
2.4 生产环境持久化建议
# 生产环境推荐配置 # 内存配置 maxmemory 8gb maxmemory-policy allkeys-lru # RDB 配置 save 900 1 save 300 10 save 60 10000 stop-writes-on-bgsave-error yes rdbcompression yes rdbchecksum yes # AOF 配置 appendonly yes appendfsync everysec auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb aof-load-truncated yes aof-use-rdb-preamble yes
3 RDB 与 AOF 备份策略
3.1 备份脚本
#!/bin/bash # filename: redis_backup.sh # Redis 备份脚本 BACKUP_DIR="/data/redis_backup" REDIS_HOST="127.0.0.1" REDIS_PORT="6379" REDIS_PASSWORD="your_redis_password" DATE=$(date +%Y%m%d_%H%M%S) # 创建备份目录 mkdir -p $BACKUP_DIR # 获取 Redis 配置 REDIS_DATA_DIR=$(redis-cli -h $REDIS_HOST -p $REDIS_PORT -a $REDIS_PASSWORD CONFIG GET dir | tail -1) REDIS_DBFILE=$(redis-cli -h $REDIS_HOST -p $REDIS_PORT -a $REDIS_PASSWORD CONFIG GET dbfilename | tail -1) REDIS_AOFFILE=$(redis-cli -h $REDIS_HOST -p $REDIS_PORT -a $REDIS_PASSWORD CONFIG GET appendfilename | tail -1) # 执行 BGSAVE echo "Triggering BGSAVE..." redis-cli -h $REDIS_HOST -p $REDIS_PORT -a $REDIS_PASSWORD BGSAVE # 等待 RDB 保存完成 while [ $(redis-cli -h $REDIS_HOST -p $REDIS_PORT -a $REDIS_PASSWORD LASTSAVE) -eq $(redis-cli -h $REDIS_HOST -p $REDIS_PORT -a $REDIS_PASSWORD LASTSAVE) ]; do sleep 1 done # 复制 RDB 文件 if [ -f "$REDIS_DATA_DIR/$REDIS_DBFILE" ]; then cp $REDIS_DATA_DIR/$REDIS_DBFILE $BACKUP_DIR/dump_$DATE.rdb echo "RDB backup: $REDIS_DBFILE" fi # 复制 AOF 文件 if [ -f "$REDIS_DATA_DIR/$REDIS_AOFFILE" ]; then cp $REDIS_DATA_DIR/$REDIS_AOFFILE $BACKUP_DIR/appendonly_$DATE.aof echo "AOF backup: $REDIS_AOFFILE" fi # 压缩备份文件 cd $BACKUP_DIR tar czf redis_backup_$DATE.tar.gz *.rdb *.aof 2>/dev/null rm -f *.rdb *.aof # 删除 7 天前的备份 find $BACKUP_DIR -name "redis_backup_*.tar.gz" -mtime +7 -delete echo "Backup completed: redis_backup_$DATE.tar.gz" ls -lh $BACKUP_DIR
3.2 恢复脚本
#!/bin/bash # filename: redis_restore.sh # Redis 数据恢复脚本 BACKUP_FILE=$1 REDIS_HOST="127.0.0.1" REDIS_PORT="6379" REDIS_PASSWORD="your_redis_password" if [ -z "$BACKUP_FILE" ]; then echo "Usage: $0" exit 1 fi if [ ! -f "$BACKUP_FILE" ]; then echo "Error: Backup file not found" exit 1 fi # 停止 Redis echo "Stopping Redis..." systemctl stop redis # 备份当前数据 REDIS_DATA_DIR=$(redis-cli -h $REDIS_HOST -p $REDIS_PORT -a $REDIS_PASSWORD CONFIG GET dir | tail -1) if [ -f "$REDIS_DATA_DIR/dump.rdb" ]; then mv $REDIS_DATA_DIR/dump.rdb $REDIS_DATA_DIR/dump.rdb.bak fi if [ -f "$REDIS_DATA_DIR/appendonly.aof" ]; then mv $REDIS_DATA_DIR/appendonly.aof $REDIS_DATA_DIR/appendonly.aof.bak fi # 解压备份文件 cd $REDIS_DATA_DIR tar xzf $BACKUP_FILE # 启动 Redis echo "Starting Redis..." systemctl start redis # 验证数据 KEY_COUNT=$(redis-cli -h $REDIS_HOST -p $REDIS_PORT -a $REDIS_PASSWORD DBSIZE) echo "Restored keys: $KEY_COUNT" # 如果数据不对,恢复备份 if [ "$KEY_COUNT" -eq 0 ]; then echo "Warning: No data restored, restoring from .bak files" mv $REDIS_DATA_DIR/dump.rdb.bak $REDIS_DATA_DIR/dump.rdb systemctl restart redis fi
4 安全加固
4.1 密码认证
# 设置密码(临时) redis-cli CONFIG SET requirepass "your_strong_password" # 设置密码(永久,redis.conf) requirepass your_strong_password # 使用密码连接 redis-cli -a your_strong_password redis-cli -h 127.0.0.1 -p 6379 -a your_strong_password # 使用密码认证 redis-cli AUTH your_strong_password # 设置多个密码(ACL,Redis 6.0+) ACL SETUSER alice on >password ~cached:* +get +set +del +exists
4.2 绑定地址
# 只监听本地 bind 127.0.0.1 # 监听特定 IP bind 192.168.1.100 # 监听多个 IP bind 127.0.0.1 192.168.1.100 # 监听所有接口(危险!) bind 0.0.0.0 # 禁止生产环境使用
4.3 禁用危险命令
# redis.conf # 禁用危险命令 rename-command FLUSHDB "" rename-command FLUSHALL "" rename-command DEBUG "" rename-command KEYS "" # 或者重命名为不易猜测的名字 rename-command FLUSHDB FLUSHDB_RENAMED rename-command KEYS KEYSCMD
4.4 限制连接数
# 最大连接数 maxclients 10000 # TCP backlog tcp-backlog 511 # 超时设置(客户端空闲多久断开) timeout 300 # 保活设置 tcp-keepalive 300
4.5 防火墙设置
# iptables 限制访问 iptables -A INPUT -p tcp -s 192.168.1.0/24 --dport 6379 -j ACCEPT iptables -A INPUT -p tcp --dport 6379 -j DROP # 如果使用云服务器,使用安全组限制 # 只允许应用服务器 IP 访问 Redis
4.6 安全检查清单
#!/bin/bash
# filename: redis_security_check.sh
# Redis 安全检查脚本
echo "=== Redis 安全检查 ==="
echo ""
# 1. 检查是否设置了密码
REQUIREPASS=$(redis-cli CONFIG GET requirepass | tail -1)
if [ "$REQUIREPASS" = "" ] || [ "$REQUIREPASS" = "" ]; then
echo "[WARN] Redis 未设置密码!"
else
echo "[OK] Redis 已设置密码"
fi
# 2. 检查绑定地址
BIND=$(redis-cli CONFIG GET bind | tail -1)
if [[ "$BIND" == *"0.0.0.0"* ]]; then
echo "[WARN] Redis 绑定了 0.0.0.0,可能存在安全风险!"
else
echo "[OK] Redis 绑定地址: $BIND"
fi
# 3. 检查是否禁用危险命令
DEBUG=$(redis-cli CONFIG GET rename-command | grep -c DEBUG)
if [ $DEBUG -gt 1 ]; then
echo "[WARN] DEBUG 命令未被禁用!"
else
echo "[OK] DEBUG 命令已禁用或重命名"
fi
# 4. 检查最大连接数
MAXCLIENTS=$(redis-cli CONFIG GET maxclients | tail -1)
echo "最大连接数: $MAXCLIENTS"
# 5. 检查保护模式
PROTECTED=$(redis-cli CONFIG GET protected-mode | tail -1)
if [ "$PROTECTED" = "yes" ]; then
echo "[OK] 保护模式已启用"
else
echo "[WARN] 保护模式已关闭!"
fi
# 6. 检查是否使用 root 运行
REDIS_USER=$(ps aux | grep redis-server | grep -v grep | awk '{print $1}')
if [ "$REDIS_USER" = "root" ]; then
echo "[WARN] Redis 使用 root 用户运行!"
else
echo "[OK] Redis 使用 $REDIS_USER 用户运行"
fi
echo ""
echo "=== 检查完成 ==="
5 主从复制配置
5.1 主从配置
# 从库配置(redis.conf) replicaof 192.168.1.100 6379 # 或者临时执行 redis-cli REPLICAOF 192.168.1.100 6379 # 取消复制(成为独立主库) redis-cli REPLICAOF NO ONE
5.2 主从配置参数
# 从库配置 replicaof 192.168.1.100 6379 replica-serve-stale-data yes # 主库失联时从库是否响应读请求 replica-read-only yes # 从库只读 repl-diskless-sync no # 是否使用无盘复制 repl-diskless-sync-delay 5 # 无盘复制延迟 repl-disable-tcp-nodelay no # 是否禁用 TCP_NODELAY replica-priority 100 # 从库优先级,哨兵选举时使用
5.3 验证复制状态
# 查看复制信息 redis-cli INFO replication # 输出示例 # role:master # connected_slaves:2 # slave0:ip=192.168.1.101,port=6379,state=online,offset=12345,lag=0 # slave1:ip=192.168.1.102,port=6379,state=online,offset=12345,lag=0 # 从库视角 # role:slave # master_host:192.168.1.100 # master_port:6379 # master_link_status:up # 检查复制延迟 redis-cli -hREPLICAOF NO ONE # 然后比较两边的 DBSIZE
6 哨兵集群
6.1 哨兵配置
# sentinel.conf # 哨兵端口 port 26379 # 哨兵监控的主节点 # sentinel monitorsentinel monitor mymaster 192.168.1.100 6379 2 # 密码(如果有) sentinel auth-pass mymaster your_password # 主节点down后多久进行故障转移 sentinel down-after-milliseconds mymaster 30000 # 故障转移超时时间 sentinel failover-timeout mymaster 180000 # 故障转移时同时同步的新从库数量 sentinel parallel-syncs mymaster 1 # 自动发现其他哨兵 sentinel monitor mymaster 192.168.1.100 6379 2 sentinel known-replica mymaster 192.168.1.101 6379 sentinel known-sentinel mymaster 192.168.1.200 26379
6.2 启动哨兵
# 启动哨兵 redis-sentinel /etc/redis/sentinel.conf # 或者 redis-server /etc/redis/sentinel.conf --sentinel # 查看哨兵状态 redis-cli -p 26379 INFO sentinel # 查看所有监控的主节点 redis-cli -p 26379 SENTINEL masters # 查看特定主节点的详细信息 redis-cli -p 26379 SENTINEL MASTER mymaster # 查看主节点的所有从库 redis-cli -p 26379 SENTINEL REPLICAS mymaster
6.3 哨兵部署建议
至少部署 3 个哨兵实例
哨兵应该部署在不同的物理机器上
哨兵数量应该 >= (2n+1),其中 n 为主库数量
quorum 设置应该为 (哨兵数量/2)+1
# 3 个哨兵的配置 # sentinel.conf sentinel monitor mymaster 192.168.1.100 6379 2 # 5 个哨兵的配置 # sentinel.conf sentinel monitor mymaster 192.168.1.100 6379 3
7 集群模式
7.1 Redis Cluster 配置
# redis.conf (集群节点配置) cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 15000 cluster-replica-validity-factor 10 cluster-migration-barrier 1 cluster-require-full-coverage yes
7.2 创建集群
# 假设有 6 个 Redis 实例 # 3 个主库: 192.168.1.101:6379, 192.168.1.102:6379, 192.168.1.103:6379 # 3 个从库: 192.168.1.104:6379, 192.168.1.105:6379, 192.168.1.106:6379 # 创建集群 redis-cli --cluster create 192.168.1.101:6379 192.168.1.102:6379 192.168.1.103:6379 192.168.1.104:6379 192.168.1.105:6379 192.168.1.106:6379 --cluster-replicas 1 # 参数说明: # --cluster-replicas 1: 每个主库配置 1 个从库
7.3 集群管理命令
# 查看集群状态 redis-cli -c -h 192.168.1.101 -p 6379 CLUSTER INFO # 查看节点列表 redis-cli -c -h 192.168.1.101 -p 6379 CLUSTER NODES # 查看槽分配 redis-cli -c -h 192.168.1.101 -p 6379 CLUSTER SLOTS # 添加新节点 redis-cli --cluster add-node 192.168.1.107:6379 192.168.1.101:6379 # 添加从库 redis-cli --cluster add-node 192.168.1.108:6379 192.168.1.101:6379 --cluster-slave # 删除节点 redis-cli --cluster del-node 192.168.1.101:6379# 重新分片 redis-cli --cluster reshard 192.168.1.101:6379 # 均衡槽分布 redis-cli --cluster rebalance 192.168.1.101:6379 # 故障转移 # 从库执行 redis-cli -h 192.168.1.104 -p 6379 CLUSTER FAILFAILOVER
7.4 集群扩缩容
# 扩容:添加新主库 # 1. 启动新节点 redis-server /etc/redis/redis.conf --daemonize yes # 2. 添加到集群 redis-cli --cluster add-node 192.168.1.107:6379 192.168.1.101:6379 # 3. 重新分片(分配槽) redis-cli --cluster reshard 192.168.1.101:6379 # 按照提示输入目标节点 ID 和槽数量 # 缩容:移除主库 # 1. 将槽迁移到其他主库 redis-cli --cluster reshard 192.168.1.101:6379 # 选择一个节点接收 192.168.1.107 的槽 # 2. 删除节点 redis-cli --cluster del-node 192.168.1.101:6379
8 监控与告警
8.1 INFO 命令详解
# 查看所有信息 redis-cli INFO # 查看特定 section redis-cli INFO server # 服务器信息 redis-cli INFO clients # 客户端信息 redis-cli INFO memory # 内存信息 redis-cli INFO persistence # 持久化信息 redis-cli INFO stats # 统计信息 redis-cli INFO replication # 复制信息 redis-cli INFO cpu # CPU 信息 redis-cli INFO commandstats # 命令统计 redis-cli INFO latencystats # 延迟统计 redis-cli INFO sentinel # 哨兵信息
8.2 关键监控指标
# 内存使用 redis-cli INFO memory | grep -E "used_memory_human|maxmemory_human|mem_fragmentation_ratio" # 连接数 redis-cli INFO clients # connected_clients: 100 # blocked_clients: 0 # tracking_clients: 0 # QPS redis-cli INFO stats | grep -E "instantaneous_ops_per_sec|total_commands_processed" # 复制延迟 redis-cli INFO replication | grep -E "master_repl_offset|replica_offset" # 持久化状态 redis-cli INFO persistence | grep -E "rdb_last_bgsave_status|aof_last_write_status"
8.3 慢查询日志
# 开启慢查询日志 redis-cli CONFIG SET slowlog-log-slower-than 10000 # 10ms redis-cli CONFIG SET slowlog-max-len 128 # 查看慢查询 redis-cli SLOWLOG GET 10 # 清空慢查询 redis-cli SLOWLOG RESET # 查看慢查询数量 redis-cli SLOWLOG LEN
slowlog 条目字段:
1) (integer) 4 # 条目 ID 2) (integer) 1609459200 # Unix 时间戳 3) (integer) 5000 # 执行时间(微秒) 4) 1) "GET" # 命令 2) "mykey" # 参数 5) "127.0.0.1:12345" # 客户端 IP
8.4 监控脚本
#!/bin/bash
# filename: redis_monitor.sh
# Redis 监控脚本
ALERT_EMAIL="ops@example.com"
REDIS_HOST="127.0.0.1"
REDIS_PORT="6379"
REDIS_PASSWORD=""
WARN_MEMORY_PCT=80
CRIT_MEMORY_PCT=90
# 获取内存使用率
MEMORY_INFO=$(redis-cli -h $REDIS_HOST -p $REDIS_PORT -a $REDIS_PASSWORD INFO memory 2>/dev/null)
USED=$(echo "$MEMORY_INFO" | grep used_memory: | cut -d: -f2)
MAX=$(redis-cli -h $REDIS_HOST -p $REDIS_PORT -a $REDIS_PASSWORD CONFIG GET maxmemory | tail -1)
MEMORY_PCT=$(echo "scale=2; $USED*100/$MAX" | bc)
echo "内存使用率: ${MEMORY_PCT}%"
if (( $(echo "$MEMORY_PCT > $CRIT_MEMORY_PCT" | bc -l) )); then
echo "严重: 内存使用率超过 ${CRIT_MEMORY_PCT}%" | mail -s "[CRITICAL] Redis 内存告警" $ALERT_EMAIL
elif (( $(echo "$MEMORY_PCT > $WARN_MEMORY_PCT" | bc -l) )); then
echo "警告: 内存使用率超过 ${WARN_MEMORY_PCT}%" | mail -s "[WARNING] Redis 内存告警" $ALERT_EMAIL
fi
# 检查连接数
CLIENTS=$(redis-cli -h $REDIS_HOST -p $REDIS_PORT -a $REDIS_PASSWORD INFO clients | grep connected_clients | cut -d: -f2)
echo "连接数: $CLIENTS"
# 检查复制延迟
REPL_LAG=$(redis-cli -h $REDIS_HOST -p $REDIS_PORT -a $REDIS_PASSWORD INFO replication | grep -E "master_repl_offset|replica0:offset" | tail -2)
echo "复制状态: $REPL_LAG"
# 检查持久化状态
PERSISTENCE=$(redis-cli -h $REDIS_HOST -p $REDIS_PORT -a $REDIS_PASSWORD INFO persistence | grep -E "rdb_last_bgsave_status|aof_last_write_status")
echo "持久化状态: $PERSISTENCE"
9 常见问题与解决方案
9.1 OOM(内存溢出)
现象:
OOM command not allowed when used memory > 'maxmemory'
排查:
# 查看内存使用
redis-cli INFO memory | grep used_memory
redis-cli CONFIG GET maxmemory
# 查看大 key
redis-cli --bigkeys
# 查看 key 统计
redis-cli --scan | head -1000 | xargs -I {} redis-cli DEBUG OBJECT ENCODING {}
解决:
增加 maxmemory
调整淘汰策略
清理无用数据
使用 Redis Cluster 分片
9.2 持久化失败
现象:
Background saving error BGSAVE failed
排查:
# 查看最后保存状态 redis-cli INFO persistence # 查看磁盘空间 df -h # 查看 Redis 数据目录权限 ls -la /var/lib/redis/
解决:
确保磁盘空间充足
确保 Redis 用户有写权限
修改 dir 路径到有空间的分区
9.3 复制断开
现象:
Disconnected from master Master link status: down
排查:
# 查看复制状态 redis-cli INFO replication # 检查主库是否可达 telnet 192.168.1.100 6379 # 检查网络 ping -c 5 192.168.1.100
解决:
确保主库可达
检查防火墙设置
如果是主库挂了,等待故障转移或手动切换
9.4 响应延迟
现象:Redis 响应变慢
排查:
# 检查慢查询 redis-cli SLOWLOG GET 10 # 检查大 key redis-cli --bigkeys # 检查 CPU 使用 top -p $(pidof redis-server) # 检查内存碎片 redis-cli INFO memory | grep mem_fragmentation_ratio
解决:
优化慢查询命令
拆分大 key
整理内存碎片
增加 Redis 实例
10 总结
10.1 生产环境检查清单
| 检查项 | 建议 |
|---|---|
| maxmemory | 设置为物理内存的 70-80% |
| 淘汰策略 | 缓存场景用 allkeys-lru |
| 持久化 | 建议同时启用 RDB 和 AOF |
| AOF 策略 | 使用 everysec 平衡性能和安全 |
| 密码 | 必须设置强密码 |
| 绑定地址 | 只监听内网 IP |
| 危险命令 | 重命名或禁用 |
| 备份 | 每日备份,保留 7 天 |
| 监控 | 监控内存、连接数、QPS |
| 日志 | 开启慢查询日志 |
10.2 推荐配置模板
# redis.conf 生产环境推荐配置 # 网络配置 bind 192.168.1.100 port 6379 timeout 300 tcp-keepalive 300 # 安全配置 requirepass your_strong_password rename-command FLUSHDB "" rename-command FLUSHALL "" rename-command DEBUG "" rename-command KEYS "" # 内存配置 maxmemory 8gb maxmemory-policy allkeys-lru maxmemory-samples 5 # 持久化配置 save 900 1 save 300 10 save 60 10000 stop-writes-on-bgsave-error yes rdbcompression yes rdbchecksum yes appendonly yes appendfsync everysec auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb # 内存碎片 activedefrag yes
10.3 运维注意事项
不要在生产环境执行 KEYS 命令:会阻塞 Redis,使用 SCAN 替代
# 错误 redis-cli KEYS "user:*" # 正确 redis-cli --scan --pattern "user:*" | head -1000
使用连接池:避免频繁创建和销毁连接
# Python 示例 import redis pool = redis.ConnectionPool(host='127.0.0.1', port=6379, password='pass', max_connections=50) r = redis.Redis(connection_pool=pool)
合理设置 TTL:避免 key 永不过期导致内存持续增长
# 设置 24 小时过期 SET session:12345 "data" EX 86400 # 或者 EXPIRE session:12345 86400
定期维护:定期检查内存、连接数、慢查询等指标
Redis 部署看起来简单,但生产环境中的坑很多。希望本文能帮助大家避坑,部署出稳定可靠的 Redis 服务。
全部0条评论
快来发表一下你的评论吧 !