• Geek_fb6ea6
    2020-11-04
    Redis不是单线程吗?怎么还会有并发读写的问题呢

    作者回复: 这里的并发是指有多个客户端同时访问Redis,而客户端执行的业务逻辑不只一个命令操作。假设客户端A要先从Redis读数据,然后做了修改把数据再写回Redis,此时,在读数据和写回数据的期间就可能有其他客户端的并发操作执行,所以仍然存在并发读写问题。

    共 8 条评论
    24
  • Kaito
    2020-10-26
    是否需要把读取客户端 ip 的访问次数 GET(ip),以及判断访问次数是否超过 20 的判断逻辑,也加到 Lua 脚本中? 我觉得不需要,理由主要有2个。 1、这2个逻辑都是读操作,不会对资源临界区产生修改,所以不需要做并发控制。 2、减少 lua 脚本中的命令,可以降低Redis执行脚本的时间,避免阻塞 Redis。 另外使用lua脚本时,还有一些注意点: 1、lua 脚本尽量只编写通用的逻辑代码,避免直接写死变量。变量通过外部调用方传递进来,这样 lua 脚本的可复用度更高。 2、建议先使用SCRIPT LOAD命令把 lua 脚本加载到 Redis 中,然后得到一个脚本唯一摘要值,再通过EVALSHA命令 + 脚本摘要值来执行脚本,这样可以避免每次发送脚本内容到 Redis,减少网络开销。
    共 36 条评论
    314
  • 好运来
    2020-11-01
    “对于这些操作,我们同样需要保证它们的原子性。否则,如果客户端使用多线程访问,访问次数初始值为 0,第一个线程执行了 INCR(ip) 操作后,第二个线程紧接着也执行了 INCR(ip),此时,ip 对应的访问次数就被增加到了 2,我们就无法再对这个 ip 设置过期时间了。这样就会导致,这个 ip 对应的客户端访问次数达到 20 次之后,就无法再进行访问了。即使过了 60s,也不能再继续访问,显然不符合业务要求。" 对于这段话我有疑惑,假如有两个线程A和线程B,初始ip计数是0,线程A和线程B并发执行,不管线程A和线程B谁先执行到 value = INCR(ip) ,获取到的value值总会有一个是1,而value作为线程的局部变量,也是可以继续执行下去,那不就是能够执行到 IF value == 1 THEN EXPIRE(ip,60) END 这个判断逻辑了吗,不明白为什么说不能设置先到的ip过期时间60s了?
    共 7 条评论
    19
  • dfuru
    2020-11-07
    获取访问次数和判断访问是否大于20, 若放到lua脚本中,获取到的访问次数是准确的最新值,进行判断更准确; 当放到lua脚本外,并发访问时某线程获取到的访问次数可能旧(偏小),当获取到访问次数为19时(实际可能已经达到20了),该线程仍然会对访问次数执行+1,所以应该放到lua中。
    共 3 条评论
    15
  • Mr.蜜
    2020-11-14
    是否需要把读取客户端 ip 的访问次数 GET(ip),以及判断访问次数是否超过 20 的判断逻辑,也加到 Lua 脚本中? 我觉得需要分3步来优化: 1.在执行lua之前,get(ip),进行判断,如果大于20,就直接报错了,这样也就减少了执行lua的开销; 2.在执行lua时,判断incr(ip)的返回值,这个值是加一之后的值,直接判断这个值是否大于20,返回错误。 3.如果并发量特别大的时候,可以在incr前再判断一次get(ip),减少incr的开销。
    共 1 条评论
    8
  • sky
    2020-10-29
    对于这些操作,我们同样需要保证它们的原子性。否则,如果客户端使用多线程访问,访问次数初始值为 0,第一个线程执行了 INCR(ip) 操作后,第二个线程紧接着也执行了 INCR(ip),此时,ip 对应的访问次数就被增加到了 2,我们就无法再对这个 ip 设置过期时间了。这样就会导致,这个 ip 对应的客户端访问次数达到 20 次之后,就无法再进行访问了。即使过了 60s,也不能再继续访问,显然不符合业务要求。 不太明白为何过了 60 秒,也不能继续访问呢
    共 6 条评论
    8
  • 永不止步
    2021-01-18
    除了技术之外,我觉得那段代码的判断逻辑应该属于业务范畴,最好不要放lua中,因为业务是经常变化的,lua脚本最好与具体业务无关
    共 1 条评论
    7
  • 郑印
    2021-09-08
    感觉 “Redis 在执行 Lua 脚本时,是可以保证原子性的” 这句话有误导,当lua脚本中间有命令执行出错时,以执行的命令还是生效了的,这样不能完全称之为原子性。redis只是通过lua脚本让一组命令想一个命令一样执行在加上单线程的特性避免了并发产生的问题,而不能称之为原子性。
    共 3 条评论
    5
  • huiye
    2021-02-02
    除了把多个操作在 Redis 中实现成一个操作,和使用lua脚本,使用redis的事务,把多个命令放入队列里一起执行,是不是也能保证原子性呢
    共 1 条评论
    3
  • Geek_750e24
    2020-11-28
    value = INCR(ip) //如果是第一次访问,将键值对的过期时间设置为60s后 IF value == 1 THEN EXPIRE(ip,60) END 执行 INCR命令返回value不是原子操作么?就算两个线程执行了INCR,第一个线程返回的不是1么?
    共 1 条评论
    3