本网站(662p.com)打包出售,且带程序代码数据,662p.com域名,程序内核采用TP框架开发,需要联系扣扣:2360248666 /wx:lianweikj
精品域名一口价出售:1y1m.com(350元) ,6b7b.com(400元) , 5k5j.com(380元) , yayj.com(1800元), jiongzhun.com(1000元) , niuzen.com(2800元) , zennei.com(5000元)
需要联系扣扣:2360248666 /wx:lianweikj
浅谈Redis如何应对并发访问
phpren · 206浏览 · 发布于2022-08-01 +关注

本文主要介绍了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客户端要加锁,需要使用分布式锁,而分布式锁实现复杂,增加复杂度。


    相关推荐

    使用SELECT语句检索数据

    奔跑的男人 · 806浏览 · 2019-06-03 09:33:43
    部署MySQL延迟从库的几个好处

    吴振华 · 666浏览 · 2019-05-14 21:57:51
    MongoDB凭什么跻身数据库排行前五?

    iamitnan · 723浏览 · 2019-06-18 10:04:56
    Oracle开启和关闭的几种模式

    qq2360248666 · 754浏览 · 2019-06-04 10:18:47
    加载中

    0评论

    评论
    我从小喜欢编程,一直在学习中,从未停止,未来也是如此!
    小鸟云服务器
    扫码进入手机网页