1. 当缓存遇到高并发:为什么我们需要锁?

在电商秒杀场景中,假设某商品库存缓存在Redis中。当1000个请求同时扣减库存时,如果不加控制,可能发生这样的情形:

# Python示例(技术栈:Redis + Python)
import redis
r = redis.Redis()

def reduce_stock():
    stock = int(r.get('product_001'))
    if stock > 0:
        r.decr('product_001')  # 非原子操作导致超卖

这个经典案例暴露了三个致命问题:

  1. 读取库存与实际扣减存在时间差
  2. 非原子操作导致数据不一致
  3. 并发请求未正确排队

2. 读写锁的四种经典模式

2.1 基础读写锁模式

# 互斥写锁实现(Python)
def safe_reduce_stock():
    with r.lock('product_lock'):  # 获取互斥锁
        stock = int(r.get('product_001'))
        if stock > 0:
            r.decr('product_001')

这种简单实现存在明显缺陷:

  • 单点性能瓶颈
  • 死锁风险
  • 锁超时难控制

2.2 乐观锁实践

# 使用WATCH实现CAS(技术栈:Redis事务)
def optimistic_reduce_stock():
    with r.pipeline() as pipe:
        while True:
            try:
                pipe.watch('product_001')
                stock = int(pipe.get('product_001'))
                if stock <= 0:
                    break
                pipe.multi()
                pipe.decr('product_001')
                pipe.execute()
                break
            except redis.WatchError:
                continue

特点分析:

  • 适合读多写少场景
  • 需要重试机制保障
  • 无法完全避免冲突

2.3 分布式读写锁

# Redisson实现(技术栈:Java + Redisson)
RLock lock = redisson.getLock("productLock");
try {
    lock.lock();
    // 业务操作
} finally {
    lock.unlock();
}

进阶特性:

  • 自动续期机制
  • 可重入设计
  • 锁等待队列

2.4 分段锁优化

# 库存分桶示例(Python)
def sharded_lock(stock_key):
    slot = hash(stock_key) % 16
    lock_key = f"lock_{slot}"
    with r.lock(lock_key):
        # 操作对应分片

优势体现:

  • 将全局锁拆分为多个槽位
  • 并发度提升N倍(N为分片数)
  • 需要配合数据分片使用

3. 锁冲突的四种典型场景

3.1 热点数据风暴

某社交平台的热门帖子缓存,每秒数万次读取请求。采用读写分离策略:

# 读写分离示例
def get_hot_post():
    # 读锁(共享)
    with r.read_lock('post_lock'):
        return r.get('hot_post_123')

def update_post():
    # 写锁(排他)
    with r.write_lock('post_lock'):
        # 更新操作

3.2 缓存雪崩时的锁风暴

当大量缓存同时失效时:

# 缓存重建锁(Java伪代码)
public Object getData(String key) {
    Object value = redis.get(key);
    if (value == null) {
        RLock lock = redisson.getLock(key + "_lock");
        if (lock.tryLock()) {
            try {
                // 二次检查
                value = db.query(key);
                redis.setex(key, 300, value);
            } finally {
                lock.unlock();
            }
        } else {
            Thread.sleep(50);
            return getData(key);
        }
    }
    return value;
}

3.3 分布式事务中的锁应用

订单支付场景示例:

# 事务锁组合(Python)
def pay_order():
    with r.lock('user_balance_lock'):
        with r.lock('order_status_lock'):
            # 扣减余额
            # 修改订单状态

3.4 缓存与数据库双写

# 双写一致性保障(技术栈:MySQL + Redis)
def update_product(info):
    with r.lock('product_lock'):
        # 先更新数据库
        db.update(info)
        # 再删除缓存
        r.delete('product_cache')

4. 性能优化五板斧

  1. 锁粒度控制:从全局锁到字段级锁
  2. 超时策略:动态调整锁持有时间
  3. 异步队列:非关键操作延迟执行
  4. 本地缓存:减少Redis访问频率
  5. 监控报警:实时跟踪锁等待时间

5. 踩坑经验总结

最近在物流系统中遇到的真实案例:

# 死锁示例(错误示范)
def process_order():
    lock1 = r.lock('A')
    lock2 = r.lock('B')
    # 获取锁顺序不一致导致死锁

解决方案:

  • 统一锁获取顺序
  • 设置锁等待超时
  • 使用全局排序算法

6. 技术选型指南

根据业务场景选择策略:

场景特征 推荐方案 适用案例
QPS < 1000 简单互斥锁 后台管理系统
1000 < QPS < 5000 读写锁+分段 电商商品详情页
QPS > 5000 无锁CAS+本地缓存 社交平台点赞数
强一致性要求 RedLock+版本控制 金融账户余额

7. 未来演进方向

  1. 基于AI的锁预测系统
  2. 动态锁粒度调整算法
  3. 跨数据中心的锁同步
  4. 量子加密锁技术探索