redis、memache 乐观锁和进程

本文对比了Redis和Memcached中的乐观锁实现方式,并探讨了两者在多线程与单线程架构上的区别及其背后的设计考量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Memcached乐观锁

Memcached提供了2个命令 gets + cas。gets取出数据的时候,同时返回版本号;修改之后, cas回去的时候,会比较该版本号和服务器上最新的版本号。如果不等,则cas失败。

Redis乐观锁

Redis提供了watch命令,如下所示:

    watch  key1   //修改数据之前,执行watch,意思监听此key

    multi
    set key1  foo  //如果别的客户端在此期间修改了该key1,此处更新将失败
    exec 

 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

方案3 – Redis事务

Redis也提供了事务的概念,但它不能回滚。如果1条命令执行错误,会继续执行下面的。

      multi

      get foo

      ...

      incr foo

      exec
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

此处的multi/extc,类似Mysql中的beganTransaction/endTransaction。 
另外,由于redis是单线程的,因此事务里面的多条语句执行时,不会被打断。

Memcached的多线程 vs. Redis单线程

我们都知道, Memcached内部是多线程的,而Redis是单线程的。多线程好理解,但Redis为什么要搞成单线程呢? 
个人认为,有以下几个原因: 
(1)redis有各种复杂的数据结构list, has, set。也就是说,对于一个(key, value),value的类型可以是list, hash, set。在实际应用场景中,很容易出现多个客户端对同一个key的这个复杂的value数据结构进行并发操作,如果是多线程,势必要引入锁,而锁却是性能杀手。 
相比较而言,memcached只有简单的get/set/add操作,没有复杂数据结构,在互斥这个问题上,没有redis那么严重。

(2)对于纯内存操作来说,cpu并不是瓶颈,瓶颈在网络IO上。所以即使单线程,也很快。另外,如果要利用多核的优势,可以在一个机器上开多个redis实例。

<think>好的,我现在需要回答用户关于Redis是否支持乐观锁以及其实现机制的问题。首先,我需要回忆一下Redis的事务机制,因为乐观锁通常事务相关。根据用户提供的引用资料,Redis的事务使用MULTIEXEC命令,事务中的命令要么全部执行,要么不执行。这数据库中的事务类似,但可能没有ACID中的隔离性。 接下来,用户提到的引用中提到了乐观锁的实现,特别是通过WATCH命令来监视键,这应该就是Redis实现乐观锁的关键。WATCH命令在事务开始前监视一个或多个键,如果在事务执行EXEC之前这些键被其他客户端修改,事务会被取消。这类似于乐观锁的版本号机制,检测数据是否被改动过。 我需要确认WATCH命令的作用机制。当使用WATCH监视某个键后,如果在事务提交时(执行EXEC),Redis会检查被监视的键是否被修改过。如果有修改,则事务失败,否则执行事务。这符合乐观锁的“检查后提交”策略。 然后,根据引用中的PHP代码示例,可以看到使用watch('count')来监视count键,之后开启事务,进行操作,最后执行exec。如果在事务过程中其他客户端修改了count,exec会返回空,表示失败,此时需要重试。这类似于自旋锁,不断重试直到成功或者超时。 另外,引用2提到的事务执行失败后的处理,解锁并重新加锁,再次监视,这就是重试机制,说明Redis乐观锁需要开发者自己处理重试逻辑,而不是自动重试。 总结起来,Redis通过WATCH、MULTI、EXECUNWATCH命令组合实现乐观锁。WATCH用于监视关键数据,MULTI开始事务,EXEC尝试提交,如果冲突则失败,需要重试。UNWATCH可以取消监视,通常在重试前使用。 用户的问题可能还关心具体步骤示例,所以需要分点说明实现机制,并给出一个简化的例子。同时,需要指出乐观锁Redis中的应用场景,如秒杀系统中的库存扣减,避免超卖。 最后,根据用户要求生成相关问题,可能涉及性能、实现细节、与其他锁机制对比等。</think>Redis确实支持基于$WATCH$命令的乐观锁机制,其实现方式结合了事务监控与版本控制思想。以下为具体实现原理步骤: ### 一、Redis乐观锁核心机制 1. **监视机制** 使用$WATCH$命令监视指定键,建立数据版本快照。当被监视键的值发生修改时,事务自动终止执行[^3] ```shell WATCH inventory_count ``` 2. **事务执行** 通过$MULTI$开启事务队列,$EXEC$提交事务。若其他客户端在$WATCH$后修改了被监控键,当前事务将返回`(nil)`表示失败 ```shell MULTI DECR inventory_count EXEC # 返回nil表示事务失败 ``` 3. **冲突处理** 事务失败后需使用$UNWATCH$解除监控,重新执行业务流程(典型重试模式)[^2] ### 二、秒杀场景实现示例 ```python import redis r = redis.Redis() def deduct_inventory(): while True: try: r.watch('inventory') # 开始监视库存量 count = int(r.get('inventory')) if count <= 0: return False # 开启事务 pipeline = r.pipeline() pipeline.multi() pipeline.decr('inventory') # 提交事务(返回空列表表示失败) if pipeline.execute(): return True except redis.WatchError: continue # 库存被修改,重新尝试 finally: r.unwatch() ``` ▲ 此代码实现了库存扣减的原子性操作,当多个客户端同时修改库存时,仅有一个事务能成功执行 ### 三、机制特点分析 | 特性 | 说明 | |-------------|--------------------------------------------------------------------| | 非阻塞性 | 通过版本检测而非互斥锁,避免线程阻塞[^1] | | 重试成本 | 需手动实现重试逻辑,高并发场景可能产生自旋开销 | | 适用场景 | 冲突概率低、数据量小的场景(如计数器、库存管理)[^3] |
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值