在现代互联网系统中,高并发已经成为常态。无论是电商的秒杀场景、社交平台的热点推荐,还是支付接口的风控,系统需要同时应对成千上万的请求。这时候,Redis 作为一个高性能的内存数据库,凭借其极快的读写速度和丰富的数据结构,成为解决高并发问题的利器。
1. 缓存热点数据 —— 缓解数据库压力
问题背景:数据库在高并发场景下容易成为瓶颈,特别是热点数据的访问会导致 QPS 瞬间飙升。
Redis 解决方案:
使用
String
或Hash
缓存热点数据。采用 Cache Aside 模式:先查缓存,缓存未命中再查数据库并回填。
示例代码:
import redisr = redis.Redis(host='localhost', port=6379, db=0)def get_data_from_db(key):print("查询数据库")return {"id": key, "value": f"data_{key}"}def get_data(key):cache_key = f"cache:{key}"val = r.get(cache_key)if val:print("命中缓存")return eval(val)data = get_data_from_db(key)r.setex(cache_key, 60, str(data))return dataprint(get_data(1))
print(get_data(1))
在高并发场景下使用 Cache-Aside(旁路缓存) 模式,确实需要特别注意一些坑点和边界情况。主要有以下几个方面:
1. 缓存击穿(Cache Miss Under High Concurrency)
问题:某个热点 key 过期瞬间,大量请求并发打到数据库,造成瞬时压力飙升。
解决:
加 互斥锁(分布式锁) 控制只允许一个请求回源数据库并更新缓存。
或者使用 逻辑过期:缓存里放置过期时间戳,过期时先返回旧值,再异步刷新。
2. 缓存穿透(Cache Penetration)
问题:请求的数据在数据库中不存在,每次都会查询 DB,导致 DB 压力大。
解决:
缓存空对象(短 TTL),避免重复访问 DB。
增加 布隆过滤器 或 前置拦截机制,快速判断 key 是否可能存在。
3. 缓存雪崩(Cache Avalanche)
问题:大量缓存 key 在同一时间点同时过期,引发请求全部打到 DB。
解决:
给 key 设置 随机过期时间,避免同时失效。
使用 多级缓存(L1/L2) 减轻瞬时压力。
4. 数据一致性(Consistency)
问题:Cache-Aside 是 最终一致性,更新逻辑里 “先写 DB 再删缓存” 会有时间窗口问题。
解决:
常见策略是 先更新 DB,再删除缓存(推荐),避免脏读。
或者使用 延时双删(写 DB → 删缓存 → 延迟一小段时间再删一次缓存)。
若业务对一致性要求极高,可能需要 订阅 binlog(如 Canal)异步更新缓存。
5. 热点 Key 与大 Value
热点 Key:可能被频繁访问,甚至成为单点瓶颈。可通过 分片/多副本 缓解。
大 Value:更新频率低但体积大时,更新缓存成本高,可以考虑 局部字段缓存 或 拆分存储。
6. 并发控制 & 原子性
多线程并发下需要注意 读写竞争:避免多个线程同时回源刷新。
分布式场景下要用 原子操作(如 Redis 的 setnx + expire) 做锁和限流。
7. 监控与降级
监控缓存命中率、请求 QPS、DB 压力。
当缓存大面积失效时,可以考虑:
启动 限流/熔断。
提供 降级数据(兜底逻辑)。
应用场景:用户信息、商品详情页、首页推荐数据等。
2. 限流 —— 防止接口过载
问题背景:突发流量可能会压垮下游服务,例如秒杀、登录、支付接口。
Redis 解决方案:
使用
String
作为计数器:INCR
+EXPIRE
实现固定时间窗口限流。使用
Sorted Set
存储时间戳:实现滑动窗口限流,更加精细化。可以配合 Lua 脚本保证原子性操作。
应用场景:API 调用限流、防止刷单、短信/验证码接口保护。
示例代码(滑动窗口限流):
import time
import redisr = redis.Redis(host='localhost', port=6379, db=0)def is_allowed_sliding_window(user_id, action, period=60, max_count=5):key = f"rate_limit:{user_id}:{action}"now = time.time()pipeline = r.pipeline()pipeline.zadd(key, {now: now})pipeline.zremrangebyscore(key, 0, now - period)pipeline.zcard(key)pipeline.expire(key, period)_, _, count, _ = pipeline.execute()return count <= max_countfor i in range(10):if is_allowed_sliding_window("u1001", "login"):print(i, "允许")else:print(i, "拒绝")time.sleep(0.5)
或者 使用 String
作为计数器
import redis
import timer = redis.Redis(host='localhost', port=6379, db=0)def is_allowed(user_id, action, period=60, max_count=5):"""在 period 时间内最多允许 max_count 次操作"""key = f"rate_limit:{user_id}:{action}"count = r.incr(key)if count == 1:r.expire(key, period) # 设置过期时间if count > max_count:return Falsereturn True# 测试
for i in range(10):if is_allowed("u1001", "login"):print(i, "允许")else:print(i, "拒绝")time.sleep(0.5)
3. 分布式队列 —— 异步削峰
问题背景:大量请求直接打到数据库或下游服务,可能会瞬间撑爆系统。
Redis 解决方案:
使用
List
(LPUSH
+BRPOP
)作为简单任务队列。使用
Stream
实现类似 Kafka 的消息队列:支持消费组、消息确认和持久化。常见用途:削峰填谷,将请求转为异步任务,让系统有更多缓冲时间。
应用场景:订单处理、日志收集、消息通知、秒杀排队。
示例代码(Stream 队列):
import redisr = redis.Redis(host='localhost', port=6379, db=0)
stream_key = "order_stream"# 生产者
def produce():for i in range(5):r.xadd(stream_key, {"order": f"order_{i}"})print("生产订单:", f"order_{i}")# 消费者
def consume():last_id = "0-0"while True:messages = r.xread({stream_key: last_id}, block=2000, count=2)if not messages:breakfor _, msgs in messages:for msg_id, data in msgs:print("消费订单:", msg_id, data)last_id = msg_idproduce()
consume()
4. 分布式锁 —— 保证数据一致性
问题背景:在分布式环境中,多实例同时修改同一资源,可能造成数据冲突。
Redis 解决方案:
使用
String
类型:SET key value NX PX timeout
实现加锁,避免重复设置。校验
value
防止误删锁。
高级方案:使用 RedLock 算法 提升可靠性,避免单点故障。
应用场景:库存扣减、任务调度、并发下的幂等操作。
示例代码:
import redis
import uuid
import timer = redis.Redis(host='localhost', port=6379, db=0)def acquire_lock(lock_key, expire=5):lock_id = str(uuid.uuid4())result = r.set(lock_key, lock_id, nx=True, ex=expire)return lock_id if result else Nonedef release_lock(lock_key, lock_id):script = """if redis.call('get', KEYS[1]) == ARGV[1] thenreturn redis.call('del', KEYS[1])elsereturn 0end"""return r.eval(script, 1, lock_key, lock_id)lock_id = acquire_lock("my_lock", expire=3)
if lock_id:print("获得锁,执行业务逻辑...")time.sleep(2)print("释放锁:", release_lock("my_lock", lock_id))
else:print("未获得锁")
5. 实时统计与排行榜
问题背景:高并发下,需要对访问量、点赞数、排名进行实时计算。
Redis 解决方案:
使用
INCR
/HINCRBY
做计数器。使用
Sorted Set
实现排行榜,支持按分数排序。
应用场景:网站 PV/UV 统计、热搜榜、积分排名、点赞排行榜。
示例代码:
import redisr = redis.Redis(host='localhost', port=6379, db=0)# 统计 PV
r.incr("page_view")
print("页面访问量:", r.get("page_view").decode())# 排行榜
leaderboard = "game_rank"
r.zincrby(leaderboard, 10, "user1")
r.zincrby(leaderboard, 20, "user2")print("排行榜:", r.zrevrange(leaderboard, 0, -1, withscores=True))
总结
在互联网高并发场景下,Redis 可以解决以下核心问题:
缓存热点数据 → 缓解数据库压力,提升响应速度。
限流 → 防止突发流量冲击系统。
分布式队列 → 实现削峰填谷,支撑异步处理。
分布式锁 → 保证数据一致性,防止并发冲突。
实时统计与排行榜 → 提供快速的聚合计算能力。
Redis 不仅仅是一个缓存,更是一个 高并发场景下的基础设施。合理利用其数据结构与特性,可以极大提升系统的可扩展性与稳定性。