`
zengshaotao
  • 浏览: 792684 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Redis并发写入(乐观同步方法)

 
阅读更多

一,什么是乐观同步

乐观同步是在取出一个数据A的时候,会携带一个取出时的版本信息,比如:1,而如果在操作的时候,有另外一个操作B把存储在Redis中的数据修改了,那个redis中的数据版本就会加1,这个时候如果再写入A的数据,发现A携带的版本与redis储存的不一样了,这时,redis就判定本次写入失败。

二,redis的事务机制

redis提供了一个事务操作的机制MULTI 命令用于开启一个事务,它总是返回 OK 。

MULTI 执行之后, 客户端可以继续向服务器发送任意多条命令, 这些命令不会立即被执行, 而是被放到一个队列中, 当 EXEC 命令被调用时, 所有队列中的命令才会被执行。

另一方面, 通过调用 DISCARD , 客户端可以清空事务队列, 并放弃执行事务。

以下是一个事务例子, 它原子地增加了 foo 和 bar 两个键的值:

> MULTI
OK

> INCR foo
QUEUED

> INCR bar
QUEUED

> EXEC
1) (integer) 1
2) (integer) 1

EXEC 命令的回复是一个数组, 数组中的每个元素都是执行事务中的命令所产生的回复。 其中, 回复元素的先后顺序和命令发送的先后顺序一致。

当客户端处于事务状态时, 所有传入的命令都会返回一个内容为 QUEUED 的状态回复(status reply), 这些被入队的命令将在 EXEC命令被调用时执行。

三,事务可能遇到的错误

 

使用事务时可能会遇上以下两种错误:

  • 事务在执行 EXEC 之前,入队的命令可能会出错。比如说,命令可能会产生语法错误(参数数量错误,参数名错误,等等),或者其他更严重的错误,比如内存不足(如果服务器使用 maxmemory 设置了最大内存限制的话)。
  • 命令可能在 EXEC 调用之后失败。举个例子,事务中的命令可能处理了错误类型的键,比如将列表命令用在了字符串键上面,诸如此类。

对于发生在 EXEC 执行之前的错误,客户端以前的做法是检查命令入队所得的返回值:如果命令入队时返回 QUEUED ,那么入队成功;否则,就是入队失败。如果有命令在入队时失败,那么大部分客户端都会停止并取消这个事务。

四,事务的回滚

从 Redis 2.6.5 开始,服务器会对命令入队失败的情况进行记录,并在客户端调用 EXEC 命令时,拒绝执行并自动放弃这个事务。

在 Redis 2.6.5 以前, Redis 只执行事务中那些入队成功的命令,而忽略那些入队失败的命令。 而新的处理方式则使得在流水线(pipeline)中包含事务变得简单,因为发送事务和读取事务的回复都只需要和服务器进行一次通讯。(待测试

五,redis乐观同步

WATCH 命令可以为 Redis 事务提供 check-and-set (CAS)行为。

被 WATCH 的键会被监视,并会发觉这些键是否被改动过了。 如果有至少一个被监视的键在 EXEC 执行之前被修改了, 那么整个事务都会被取消, EXEC 返回空多条批量回复(null multi-bulk reply)来表示事务已经失败。

举个例子, 假设我们需要原子性地为某个值进行增 1 操作(假设 INCR 不存在)。

首先我们可能会这样做:

val = GET mykey
val = val + 1
SET mykey $val
上面的这个实现在只有一个客户端的时候可以执行得很好。 但是, 当多个客户端同时对同一个键进行这样的操作时, 就会产生竞争条件。

举个例子, 如果客户端 A 和 B 都读取了键原来的值, 比如 10 , 那么两个客户端都会将键的值设为 11 , 但正确的结果应该是 12 才对。

有了 WATCH , 我们就可以轻松地解决这类问题了:

WATCH mykey

val = GET mykey
val = val + 1

MULTI
SET mykey $val
EXEC
使用上面的代码, 如果在 WATCH 执行之后, EXEC 执行之前, 有其他客户端修改了 mykey 的值, 那么当前客户端的事务就会失败。 程序需要做的, 就是不断重试这个操作, 直到没有发生碰撞为止。

这种形式的锁被称作乐观锁, 它是一种非常强大的锁机制。 并且因为大多数情况下, 不同的客户端会访问不同的键, 碰撞的情况一般都很少, 所以通常并不需要进行重试。

了解 WATCH
WATCH 使得 EXEC 命令需要有条件地执行: 事务只能在所有被监视键都没有被修改的前提下执行, 如果这个前提不能满足的话,事务就不会被执行。

如果你使用 WATCH 监视了一个带过期时间的键, 那么即使这个键过期了, 事务仍然可以正常执行, 关于这方面的详细情况,请看这个帖子: http://code.google.com/p/redis/issues/detail?id=270
WATCH 命令可以被调用多次。 对键的监视从 WATCH 执行之后开始生效, 直到调用 EXEC 为止。

用户还可以在单个 WATCH 命令中监视任意多个键, 就像这样:

redis> WATCH key1 key2 key3
OK
当 EXEC 被调用时, 不管事务是否成功执行, 对所有键的监视都会被取消。

另外, 当客户端断开连接时, 该客户端对键的监视也会被取消。

使用无参数的 UNWATCH 命令可以手动取消对所有键的监视。 对于一些需要改动多个键的事务, 有时候程序需要同时对多个键进行加锁, 然后检查这些键的当前值是否符合程序的要求。 当值达不到要求时, 就可以使用 UNWATCH 命令来取消目前对键的监视, 中途放弃这个事务, 并等待事务的下次尝试

分享到:
评论

相关推荐

    聊聊高并发高可用那些事(Kafka、Redis、MySQL)

    以上内容涵盖了Kafka、Redis和MySQL在处理高并发和高可用性时的关键知识点,包括它们的基本原理、操作方法、优化策略和常见问题的解决方案。学习和掌握这些知识点,有助于构建稳定、高效的数据处理系统。

    Redis面试题.pdf

    - **并发控制:**通过分布式锁或乐观锁机制避免竞态条件。 #### 八、并发竞争问题解决方案 **分布式锁实现:** - 使用`SETNX`命令设置锁,保证同一时间内只有一个客户端持有锁。 **乐观锁机制:** - 结合`WATCH`...

    Redis面试题.zip

    - 主从复制可以提高读取性能,增加可用性,主节点写入,从节点同步更新。 - 可以设置多个从节点,形成复制树结构。 - 如果主节点宕机,可以从节点中提升一个为新的主节点。 6. **Redis的集群方案** - Redis ...

    高性能分布式缓存 Redis1

    - **并发问题**:多个客户端同时对同一key进行set操作可能导致并发竞争,需要采用乐观锁或分布式锁来解决。 - **数据一致性**:Redis的主从同步可能不是实时的,可能导致数据不一致。 - **缓存失效策略**:缓存穿透...

    Redis 从熟悉到精通

    - 这个机制类似于乐观锁,通常用于解决并发控制问题,如在多用户环境下对资源的竞争。 #### 四、Redis 持久化 Redis 作为一种内存数据库,需要解决数据持久化的问题,以防止数据丢失。Redis 提供了两种持久化方案...

    java+redis+秒杀项目实战.zip

    在设计秒杀表时,要考虑到高并发写入,可能采用乐观锁或悲观锁等策略,防止数据冲突。 8. **缓存更新策略**:在秒杀结束后,需要更新Redis中的库存信息,并同步到数据库。这可能涉及到“双写一致性”问题,项目可能...

    架构师系列书籍--Redis实战

    - 提供高并发写入能力。 ##### 1.1.5 memcached - **简介**:memcached是一种简单的内存对象缓存系统,用于减轻数据库负载并提高网站速度。 - **特点**: - 主要用于缓存数据。 - 简单易用,支持多种编程语言。 ...

    Java面试解析总结:Java+Redis+数据库+解决方案+分布式...docx

    - **Spring如何处理线程并发问题**:Spring提供了多种机制来处理并发问题,如使用`@Async`注解实现异步方法调用,或者利用Spring提供的并发工具类等。 #### JVM篇 - **Java类加载过程**:Java程序的执行依赖于类...

    高并发网站多级缓存设计.docx

    - 使用分布式锁或乐观锁等机制确保并发写入缓存时的数据一致性。 在设计高并发网站的多级缓存时,需要根据业务需求、数据量、系统规模以及对数据一致性的要求,综合考虑各种缓存策略和技术,以达到最佳性能和稳定...

    行业文档-设计装置-实现数据库交易流水表读写同步的方法.zip

    本文档将深入探讨如何设计装置并实现数据库交易流水表的读写同步方法。这种方法旨在提高系统的性能和稳定性,同时避免数据丢失或不一致的情况。 首先,我们需要理解交易流水表的概念。交易流水表是一种记录系统内...

    并发编程下的锁机制,乐观锁、悲观锁、共享锁、排他锁、分布式锁、锁降级原理篇

    在并发编程中,锁机制是控制多线程访问共享资源的一种重要方式,它确保了并发环境下的数据一致性。本文将详细讲解几种常见的锁机制:悲观锁、乐观锁、共享锁和排他锁,并简要介绍分布式锁以及锁降级原理。 1. **...

    金融级分布式缓存平台的一致性设计

    因此,设计良好的并发控制策略是必要的,例如使用乐观锁、CAS(Compare And Swap)或基于时间戳的版本机制。 第三,主从切换一致性涉及到主从复制过程中的数据同步。在主节点故障切换至从节点时,可能存在短暂的...

    01-JAVA岗位笔试题(A卷)附答案

    #### 十九、Redis并发竞争问题 在多线程或多进程环境中,可能会出现对Redis的并发访问问题,解决方法包括: - **使用Redis的事务**:通过MULTI/EXEC指令序列化多个命令的执行。 - **使用Lua脚本**:在Redis服务器端...

    行业文档-设计装置-一种基于分布式缓存的数据库读写方法.zip

    此外,为了应对分布式环境下的并发访问和数据一致性问题,本设计可能采用了诸如乐观锁、悲观锁或者分布式锁等机制,确保在多线程或多节点间的操作不会引发冲突。 分布式缓存的实现还需要考虑以下几个关键点: - **...

    30_分布式缓存相关面试题的回答技巧总结.zip

    - **Write-through**:写操作直接写入数据库并同步更新缓存。 - **Write-behind**(Write-back):先写缓存,定时批量写入数据库,存在数据丢失风险。 - **Cache Aside**:读取时先查缓存,不在则去数据库查询;...

    02.消息中间件面试宝典

    - 在特定场景下(如MySQL与Redis同步),可能需要保证消息顺序。 - 使用相同的消息Key计算哈希,确保消息存放在同一分区,由同一消费者处理。 7. **消息幂等性**: - 消费者消费失败时,MQ会自动重试。 - 确保...

    Java面试可能问的问题.docx

    12. **并发控制**:在订单服务中,加减库存需要考虑并发一致性,可以使用乐观锁、悲观锁、分布式锁等策略。 13. **多线程**:多线程用于提高程序的执行效率,Java提供了Thread类和Runnable接口来创建和管理线程。 ...

    网络游戏-一种游戏用户数据的数据存储方法.zip

    9. 并发控制:在高并发场景下,必须处理好多个用户同时操作同一数据的问题。这通常通过锁机制、乐观锁或悲观锁来实现。 10. 扩展性设计:为应对未来增长,游戏数据存储系统应具备良好的扩展性,能够无缝添加新的...

Global site tag (gtag.js) - Google Analytics