本篇内容介绍了“Redis怎么应对并发访问”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
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是一种轻量小巧的脚本语言,用标准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怎么应对并发访问”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注亿速云网站,小编将为大家输出更多高质量的实用文章!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。