Redis 的并发竞争问题

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容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
相关文章
|
2月前
|
缓存 NoSQL Redis
Redis经典问题:数据并发竞争
数据并发竞争是大流量系统(如火车票系统、微博平台)中常见的问题,可能导致用户体验下降甚至系统崩溃。本文介绍了两种解决方案:1) 加写回操作加互斥锁,查询失败快速返回默认值;2) 保持多个缓存备份,减少并发竞争概率。通过实践案例展示,成功提高了系统的稳定性和性能。
|
3月前
|
缓存 NoSQL 关系型数据库
大厂面试高频:如何解决Redis缓存雪崩、缓存穿透、缓存并发等5大难题
本文详解缓存雪崩、缓存穿透、缓存并发及缓存预热等问题,提供高可用解决方案,帮助你在大厂面试和实际工作中应对这些常见并发场景。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:如何解决Redis缓存雪崩、缓存穿透、缓存并发等5大难题
|
7月前
|
NoSQL 算法 Java
(十三)全面理解并发编程之分布式架构下Redis、ZK分布式锁的前世今生
本文探讨了从单体架构下的锁机制到分布式架构下的线程安全问题,并详细分析了分布式锁的实现原理和过程。
129 6
|
7月前
|
负载均衡 NoSQL Java
|
8月前
|
NoSQL 关系型数据库 MySQL
实时计算 Flink版产品使用问题之如何确保多并发sink同时更新Redis值时,数据能按事件时间有序地更新并且保持一致性
实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStream API、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。
|
8月前
|
NoSQL Redis
Redis系列学习文章分享---第五篇(Redis实战篇--优惠券秒杀,全局唯一id 添加优惠券 实现秒杀下单 库存超卖问题分析 乐观锁解决超卖 实现一人一单功能 集群下的线程并发安全问题)
Redis系列学习文章分享---第五篇(Redis实战篇--优惠券秒杀,全局唯一id 添加优惠券 实现秒杀下单 库存超卖问题分析 乐观锁解决超卖 实现一人一单功能 集群下的线程并发安全问题)
155 0
|
9月前
|
缓存 NoSQL Redis
Redis经典问题:数据并发竞争
在大流量系统中,数据并发竞争可能导致系统性能下降和崩溃。为解决此问题,可以采取加写回操作和互斥锁,确保数据一致性并减少写操作对缓存的影响。另外,保持缓存数据多个备份能降低并发竞争概率。通过实例展示了如何在电商网站中应用这些策略,从而提高系统稳定性和性能。关注微信公众号“软件求生”获取更多技术分享。
526 1
|
9月前
|
缓存 NoSQL Java
Java项目:支持并发的秒杀项目(基于Redis)
Java项目:支持并发的秒杀项目(基于Redis)
207 0
|
9月前
|
存储 缓存 NoSQL
《吊打面试官》系列-Redis双写一致性、并发竞争、线程模型
《吊打面试官》系列-Redis双写一致性、并发竞争、线程模型
71 0
|
9月前
|
存储 NoSQL 关系型数据库
redis与mysql的数据一致性问题(并发更新)
redis与mysql的数据一致性问题(并发更新)
79 0