在高并发场景下,缓存更新冲突是导致数据不一致的常见问题。本文将通过具体案例分析并发环境下的缓存一致性挑战,并提供有效的解决方案。
问题复现
假设有一个商品库存系统,使用Redis缓存商品信息。当多个请求同时尝试更新同一商品库存时,可能出现以下情况:
# 并发更新示例
async def update_stock(product_id, quantity):
# 读取当前库存
current_stock = await redis.get(f"stock:{product_id}")
# 模拟业务处理
time.sleep(0.1) # 模拟处理时间
# 更新库存
new_stock = int(current_stock) - quantity
await redis.set(f"stock:{product_id}", new_stock)
当两个请求同时执行时,都读取到相同的旧值,导致更新丢失。
解决方案
1. 分布式锁机制
async def update_stock_with_lock(product_id, quantity):
lock_key = f"lock:{product_id}"
# 获取分布式锁
if await redis.set(lock_key, "locked", nx=True, ex=10):
try:
current_stock = await redis.get(f"stock:{product_id}")
new_stock = int(current_stock) - quantity
await redis.set(f"stock:{product_id}", new_stock)
finally:
# 释放锁
await redis.delete(lock_key)
else:
# 锁获取失败,重试或抛出异常
raise Exception("获取锁失败")
2. CAS(Compare-And-Swap)机制
async def update_stock_cas(product_id, quantity):
while True:
current_stock = await redis.get(f"stock:{product_id}")
new_stock = int(current_stock) - quantity
# 使用CAS更新,确保数据一致性
result = await redis.set(
f"stock:{product_id}",
new_stock,
nx=True, # 仅当key不存在时设置
xx=True # 仅当key存在时设置
)
if result:
break # 更新成功退出循环
3. 消息队列异步更新 通过消息队列将更新请求排队处理,避免并发冲突。系统在消费消息时进行幂等性校验。
这些方案可根据业务场景选择使用,关键在于平衡一致性与性能要求。

讨论