浅谈Redis如何应对并发访问

 更新时间:2022年08月01日 15:20:17   作者:剑圣无痕  
本文主要介绍了Redis如何应对并发访问,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

前言

项目中经常会遇到这种场景,我们需要先将Redis数据读取到本地,然后进行修改,修改完成后在将数据写回Redis,这种读取-修改-写回操作,我们称之为RMW操作。当有多个客户端对同一份数据执行RMW操作的话,Redis如何保证RMW操作涉及的代码以原子性方式执行?

原子性操作

Redis的原子性操作是一种无锁操作,即可以保证并发控制,还能减少系统对并发性能的影响,

单命令模式

把Redis多个操作实现成一个操作,即为单命令模式。

Redis提供了INCR/DECR命令,可以对数据进行增值/减值操作,而且它们本身就是单个命令操作,Redis单线程模式,执行命令时具有互斥性。

示例说明

 public Long getIncrNumber(String key,long alive) 
    {
        RedisAtomicLong entityIdCounter = new RedisAtomicLong(key, redisTemplate.getConnectionFactory());
        Long incrNum = entityIdCounter.getAndIncrement();
        if (null == incrNum || incrNum.longValue()==0) 
        {
            entityIdCounter.expire(alive,TimeUnit.MILLISECONDS);
            incrNum = entityIdCounter.getAndIncrement();
        }
        return incrNum;
    }

说明:采用Reids的INCR命令,如果不存在的key则设置过期时间,如果key存在则进行递增操作返回。所以如果我们执行RMW操作进行相关的递增或者递减操作时,Redis提供的INCR和DECY命令可以保证并发控制。

多命令模式

当我们不是执行简单的加加减减操作,而是更加复杂的逻辑判断或者其他操作时,Redis是无法保证原子性,所以需要将多个操作写到一个Lua脚本中,Redis会把Lua脚本作为一个整体执行,在执行过程中不会被其他命令打断,从而保证了操作的原子性。

lua简介

Lua是一种轻量小巧的脚本语言,用标准C语言编写并以源代码形式开放, 其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。

示例说明

接口进行限流操作,同一用户3秒内不能重复访问,我们可以通过lua脚本来实现。

local key = KEYS[1]
local count = tonumber(ARGV[1])
local time = tonumber(ARGV[2])
local current = redis.call('get', key)
if current and tonumber(current) > count then
    return tonumber(current)
end
current = redis.call('incr', key)
if tonumber(current) == 1 then
    redis.call('expire', key, time)
end
return tonumber(current)

说明:key、count、time为三个传入参数,分别代表Redis的key、次数和过期时间。通过get获取key对应的值,获取的值为时间内访问接口的次数,如果为第一次访问则返回的为null,此时需要对当前key进行自增1操作,如果返回为数字,则需要判断返回的数字是否已经超过了cout值,如果超过说明已经超过限流了,直接返回。

建议

  • 1.编写lua脚本不要进行复杂耗时的计算逻辑,否则执行lua时间过长,会导致Redis主线程阻塞。
  • 2.lua脚本尽量简单,不要把所有的操作都放入到lua脚本中执行,这样会导致Redis执行脚本的时间增加,同时也会降低Redis的并发性能。

事务

关于事务保证原子性,采用的watch命令其原理和乐观锁的实现原理类似,详情可以参考juejin.cn/post/712582… 文章,本文就不在具体阐述。

加锁

关于Redis的分布式锁的实现,后续的章节进行详情说明。高并发环境下加锁虽然能够保证正确性,但是也会带来其他的问题:

  • 加锁操作过多会降低系统的并发访问性能
  • Redis客户端要加锁,需要使用分布式锁,而分布式锁实现复杂,增加复杂度。

总结

本文讲解了针对并发访问Redis如何保证原子性操作,针对不同的业务场景,选择合适的方案,更多相关Redis 并发访问内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:

相关文章

  • Redis实现分布式Session管理的机制详解

    Redis实现分布式Session管理的机制详解

    这篇文章主要介绍了Redis实现分布式Session管理的机制详解,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-01-01
  • Redis shake实现可视化监控的示例代码

    Redis shake实现可视化监控的示例代码

    Redis可视化监控是通过监控Redis服务器的各项指标和状态,并将其以可视化的方式展示给用户,本文给大家介绍了Redis shake实现可视化监控,并通过代码示例讲解的非常详细,需要的朋友可以参考下
    2024-03-03
  • Redis中实现查找某个值的范围

    Redis中实现查找某个值的范围

    这篇文章主要介绍了Redis中实现查找某个值的范围,本文的题引来了Redis作者Salvatore Sanfilippo(@antirez)的回答,比较经典,需要的朋友可以参考下
    2015-06-06
  • Redis的9种数据类型用法解读

    Redis的9种数据类型用法解读

    这篇文章主要介绍了Redis的9种数据类型用法及说明,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-02-02
  • Redis集群新增、删除节点以及动态增加内存的方法

    Redis集群新增、删除节点以及动态增加内存的方法

    本文主要介绍了Redis集群新增、删除节点以及动态增加内存的方法,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-09-09
  • 5分钟搭建redis集群(redis5.0.5)

    5分钟搭建redis集群(redis5.0.5)

    本文主要介绍了5分钟搭建redis集群,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-08-08
  • 详解Redis中的简单动态字符串和C字符串的区别

    详解Redis中的简单动态字符串和C字符串的区别

    简单动态字符串(SDS)和 C 字符串在实现和特性上存在一些区别,这些区别使得 SDS 更适合作为 Redis 中字符串对象的内部表示,本文给大家介绍一下Redis中的简单动态字符串和C字符串的区别,需要的朋友可以参考下
    2023-12-12
  • Redis中3种特殊的数据类型(BitMap、Geo和HyperLogLog)

    Redis中3种特殊的数据类型(BitMap、Geo和HyperLogLog)

    这篇文章主要给大家介绍了关于Redis中3种特殊的数据类型(BitMap、GEOADD和GEODIST)的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧。
    2018-03-03
  • Redis优化token校验主动失效的实现方案

    Redis优化token校验主动失效的实现方案

    在普通的token颁发和校验中 当用户发现自己账号和密码被暴露了时修改了登录密码后旧的token仍然可以通过系统校验直至token到达失效时间,所以系统需要token主动失效的一种能力,所以本文给大家介绍了Redis优化token校验主动失效的实现方案,需要的朋友可以参考下
    2024-03-03
  • redis通过6379端口无法连接服务器(redis-server.exe闪退)

    redis通过6379端口无法连接服务器(redis-server.exe闪退)

    这篇文章主要介绍了redis通过6379端口无法连接服务器(redis-server.exe闪退),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-05-05

最新评论