Skip to content
清晨的一缕阳光
返回

Redis 最佳实践总结

Redis 最佳实践总结

一、架构设计最佳实践

1.1 选型决策树

选择部署方案:

1. 数据量是否 > 50GB?
   ├── 是 → Cluster 集群
   └── 否 → 2

2. QPS 是否 > 10 万?
   ├── 是 → Cluster 集群
   └── 否 → 3

3. 是否需要自动故障转移?
   ├── 是 → 哨兵模式
   └── 否 → 主从复制

4. 预算是否充足?
   ├── 否 → 单机版(开发测试)
   └── 是 → 哨兵模式(3 哨兵 +1 主 2 从)

1.2 推荐架构

规模架构节点数内存QPS
小型单机14GB<1 万
中型主从38GB<5 万
大型哨兵616GB<10 万
超大型Cluster6+32GB+>10 万

1.3 Key 设计规范

# 命名规范
业务名:模块名:ID:字段
user:profile:12345:name
order:detail:202511050001:status

# 避免的模式
 user_12345_name     # 分隔符不统一
 User:12345:Name     # 大小写不一致
 very:long:key:that:wastes:memory:12345  # 过长

# 推荐
 user:12345:name     # 简洁明了
 u:12345:n           # 极致压缩(内部系统)

1.4 数据类型选择

场景推荐类型理由
简单缓存String性能最好
对象存储Hash可单独修改字段
计数器String+INCR原子操作
队列List/Stream先进先出
排行榜ZSet自动排序
去重Set天然去重
UV 统计HyperLogLog节省空间
签到Bitmap极致压缩
地理位置GEO内置计算

二、性能优化最佳实践

2.1 内存优化

# 内存配置
maxmemory 8gb                    # 预留 25%
maxmemory-policy allkeys-lru     # 推荐淘汰策略
maxmemory-samples 10             # 采样数量

# 压缩优化
hash-max-ziplist-entries 512     # Hash 压缩列表
hash-max-ziplist-value 64
list-max-ziplist-size -2         # List 压缩
set-max-intset-entries 512       # Set 整数集合
zset-max-ziplist-entries 128     # ZSet 压缩
zset-max-ziplist-value 64

内存监控

# 关键指标
INFO memory | grep used_memory_human
INFO memory | grep mem_fragmentation_ratio

# 告警阈值
# 内存使用率 > 80%:告警
# 碎片率 > 1.5:需要整理
# 淘汰次数 > 1000/s:需要扩容

2.2 命令优化

避免的命令

# ❌ 危险命令(阻塞主线程)
KEYS *              # 使用 SCAN 代替
HGETALL large_hash  # 使用 HSCAN 代替
SMEMBERS large_set  # 使用 SSCAN 代替
LRANGE list 0 -1    # 限制范围

# ✅ 推荐替代
SCAN 0 MATCH pattern COUNT 1000
HSCAN key 0 COUNT 100
SSCAN key 0 COUNT 100
LRANGE list 0 100

批量操作

// ❌ 逐个操作(1000 次网络往返)
for (String key : keys) {
    jedis.get(key);
}

// ✅ Pipeline(1 次网络往返)
Pipeline pipeline = jedis.pipelined();
for (String key : keys) {
    pipeline.get(key);
}
List<Response<String>> results = pipeline.sync();

// ✅ MGET(1 次网络往返)
List<String> values = jedis.mget(keys.toArray(new String[0]));

2.3 连接池优化

JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(50);           // 最大连接数
config.setMaxIdle(20);            // 最大空闲连接
config.setMinIdle(5);             // 最小空闲连接
config.setMaxWaitMillis(3000);    // 获取连接超时
config.setTestWhileIdle(true);    // 空闲时检测
config.setTimeBetweenEvictionRunsMillis(30000); // 检测间隔

JedisPool pool = new JedisPool(config, host, port, 5000, password);

2.4 持久化优化

# RDB 优化
save 900 1          # 避免过于频繁
save 300 10
save 60 10000
rdbcompression yes  # 开启压缩
rdbchecksum yes     # 开启校验

# AOF 优化
appendonly yes
appendfsync everysec              # 推荐
no-appendfsync-on-rewrite yes     # 重写时不 fsync
auto-aof-rewrite-percentage 100   # 重写阈值
auto-aof-rewrite-min-size 256mb

# 混合持久化(推荐)
aof-use-rdb-preamble yes

三、运维监控最佳实践

3.1 关键指标监控

#!/bin/bash
# redis_monitor.sh

# 获取 INFO 信息
INFO=$(redis-cli INFO)

# 内存指标
USED_MEM=$(echo "$INFO" | grep "used_memory:" | cut -d: -f2)
MAX_MEM=$(redis-cli CONFIG GET maxmemory | tail -1)
MEM_PCT=$((USED_MEM * 100 / MAX_MEM))

# 连接指标
CONNECTED=$(echo "$INFO" | grep "connected_clients:" | cut -d: -f2)
BLOCKED=$(echo "$INFO" | grep "blocked_clients:" | cut -d: -f2)

# 性能指标
QPS=$(echo "$INFO" | grep "instantaneous_ops_per_sec:" | cut -d: -f2)
REJECTED=$(echo "$INFO" | grep "rejected_connections:" | cut -d: -f2)

# 持久化指标
RDB_STATUS=$(echo "$INFO" | grep "rdb_last_bgsave_status:" | cut -d: -f2)
AOF_ENABLED=$(echo "$INFO" | grep "aof_enabled:" | cut -d: -f2)

echo "=== Redis 监控 ==="
echo "内存使用:${MEM_PCT}%"
echo "连接数:$CONNECTED (阻塞:$BLOCKED)"
echo "QPS: $QPS"
echo "拒绝连接:$REJECTED"
echo "RDB 状态:$RDB_STATUS"
echo "AOF 开启:$AOF_ENABLED"

# 告警
[ $MEM_PCT -gt 80 ] && echo "⚠️  内存告警"
[ $CONNECTED -gt 1000 ] && echo "⚠️  连接数告警"
[ "$RDB_STATUS" != "ok" ] && echo "⚠️  RDB 失败告警"

3.2 慢查询分析

# 慢查询配置
slowlog-log-slower-than 10000  # 10ms
slowlog-max-len 128            # 保留 128 条
# 查看慢查询
SLOWLOG GET 10

# 分析慢查询原因
# 1. 大 Key 操作
# 2. 复杂命令(如集合运算)
# 3. 持久化阻塞
# 4. 内存淘汰

# 定期清理
SLOWLOG RESET

3.3 定期巡检清单

每日检查

每周检查

每月检查

四、安全最佳实践

4.1 访问控制

# 强密码
requirepass YourStrongPassword123!

# 禁用危险命令
rename-command FLUSHDB ""
rename-command FLUSHALL ""
rename-command CONFIG ""
rename-command KEYS ""
rename-command DEBUG ""
rename-command SHUTDOWN ""

# 绑定内网
bind 192.168.1.100

# 修改端口
port 6380

4.2 ACL 权限(Redis 6.0+)

# 默认用户
user default off

# 只读用户
user readonly on >readonlypass ~* +@read

# 应用用户
user appuser on >apppass ~app:* +@write +@read +INCR

# 监控用户
user monitoruser on >monitorpass ~* +INFO +PING

4.3 网络安全

# 防火墙规则
iptables -A INPUT -p tcp -s 192.168.1.0/24 --dport 6379 -j ACCEPT
iptables -A INPUT -p tcp --dport 6379 -j DROP

# TLS 加密(Redis 6.0+)
tls-port 6379
tls-cert-file /etc/redis/tls/redis.crt
tls-key-file /etc/redis/tls/redis.key
tls-ca-cert-file /etc/redis/tls/ca.crt

五、故障处理最佳实践

5.1 常见问题处理

问题 1:内存溢出

# 诊断
INFO memory
MEMORY STATS

# 解决
# 1. 临时增加内存
CONFIG SET maxmemory 16gb

# 2. 分析大 Key
redis-cli --bigkeys

# 3. 清理数据
--scan --pattern "cache:*" | xargs redis-cli unlink

# 4. 调整淘汰策略
CONFIG SET maxmemory-policy allkeys-lru

问题 2:CPU 过高

# 诊断
SLOWLOG GET 10
MONITOR | grep -E "KEYS|SMEMBERS|HGETALL"

# 解决
# 1. 终止问题命令
CLIENT KILL ADDR 192.168.1.100:12345

# 2. 优化慢查询

# 3. 限流
# 应用层限制 QPS

问题 3:主从同步失败

# 诊断
INFO replication

# 解决
# 1. 检查网络
telnet master-ip 6379

# 2. 检查磁盘空间
df -h

# 3. 重新配置主从
SLAVEOF master-ip 6379

# 4. 检查复制积压
CONFIG GET repl-backlog-size

5.2 故障转移演练

# 哨兵故障转移测试

# 1. 模拟主节点故障
redis-cli -h master DEBUG sleep 1000

# 2. 观察哨兵日志
tail -f /var/log/redis/sentinel.log

# 3. 验证新主节点
redis-cli -h new-master INFO replication

# 4. 验证数据完整性
redis-cli keys "*" | wc -l

六、高可用架构

6.1 哨兵模式配置

# sentinel.conf
port 26379
sentinel monitor mymaster 192.168.1.10 6379 2
sentinel auth-pass mymaster password
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 60000
sentinel parallel-syncs mymaster 1

6.2 Cluster 集群配置

# redis-cluster.conf
bind 0.0.0.0
port 7000
cluster-enabled yes
cluster-config-file nodes-7000.conf
cluster-node-timeout 5000
# 创建集群
redis-cli --cluster create \
    192.168.1.10:7000 192.168.1.11:7001 192.168.1.12:7002 \
    192.168.1.13:7003 192.168.1.14:7004 192.168.1.15:7005 \
    --cluster-replicas 1 --cluster-yes

七、缓存设计最佳实践

7.1 缓存策略

// 旁路缓存(Cache-Aside)
public String get(String key) {
    // 1. 查缓存
    String value = redis.get(key);
    if (value != null) {
        return value;
    }
    
    // 2. 查数据库
    value = db.get(key);
    if (value != null) {
        // 3. 写缓存
        redis.setex(key, 3600, value);
    }
    
    return value;
}

// 读写穿透(需要框架支持)
// 缓存命中:直接返回
// 缓存未命中:自动加载并缓存

7.2 缓存问题处理

缓存穿透

// 解决方案:布隆过滤器
if (!bloomFilter.mightContain(key)) {
    return null;  // 肯定不存在
}
// 继续查询缓存和数据库

缓存击穿

// 解决方案:互斥锁
String value = redis.get(key);
if (value == null) {
    String lockKey = "lock:" + key;
    if (redis.setnx(lockKey, "1", 10)) {
        try {
            // 双重检查
            value = redis.get(key);
            if (value == null) {
                value = db.get(key);
                redis.setex(key, 3600, value);
            }
        } finally {
            redis.del(lockKey);
        }
    } else {
        Thread.sleep(100);  // 等待后重试
        return get(key);
    }
}

缓存雪崩

// 解决方案:随机过期时间
int expireTime = 3600 + random.nextInt(300);
redis.setex(key, expireTime, value);

// 或者:永不过期 + 异步更新

八、总结

8.1 核心原则

  1. 简单优先:能用简单方案就不用复杂方案
  2. 预防为主:提前规划,避免问题发生
  3. 监控先行:建立完善的监控告警体系
  4. 安全底线:权限控制、网络隔离
  5. 持续优化:定期巡检、性能测试

8.2 检查清单

上线前

日常运维


分享这篇文章到:

上一篇文章
RocketMQ 延迟消息与定时消息详解
下一篇文章
AI 应用测试策略详解