我是靠谱客的博主 优秀棒球,这篇文章主要介绍redis之如何应对并发访问问题,现在分享给大家,希望可以做个参考。

写在前面

在这里插入图片描述
本文一起看下Redis的并发访问控制。

1:单线程的Redis为什么会有并发问题

我们知道,Redis是单线程的,为什么还是会有并发问题呢?没错,如果是单命令操作的话肯定没有并发问题,但考虑事务的场景,比如库存量,我们会按照如下的步骤进行修改:

复制代码
1
2
3
4
1:读取库存量 2:减少库存量 3:写回库存量

我们把这个流程叫做读取-修改-写回,Read-Modify-Write,简称RMW操作。以上的3个步骤,对应到Redis其实是3个命令,当存在并发时,就可能导致库存量错误了,如下图,库存量最终应该是8,但由于并发导致库存量最终是9:

在这里插入图片描述

2:如何解决并发问题

解决并发问题的核心点就是,让操作以原子性的方式执行,首先单命令Redis是天然支持的,另外还有就是lua脚本,对于lua脚本Redis会以原子性的方式执行,分别来看下。

2.1:单命令

对于RMW操作,正常伪代码可能如下:

在这里插入图片描述

这类代码,也有专门的名称,叫做临界代码块,即同时只能被一个线程执行的代码块,因为这类问题比较常见,所以Redis提供了incr和desc单命令来代替以上代码,如下:

复制代码
1
2
3
4
5
6
7
8
9
127.0.0.1:6379> set age 99 OK 127.0.0.1:6379> incr age (integer) 100 127.0.0.1:6379> decr age (integer) 99 127.0.0.1:6379> decr age (integer) 98

但是对于具有逻辑判断的场景,就无法简单的使用一个命令来完成了,此时我们就需要使用lua脚本。

2.2:lua脚本

考虑限流场景,比如点赞,每小时来自同一个IP的点赞数不能超过100个,此时代码可能如下:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
if (containsKey(ip)) { int 点赞数 = get(ip); if (赞点数 > 100) { sout("点赞数超过100"); } else { set(ip, 点赞数+1); } } else { // 点赞数设置为1,并设置过期时间为3600秒 set(ip, 1, 3600); }

此时如果有来自同一IP的大量并发的话,最终的点赞数肯定会大于100,这不是我们想要的结果,此时,我们就可以将这块代码定义在lua脚本中,如rateLimitLua.script,可能如下:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
IF containsKey(ip)) THEN 点赞数 = get(ip); IF (赞点数 > 100) THEN sout("点赞数超过100"); ELSE set(ip, 点赞数+1); END ELSE // 点赞数设置为1,并设置过期时间为3600秒 set(ip, 1, 3600); END

然后就可以通过eval来执行了redis.cli --eval rateLimitLua.script keys,args,并且以原子的方式执行。

写在后面

参考文章列表:

Redis 单线程 为何却需要事务处理并发问题 。

Redis事务、MULTI 命令和EXEC 命令 。

最后

以上就是优秀棒球最近收集整理的关于redis之如何应对并发访问问题的全部内容,更多相关redis之如何应对并发访问问题内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(75)

评论列表共有 0 条评论

立即
投稿
返回
顶部