Redis 使用场景、缓存什么数据?怎么保证数据一致性?
Redis 作为高性能的内存数据库,其核心价值在于极速读写能力与丰富的数据结构,但使用不当会导致数据一致性问题。
一、Redis 核心使用场景与缓存数据类型
1. 高频读低频写数据(缓存经典场景)
数据类型 | 示例 | 数据结构选择 |
---|---|---|
热点商品信息 | 商品详情页 | String/ Hash |
用户会话(Session) | 登录状态、购物车 | String |
全局配置项 | 系统开关、AB测试配置 | String/ Hash |
2. 复杂计算中间结果
场景 | Redis 解决方案 | 优势 |
---|---|---|
实时排行榜 | ZSET (有序集合) | 亿级数据毫秒排序 |
好友关系 | SET (集合) | 交集/并集快速计算 |
地理位置查询 | GEO | 附近的人/商家 |
3. 高并发写缓冲
- 适用场景:秒杀库存扣减、点赞计数
- 数据结构:
INCR
命令原子操作计数器
4. 不该缓存的数据类型
- 强一致性要求数据:银行账户余额
- 超大二进制文件:视频/图片(应用OSS存储)
- 极少访问的冷数据:历史归档记录
二、数据一致性保障方案(缓存与DB同步)
1. 主流方案对比
方案 | 一致性强度 | 延迟 | 复杂度 | 适用场景 |
---|---|---|---|---|
先更新DB后删缓存 | 最终一致 | 低 | 低 | 通用场景(推荐) |
双写事务 | 强一致 | 高 | 高 | 金融交易 |
订阅Binlog | 最终一致 | 中 | 中 | 异构系统同步 |
缓存过期 | 弱一致 | 不确定 | 低 | 容忍脏数据场景 |
2. 最佳实践:Cache-Aside Pattern
3. 关键问题解决方案
问题1:缓存删除失败
- 重试机制:
// 删除缓存的重试策略(指数退避) RetryTemplate retryTemplate = new RetryTemplate(); ExponentialBackOffPolicy backOff = new ExponentialBackOffPolicy(); backOff.setInitialInterval(500); backOff.setMultiplier(2); retryTemplate.setBackOffPolicy(backOff); retryTemplate.execute(ctx -> {redis.del(key);return null; });
问题2:并发写导致脏数据
- 分布式锁控制:
SET lock_key unique_id NX PX 30000 # 获取锁 // 执行DB更新+删缓存 EVAL "if redis.call('get',KEYS[1])==ARGV[1] then return redis.call('del',KEYS[1]) end" 1 lock_key unique_id
问题3:主从延迟
- 强制读主库:
/* 在SQL中增加Hint强制走主库 */ SELECT /*+ MASTER */ * FROM table WHERE id=100
三、多级缓存架构设计
缓存层级配置策略:
层级 | 缓存工具 | 过期时间 | 容量限制 |
---|---|---|---|
CDN | Akamai/阿里云CDN | 10分钟-24小时 | TB级 |
Nginx | proxy_cache | 1-5分钟 | 10-100GB |
应用本地缓存 | Caffeine | 30秒-2分钟 | 1-5GB |
分布式缓存 | Redis | 5分钟-12小时 | 百GB-TB级 |
四、高可靠生产配置
1. Redis 部署架构
2. 关键参数调优
# redis.conf 生产建议
maxmemory 64gb # 预留20%内存
maxmemory-policy volatile-lfu # 对带过期Key用LFU淘汰
appendfsync everysec # RDB+AOF混合持久化
cluster-require-full-coverage no # 部分节点故障仍可用
3. 监控告警指标
指标 | 危险阈值 | 监控工具 |
---|---|---|
内存使用率 | >80% | Prometheus |
网络延迟 | >50ms | Redis SLOWLOG |
Key驱逐速率 | >1000/秒 | info stats |
主从同步延迟 | >10MB | redis-cli --latency |
连接数 | >5000 | Grafana仪表盘 |
五、经典踩坑案例
案例:缓存雪崩
现象:大量Key同时过期 → 请求穿透到DB → 数据库崩溃
解决:
# 设置差异化过期时间
EXPIRE key ${base_time + random(0, 300)}
案例:热Key问题
现象:某明星离婚事件导致用户主页缓存Key QPS超50万
解决:
// 本地缓存+Redis二级缓存
LoadingCache<String, Object> localCache = Caffeine.newBuilder().maximumSize(10_000).refreshAfterWrite(1, TimeUnit.SECONDS).build(key -> redis.get(key));
案例:大Value阻塞
现象:10MB的JSON数据导致网络阻塞
解决:
# 压缩存储
import zlib
compressed = zlib.compress(json.dumps(data).encode())
redis.set(key, compressed)# 读取时解压
data = json.loads(zlib.decompress(redis.get(key)))
总结:Redis 使用黄金法则
-
缓存选型铁律:
- 只缓存变更频率低、访问频率高的数据
- 价值公式:
缓存收益 = (DB读取成本 - Redis读取成本) * 读取次数 - 缓存维护成本
-
一致性选择:
-
性能压测指标:
操作 单节点QPS GET/SET 10万+ LPUSH 8万+ ZADD 5万+ 事务(MULTI) 3万+
终极建议:
- 对一致性要求极高的场景:使用Redis作为只读缓存,写请求直落数据库
- 超大规模热点数据:采用Redis+本地缓存两级架构,本地缓存兜底
- 每天凌晨自动扫描大Key:
redis-cli --bigkeys -i 0.1
- 定期执行缓存穿透防御演练:模拟请求不存在的Key验证防护机制
你想要的我全都有:https://pan.q删掉憨子uark.cn/s/75a5a07b45a2