Redis 的并发竞争问题

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介: Redis 的并发竞争问题

Redis 的并发竞争问题,主要是发生在并发写竞争。

考虑到 redis 没有像 db 中的 sql 语句,update val = val + 10 where ...,无法使用这种方式进行对数据的更新。

假如有某个 key = "price",  value 值为 10,现在想把 value 值进行 + 10 操作。正常逻辑下,就是先把数据 key 为 price 的值读回来,加上 10,再把值给设置回去。如果只有一个连接的情况下,这种方式没有问题,可以工作得很好,但如果有两个连接时,两个连接同时想对还 price 进行 + 10 操作,就可能会出现问题了。

例如:两个连接同时对 price 进行写操作,同时加 10,最终结果我们知道,应该为 30 才是正确。

考虑到一种情况:

T1 时刻,连接 1 将 price 读出,目标设置的数据为 10+10 = 20。

T2 时刻,连接 2 也将数据读出,也是为 10,目标设置为 20。

T3 时刻,连接 1 将 price 设置为 20。

T4 时刻,连接 2 也将 price 设置为 20,则最终结果是一个错误值 20。

如何解决?

方案一:可以使用独占锁的方式,类似操作系统的 mutex 机制。(网上有例子,http://blog.csdn.net/black_ox/article/details/48972085 不过实现相对复杂,成本较高)

方案二:使用乐观锁的方式进行解决(成本较低,非阻塞,性能较高)

如何用乐观锁方式进行解决?

本质上是假设不会进行冲突,使用 redis 的命令 watch 进行构造条件。伪代码如下:

watch price

get price $price

$price = $price + 10

multi

set price $price

exec

解释一下:

watch 这里表示监控该 key 值,后面的事务是有条件的执行,如果从 watch 的 exec 语句执行时,watch 的 key 对应的 value 值被修改了,则事务不会执行。

同样考虑刚刚的场景,

T1 时刻,连接 1 对 price 进行 watch,读出 price 值为 10,目标计算为 20;

T2 时刻,连接 2 对 price 进行 watch,读出 price 值为 10,目标计算为 20;

T3 时刻,连接 2 将目标值为 20 写到 redis 中,执行事务,事务返回成功。

T4 时刻,连接 1 也对 price 进行写操作,执行事务时,由于之前已经 watch 了 price,price 在 T1 至 T4 之间已经被修改过了,所以事务执行失败。

综上,该乐观锁机制可以简单明了的解决了写冲突的问题。

又问:如果多个写操作同时过来,100 个写操作同时 watch,则最终只会有一个成功,99 个执行失败,何解?

如果同时进行有多个请求进行写操作,例如同一时刻有 100 个请求过来,那么只会有一个最终成功,其余 99 个全部会失败,效率不高。

而且从业务层面,有些是不可接受的场景。例如:大家同时去抢一个红包,如果背后也是用乐观锁的机制去处理,那每个请求后都只有一个人成功打开红包,这对业务是不可忍受的。

在这种情况下,如果想让总体效率最大化,

方案三:可以采用排队的机制进行

将所有需要对同一个 key 的请求进行入队操作,然后用一个消费者线程从队头依次读出请求,并对相应的 key 进行操作。

这样对于同一个 key 的所有请求就都是顺序访问,正常逻辑下则不会有写失败的情况下产生 。从而最大化写逻辑的总体效率。

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
27天前
|
缓存 NoSQL Java
Java项目:支持并发的秒杀项目(基于Redis)
Java项目:支持并发的秒杀项目(基于Redis)
26 0
|
3月前
|
存储 缓存 NoSQL
《吊打面试官》系列-Redis双写一致性、并发竞争、线程模型
《吊打面试官》系列-Redis双写一致性、并发竞争、线程模型
39 0
|
3月前
|
存储 NoSQL 关系型数据库
redis与mysql的数据一致性问题(并发更新)
redis与mysql的数据一致性问题(并发更新)
27 0
|
3月前
|
NoSQL Java Redis
Redis如何处理并发访问和竞态条件?
Redis如何处理并发访问和竞态条件?
31 0
|
4月前
|
消息中间件 算法 NoSQL
45k以上突击面试必备,redis+mysql+并发+spring+算法+导图等
今天小编给大家带来的一篇关于Java面试相关的电子文档资源,介绍了关于Java、面试题方面的内容,本书是由Java官网出版,格式为DOC,资源大小62.5 MB,目前豆瓣、亚马逊、当当、京东等电子书综合评分为:8.7。
|
11月前
|
缓存 NoSQL 关系型数据库
【JavaP6大纲】Redis篇:Redis 的并发竞争问题是什么?如何解决这个问题?
【JavaP6大纲】Redis篇:Redis 的并发竞争问题是什么?如何解决这个问题?
|
缓存 NoSQL 数据库
缓存—Redis穿透、并发、雪崩
系统收到用户频繁查询请求时,先从缓存中查找数据,如果缓存中有数据,直接从缓存中读取数据,返回给请求方;如果缓存中没有数据,则从数据库中读取数据,然后再更新到缓存中,这样下次再次获取时从缓存中获取。
84 0
|
缓存 NoSQL 关系型数据库
Redis 单线程 为何却需要事务处理并发问题
Redis 单线程 为何却需要事务处理并发问题
423 0
|
NoSQL Java Linux
Redis(二十二)-秒杀案例的基本实现以及用ab工具模拟并发
上一篇文章我们介绍了悲观锁和乐观锁,Redis(二十一)-Redis的事务冲突(悲观锁和乐观锁)。这篇文章我们接着来学习Redis,本文主要介绍如何通过Redis来实现秒杀,以及如何通过ab工具来模拟并发。
138 0
Redis(二十二)-秒杀案例的基本实现以及用ab工具模拟并发
|
缓存 NoSQL 关系型数据库
【Redis并发竞争】
【Redis并发竞争】
【Redis并发竞争】

热门文章

最新文章