一、Redis基础知识
1、Redis概述
Redis(Remote Dictionary Server)是一个开源的内存型键值数据库,支持分布式架构和持久化存储。其核心特性如下:
-
内存存储
Redis将所有数据存储在内存中,读写操作无需磁盘I/O,响应速度达到微秒级(读11万次/秒,写8.1万次/秒)。同时支持RDB快照和AOF日志两种持久化机制,确保数据安全。 -
高性能
- 单线程模型:早期版本通过单线程处理命令,避免多线程竞争问题。
- I/O多路复用:基于Epoll/Kqueue实现高并发请求处理。
- 网络优化:Redis 6.0引入多线程网络I/O,提升吞吐量。
-
丰富数据结构
支持多种数据类型,包括:-
基础类型:字符串(String)、列表(List)、哈希(Hash)、集合(Set)、有序集合(ZSet)。
- 扩展类型:位图(Bitmap)、地理位置(GEO)、流(Stream)、HyperLogLog。
这些结构支持原子操作(如集合交并差运算、有序集合排序),适用于复杂业务场景。
-
- 适用场景:
- 缓存:
- 核心作用:缓解数据库压力,加速热点数据访问(如商品信息、用户会话)
- 典型流程:客户端请求→查询Redis缓存→命中则返回,未命中则查数据库并更新缓存
- 穿透防御:结合布隆过滤器(Bloom Filter)过滤无效请求
- 分布式锁:
- 实现方式:通过
SETNX
命令(或RedLock算法)实现跨服务的互斥资源访问 - 应用场景:秒杀库存扣减、分布式任务调度
- 实现方式:通过
- 消息队列:
- 基础功能:使用列表(List)实现生产者-消费者模型(如LPUSH/BRPOP命令)
- 高级模式:通过发布订阅(Pub/Sub)支持实时消息广播(如聊天室、通知系统)
- 排行榜:
- 技术实现:利用有序集合(ZSet)按分数(Score)排序,支持实时更新和范围查询
- 典型应用:游戏积分榜、电商销量排名、热搜榜单
- 缓存:
2、安装与配置
1)安装准备
环境要求:
- 操作系统:支持Linux(CentOS/Ubuntu等)、Windows
- 依赖工具:
gcc
编译器(Linux)、wget
或压缩包下载工具
版本选择:
- 推荐使用最新稳定版(如7.x),可通过官网(Downloads - Redis)或镜像站(如华为云镜像)下载。
2)Linux系统安装(以CentOS/Ubuntu为例)
安装依赖
# CentOS
sudo yum install -y gcc make wget
# Ubuntu
sudo apt update && sudo apt install -y build-essential tcl
下载与解压源码
wget http://download.redis.io/releases/redis-7.2.4.tar.gz
tar xzf redis-7.2.4.tar.gz
cd redis-7.2.4
编译安装
make && sudo make install
默认安装路径为 /usr/local/bin
,包含 redis-server
(服务端)和 redis-cli
(客户端)。
配置Redis
创建配置文件目录
sudo mkdir /etc/redis
sudo cp redis.conf /etc/redis/6379.conf
修改关键参数(使用 vim /etc/redis/6379.conf
)
bind 0.0.0.0 # 允许远程访问
port 6379 # 默认端口
daemonize yes # 后台运行
dir /var/lib/redis # 数据存储路径
requirepass yourpass # 设置访问密码
protected-mode no # 关闭保护模式(远程访问需关闭)
启动Redis服务
redis-server /etc/redis/6379.conf
验证安装
redis-cli -h 127.0.0.1 -p 6379 -a yourpass
127.0.0.1:6379> ping # 返回 "PONG" 表示成功
3、核心数据结构
Redis 的核心数据结构分为两个层面:对外暴露的 5 种基本数据类型和底层实现的高效数据结构。以下从这两个维度详细解析:
1)对外数据类型(value类型)
Redis 提供 5 种基础数据结构,所有键(Key)均为字符串,而值(Value)支持以下类型:
-
String(字符串)
- 功能:支持原子增减(
INCR/DECR
)、二进制安全存储。 - 应用场景:缓存、分布式锁(
SETNX
)、计数器(如文章阅读量统计)。 - 底层实现:根据内容长度和类型,可能使用
int
(整数)、embstr
(≤39字节的短字符串)或raw
(动态字符串 SDS)编码。
- 功能:支持原子增减(
-
Hash(哈希表)
- 功能:存储字段-值对,支持部分字段操作(
HGET/HSET
)。 - 应用场景:对象缓存(如用户信息)、购物车(商品 ID 与数量映射)。
- 底层实现:默认使用
ziplist
(压缩列表)存储小规模数据,超过阈值后转为hashtable
(哈希表)。
- 功能:存储字段-值对,支持部分字段操作(
-
List(列表)
- 功能:支持双端插入/弹出(
LPUSH/RPOP
),可实现栈或队列。 - 应用场景:消息队列(
BLPOP
实现阻塞消费)、微博关注列表。 - 底层实现:早期用双向链表,后优化为
quicklist
(快速列表,由多个压缩链表片段组成)。
- 功能:支持双端插入/弹出(
-
Set(集合)
- 功能:无序唯一元素集合,支持交/并/差集运算(
SINTER/SUNION
)。 - 应用场景:标签系统、共同好友计算。
- 底层实现:小规模时用
intset
(整数集合),大规模时转为hashtable
。
- 功能:无序唯一元素集合,支持交/并/差集运算(
-
ZSet(有序集合)
- 功能:按分值(Score)排序,支持范围查询(
ZRANGEBYSCORE
)。 - 应用场景:排行榜、延迟队列(按时间戳排序)。
- 底层实现:结合
skiplist
(跳跃表)和hashtable
,前者维护有序性,后者快速访问元素。
- 功能:按分值(Score)排序,支持范围查询(
2)底层数据结构(实现基础)
-
简单动态字符串(SDS)
- 特点:预分配空间和惰性释放策略,减少内存重分配次数。
- 结构:包含
len
(长度)、alloc
(预分配空间)、buf[]
(字符数组)。
-
字典(Dict)
- 作用:实现哈希键和 Redis 数据库的存储。
- 特性:使用链地址法解决哈希冲突,支持渐进式 Rehash(
ht[2]
双表交替迁移)。
-
跳跃表(Skiplist)
- 优势:平均 O(logN) 的查询效率,支持范围操作,用于 ZSet 的有序性维护。
-
压缩列表(Ziplist)
- 设计:连续内存块存储多个元素,节省内存,适用于小规模 Hash/List/ZSet。
-
快速列表(Quicklist)
- 优化:将多个压缩列表片段通过双向链表连接,平衡内存效率和操作性能。
4、持久化机制
-
RDB 持久化(快照持久化)
-
原理
RDB 通过生成内存数据的二进制快照文件(默认
dump.rdb
)保存数据。快照的触发方式包括:- 自动触发:基于配置规则(如
save 900 1
表示 900 秒内有至少 1 次写操作时触发)。 - 手动触发:通过
SAVE
(阻塞主进程)或BGSAVE
(异步生成,利用子进程)命令。
- 自动触发:基于配置规则(如
- 优点
- 恢复速度快:二进制文件紧凑,加载效率高。
- 性能影响小:
BGSAVE
通过子进程操作,主进程可继续处理请求。 - 适合备份与归档:文件体积小,便于长期存储和灾难恢复。
- 缺点
- 数据丢失风险:若两次快照间发生故障,最后一次快照后的数据会丢失。
- 资源占用高:生成快照时可能因数据量大导致 CPU 和内存压力。
- 适用场景
- 定期备份(如每日全量备份)。
- 容忍部分数据丢失的场景(如缓存数据、统计类数据)。
-
-
AOF 持久化(日志追加持久化 append only file)
-
原理
AOF 记录所有写操作命令(如
SET
、DEL
),以追加方式写入日志文件(默认appendonly.aof
)。通过appendfsync
参数控制同步策略:- always:每次写操作后同步(最安全,性能最低)。
- everysec:每秒同步(默认,平衡安全与性能)。
- no:依赖操作系统同步(性能最好,安全性最低)。
-
优点
- 数据完整性高:可恢复至故障前的最后一条命令。
- 可读性强:日志文件为文本格式,便于人工检查和修复。
-
缺点
- 文件体积大:频繁写操作导致日志膨胀,需定期执行
BGREWRITEAOF
压缩。 - 恢复速度慢:需逐条重放命令,数据量大时耗时较长。
- 文件体积大:频繁写操作导致日志膨胀,需定期执行
-
适用场景
- 对数据安全性要求极高的场景(如金融交易记录)。
- 需要精确恢复至特定时间点的场景。
-
-
混合持久化(RDB + AOF)
-
原理
结合 RDB 和 AOF 的优势:
- 定期生成 RDB 快照作为全量备份。
- 两次快照间通过 AOF 记录增量写操作。
- 重启时优先加载 AOF 文件,再结合 RDB 实现快速恢复。
-
优点
- 兼顾数据安全性与恢复效率。
- 适合对数据完整性和恢复速度均有高要求的场景。
-
-
持久化策略选择建议
- 仅用 RDB:适合缓存场景或对数据丢失容忍度较高的业务。
- 仅用 AOF:适合对数据一致性要求严苛的业务(需接受性能损耗)。
- 混合模式:推荐生产环境使用,平衡安全性与效率。
5、基础命令与操作
以下是 Redis 的基础命令与操作分类整理,结合了数据存储、键管理、事务处理等核心功能:
-
键(Key)操作
-
基础操作
SET key value
:设置键值对(支持字符串、数值等类型)GET key
:获取键对应的值EXISTS key
:检查键是否存在,返回 1(存在)或 0(不存在)DEL key
:删除指定键KEYS pattern
:按模式匹配查询键(如KEYS *
查询所有键,但生产环境慎用)
-
过期与生命周期
EXPIRE key seconds
:设置键的过期时间(秒)TTL key
:查看键剩余过期时间(-1 表示永不过期,-2 表示已过期)PERSIST key
:移除键的过期时间,使其永久有效
-
数据库管理
SELECT index
:切换数据库(默认 0-15 共 16 个库)FLUSHDB
:清空当前数据库FLUSHALL
:清空所有数据库
-
-
数据类型操作
-
字符串(String)
SETEX key seconds value
:设置键值并指定过期时间INCR key
:将键值加 1(适用于计数器)DECR key
:将键值减 1APPEND key value
:追加字符串到现有值末尾STRLEN key
:获取字符串长度
-
哈希(Hash)
HSET key field value
:设置哈希表中字段的值HGET key field
:获取哈希表字段值HGETALL key
:获取哈希表所有字段和值HDEL key field
:删除哈希表字段
-
列表(List)
LPUSH key value
:从列表头部插入元素RPUSH key value
:从列表尾部插入元素LRANGE key start end
:获取列表指定范围的元素(0 -1
表示全部)LPOP key
:移除并返回列表头部元素
-
集合(Set)
SADD key member
:向集合添加元素SMEMBERS key
:获取集合所有元素SINTER key1 key2
:返回多个集合的交集SISMEMBER key member
:判断元素是否在集合中
-
有序集合(ZSet)
ZADD key score member
:添加带权重的元素(用于排行榜)ZRANGE key start end
:按分数升序返回元素ZREVRANGE key start end
:按分数降序返回元素
-
-
事务与持久化
-
事务
MULTI
:开启事务EXEC
:执行事务块内的所有命令DISCARD
:取消事务
-
持久化
SAVE
:同步保存数据到磁盘(阻塞其他操作)BGSAVE
:后台异步保存数据到磁盘AOF
:通过日志追加方式持久化(需配置策略如appendfsync everysec
)
-
-
实用工具命令
PING
:测试服务是否连通(返回PONG
)INFO
:查看服务器基本信息(如内存、持久化状态)CONFIG GET parameter
:获取配置参数(如maxmemory
)
-
注意事项
- 性能优化:避免在生产环境使用
KEYS *
,改用SCAN
分批次查询 - 数据类型选择:根据场景选择合适的数据结构(如计数器用字符串,社交关系用集合)
- 事务限制:Redis 事务不支持回滚,需通过
WATCH
实现乐观锁
- 性能优化:避免在生产环境使用
二、Redis进阶知识
1、主从复制与集群
-
主从复制(Master-Slave Replication)
- 核心概念
- 主节点(Master):负责写入数据,数据变更后自动同步到从节点
- 从节点(Slave):只读节点,通过全量/增量复制机制从主节点同步数据
- 数据单向性:复制仅从主到从,无法反向同步
-
复制机制
- 全量复制:首次连接或数据差异较大时触发。主节点生成RDB快照发送给从节点,并记录后续写命令到缓冲区,传输完成后从节点加载快照并执行缓冲区命令
- 增量复制:主节点通过
PSYNC
命令将网络中断期间的写命令发送给从节点,依赖复制偏移量(offset)和复制积压缓冲区(repl_backlog)实现断点续传 - 命令传播:主节点实时将写命令发送给从节点,保持数据一致性
-
作用与优缺点
- 作用:数据冗余备份、读写分离(主写从读)、故障恢复
- 优点:提升读性能,支持横向扩展
- 缺点:主节点单点故障需手动切换;复制延迟可能导致数据不一致
- 核心概念
-
哨兵模式(Sentinel)
- 核心功能
- 监控:持续检测主从节点健康状态,通过心跳机制判断节点是否存活
- 自动故障转移:主节点宕机时,哨兵选举新主节点(优先级:复制偏移量 > 运行ID),并通知其他从节点切换主节点
- 通知客户端:向客户端推送主节点变更信息,实现动态服务发现
-
选举规则
- 排除断开时间过长的从节点。
- 优先选择
slave-priority
值低、复制偏移量高、运行ID小的从节点
-
适用场景
- 高可用需求场景,避免人工干预主从切换
- 核心功能
-
集群模式(Redis Cluster)
- 架构原理
- 数据分片:将数据划分为16384个哈希槽(hash slot),每个节点负责部分槽位
- 主从结构:每组槽位对应一个主节点和多个从节点,主节点处理读写,从节点备份数据
- 动态扩容:支持在线增删节点,通过槽位迁移实现负载均衡
-
高可用机制
- 故障转移:主节点宕机时,从节点自动升级为主节点
- Gossip协议:节点间通过PING-PONG通信同步状态,检测故障并触发恢复
-
优缺点
- 优点:支持水平扩展、高吞吐量、自动容灾
- 缺点:配置复杂;跨槽操作需使用
{}
标签强制路由,部分命令不支持(如多键事务)
- 架构原理
-
主从复制与集群对比
特性 主从复制 哨兵模式 Redis Cluster 数据分布 单一主节点,全量数据复制 主从结构+哨兵监控 分片存储,多主多从 故障恢复 手动切换 自动切换主节点 自动故障转移 扩展性 从节点扩展读能力 主从扩展+哨兵高可用 支持动态水平扩展 适用场景 读写分离、基础容灾 高可用但数据量中等 海量数据、高并发场景 -
核心配置与命令
-
主从复制配置
- 从节点配置:
REPLICAOF <master_ip> <master_port>
- 查看角色:
ROLE
命令显示节点状态(主/从)及复制偏移量
- 从节点配置:
-
哨兵配置
- 哨兵节点监控主节点:
sentinel monitor <master_name> <ip> <port> <quorum>
- 哨兵节点监控主节点:
-
集群搭建
- 创建集群:
redis-cli --cluster create <nodes> --cluster-replicas <num>
- 数据迁移:
CLUSTER ADDSLOTS
分配槽位,CLUSTER MEET
添加节点
- 创建集群:
-
2、性能优化
-
配置调优
- maxmemory:设定Redis实例的最大内存使用量。这不仅有助于防止Redis占用过多系统资源,还能在达到内存限制时触发相应的淘汰策略。
- maxclients:设置最大客户端连接数,确保服务器能够处理预期数量的并发请求。
- tcp-keepalive:保持TCP连接活跃,避免长时间无数据传输导致的连接中断问题。
-
数据结构选择与优化
- Hashes、Lists、Sets和Sorted Sets:对于某些特定场景,这些数据结构比基本的字符串类型更加高效。例如,当你需要存储用户信息时,使用哈希表而不是多个单独的键值对可以显著减少内存消耗。
- Pipeline:通过批量发送命令来减少网络往返时间(RTT),特别是在执行大量读写操作时效果明显。
- Lua脚本:利用Lua脚本在服务端执行复杂的事务逻辑,减少客户端与服务器之间的通信开销。
-
持久化策略
- RDB快照:定期创建内存数据的快照文件,适合用于备份和灾难恢复。但要注意调整save参数以平衡数据安全性和性能影响。
- AOF日志:记录每个写操作到日志文件中,提供更好的数据安全性。通过配置appendfsync选项控制同步频率,以权衡性能和可靠性。
-
内存管理
- 淘汰策略:如volatile-lru、allkeys-lru等,根据应用需求选择合适的淘汰策略,以保证Redis在内存满载时仍能正常工作。
- 对象共享:Redis内部会对小范围的整数值进行对象共享,减少内存占用。
-
网络优化
- 连接池:减少频繁建立和断开连接的成本,提升响应速度。
- Redis Cluster:当单个节点不足以应对负载时,可以通过集群分散流量,实现水平扩展。
-
监控与维护
- 使用监控工具(如Prometheus+Grafana)实时监测Redis运行状态,包括内存使用情况、CPU负载、命中率等关键指标。
- 定期分析慢查询日志,识别并优化耗时长的操作。
-
更新与升级
- 保持Redis版本更新至最新稳定版,以获得最新的功能增强和性能改进。
3、缓存问题
-
缓存穿透
-
定义
-
缓存穿透是指查询一个根本不存在的数据,由于缓存中没有该数据的信息,导致每次请求都会直接访问数据库。这种情况不仅浪费了数据库资源,还可能因大量无效请求导致数据库过载。下面详细聊聊Redis缓存穿透的问题及其解决方案。
-
-
缓存穿透的原因
- 恶意攻击:黑客故意构造大量不存在的键进行频繁请求,目的是使后端数据库崩溃。
- 系统设计缺陷:在某些情况下,业务逻辑允许查询非存在的数据,且这些查询未被妥善处理。
-
解决方案
-
缓存空对象
当从数据库查询到某个键对应的数据为空时,可以将这个键对应的值设置为一个特殊值(例如
null
),并设置较短的过期时间。这样下次再有相同的请求时,可以直接从缓存中返回结果,避免再次查询数据库。- 优点:简单易行,能有效防止缓存穿透。
- 缺点:如果空对象过多,会占用额外的缓存空间;若过期时间设置不当,可能会导致短时间内多次查询数据库。
-
布隆过滤器(Bloom Filter)
布隆过滤器是一种高效的空间利用率高的概率型数据结构,用于判断一个元素是否在一个集合中。通过预先将数据库中的所有键加入布隆过滤器,可以在查询前先检查布隆过滤器,如果它说“不在”,则肯定不在;如果说“可能存在”,则进一步查询数据库或缓存。
- 优点:极大地减少了对数据库的无谓查询,非常适合高并发场景。
- 缺点:存在一定的误判率,即可能会错误地标记某些键为“可能存在”。
-
接口层增加校验
在应用层面增加必要的参数校验和合法性检查,如用户输入的有效性验证,拒绝非法请求到达服务层。
- 优点:可以从根本上减少不必要的请求,保护后端服务。
- 缺点:需要在业务逻辑中添加额外的检查逻辑,增加了开发成本。
-
限流
对于同一类型的请求,在一定时间内限制其访问频率,可以通过令牌桶算法、漏桶算法等实现。
- 优点:有效防止因突发流量导致的服务不可用。
- 缺点:需根据具体业务场景调整限流策略,否则可能影响正常用户的使用体验。
-
-
-
缓存雪崩
-
定义
- Redis缓存雪崩是指在某一时刻,大量缓存数据同时失效,导致大量的请求直接打到后端数据库,从而可能导致数据库负载骤增,甚至崩溃的情况。这种情况类似于缓存穿透,但其原因和影响范围通常更为广泛。
-
缓存雪崩的原因
-
缓存数据过期时间集中:
- 如果大量缓存数据设置了相同的过期时间,一旦这些缓存同时到期,将会导致大量请求瞬间涌向数据库。
-
Redis实例宕机或重启:
- 当Redis实例出现故障(如宕机或重启)时,所有缓存数据都会丢失,导致所有的请求都必须重新从数据库加载数据。
-
网络问题或其他系统故障:
- 网络波动或者系统其他部分的故障也可能导致缓存服务不可用,进而引发类似的问题。
-
-
缓存雪崩的影响
- 数据库压力骤增:由于大量请求直接访问数据库,可能会导致数据库响应变慢,甚至崩溃。
- 系统性能下降:数据库负载增加会导致整个系统的响应速度变慢,用户体验恶化。
- 可能引起连锁反应:如果数据库不堪重负,可能进一步影响其他依赖该数据库的服务,形成连锁反应。
-
预防和应对措施
-
设置随机过期时间
为了避免大量缓存数据在同一时间点失效,可以在设置缓存过期时间时加入一个随机因子。例如,原定的过期时间为60分钟,可以在这个基础上加上一个0到10分钟之间的随机值。
-
使用互斥锁(Mutex Lock)
当某个缓存失效时,可以通过加锁机制确保只有一个线程去重建缓存,其他线程等待该线程完成后再从缓存中读取数据。这可以避免多个线程同时查询数据库,减轻数据库的压力。
-
热点数据永不过期
对于一些非常重要的热点数据,可以设置它们永不过期,并通过后台任务定期更新这些数据。这样即使发生缓存雪崩,也不会影响到这些关键数据的可用性。
-
多级缓存策略
除了Redis作为一级缓存外,还可以引入二级缓存(如本地缓存)。当Redis缓存失效时,首先尝试从本地缓存中获取数据;若本地缓存也没有,则再查询数据库。
-
Redis集群与高可用架构
为了防止单点故障导致缓存雪崩,可以采用Redis集群方案,实现数据的分布式存储和自动故障转移。此外,配置主从复制和哨兵监控等机制,提高系统的容错能力和稳定性。
-
-
-
缓存击穿
-
定义
- 缓存击穿(Cache Breakdown或Cache Penetration)是指一个非常热门的键在缓存中过期时,大量并发请求同时访问这个键,导致这些请求直接穿透缓存层,全部打到后端数据库上。这种情况虽然不像缓存雪崩那样影响广泛,但对特定热点数据的影响却是致命的,可能导致数据库瞬间压力剧增。
-
缓存击穿的原因
- 热点数据过期:某些键的数据非常热门,但在某一时刻其缓存过期了,此时如果大量的并发请求同时查询该键,则所有请求都会穿透到数据库。
- 高并发场景:特别是在高并发的应用环境中,这种现象更容易发生,并且带来的负面影响也更大。
-
预防和应对措施
-
互斥锁(Mutex Lock)
当某个热门键过期时,使用分布式锁来确保只有一个线程去重新加载数据到缓存中,其他线程等待该线程完成后再从缓存中读取数据。这可以避免多个线程同时查询数据库,减轻数据库的压力。
-
热点数据永不过期
对于一些特别重要的热点数据,可以设置它们永不过期,并通过后台任务定期更新这些数据。这样即使发生缓存击穿的情况,也不会影响到这些关键数据的可用性。
-
异步更新缓存
当检测到某条数据即将过期时,可以通过异步的方式提前更新缓存中的数据,而不是等到缓存真正过期后再进行更新。这样可以有效减少因缓存过期而导致的瞬时负载增加。
-
多级缓存
除了Redis作为一级缓存外,还可以引入二级缓存(如本地缓存)。当Redis缓存失效时,首先尝试从本地缓存中获取数据;若本地缓存也没有,则再查询数据库。这种方式可以在一定程度上缓解缓存击穿的问题。
-
-
三、Redis高级知识
1、源码级解析
2、云原生与运维
3、企业级扩展方案
四、Redis实战
-
高性能Redis缓存实战(python版)
-
缓存三大问题解决方案
-
缓存穿透(恶意请求不存在的数据)
-
import redis import hashlib from typing import Optional class ProductCache: def __init__(self): self.redis = redis.Redis(host='localhost', port=6379, db=0) # 使用RedisBloom模块(需提前加载) self.bf_key = "product_bf" def get_product(self, product_id: str) -> Optional[dict]: # 先检查布隆过滤器 if not self.redis.bf.exists(self.bf_key, product_id): return None # 查询缓存 cache_key = f"product:{product_id}" data = self.redis.get(cache_key) if data: if data == b'NULL': # 空值标识 return None return json.loads(data) # 查数据库并回填缓存(此处模拟数据库查询) db_data = self._get_from_db(product_id) if not db_data: # 空值缓存5分钟防止穿透 self.redis.setex(cache_key, 300, 'NULL') return None self.redis.setex(cache_key, 3600, json.dumps(db_data)) return db_data def _get_from_db(self, product_id: str) -> Optional[dict]: """模拟数据库查询,返回None表示数据不存在""" # ...数据库查询逻辑...
-
-
缓存击穿(热点Key突然失效)
- 12
-
import time from redis.exceptions import LockError def get_product_with_lock(product_id: str) -> dict: cache_key = f"product:{product_id}" data = redis.get(cache_key) if data: return json.loads(data) # 尝试获取分布式锁 lock_key = f"lock:{cache_key}" try: # 使用SET命令替代已弃用的SETNX if redis.set(lock_key, "1", nx=True, ex=10): # 双重检查 data = redis.get(cache_key) if data: return json.loads(data) # 查询数据库 db_data = get_from_db(product_id) redis.setex(cache_key, 3600, json.dumps(db_data)) return db_data else: # 等待其他线程加载 time.sleep(0.1) return get_product_with_lock(product_id) finally: try: redis.delete(lock_key) except LockError: pass
-
- 12
-
缓存雪崩(大量Key同时失效)
- 1
-
import random def set_cache_with_random_ttl(key: str, value: str): # 基础TTL 1小时 + 随机0-300秒 ttl = 3600 + random.randint(0, 300) redis.setex(key, ttl, value)
-
- 1
-
-