V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
sadfQED2
V2EX  ›  问与答

请教一个 redis 原子性问题

  •  
  •   sadfQED2 · 2021-06-07 10:51:14 +08:00 · 381 次点击
    这是一个创建于 1225 天前的主题,其中的信息可能已经有所发展或是发生改变。

    问题背景:线上有一个分布式计数器(统计每 5 秒内的执行数量),计数器基于 redis Incr 实现,实现方案: 执行 Incr,如果计数小于等于 10,给 key 设置 5 秒过期时间。

    目前线上业务服务器大约 100 台实例,redis 大约 30 台(每台实例都可以写入,猜测是 redis cluster 集群方案,并不确定),这个函数调用 QPS 约 1000+

    目前问题:redis key 偶然出现永久不过期(最近 2 个月,出现了 2 次),导致计数器不能清零

    具体代码:

    /**
    分布式计数器,每次调用数量加一,返回计数器增加后的值
     */
    func incrCount() int {
    	redisKey:="xxxxxx"
    	count,err:=redis.Incr(redisKey)
    	if err!=nil {
    		Logger.Warn("Redis Incr Error! Error Info : %+v",err) // 这里没有日志输出
    		return 0
    	}
    
    	// 设置 10 次 expire,防止失败
    	if count <= 10 {
    		res,err:= redis.Expire(redisKey,5) // 给 key 设置 5s 过期
    		if err!=nil || res != 1 {
    			Logger.Warn("Redis Set Expire Error! Error Info:%+v",err)  // 这里没有日志输出
    		}
    	}
    	return count
    }
    

    查过日志,代码里面 2 处 Warn 日志都未打印,代码无其他报错,业务代码容器无异常重启,宿主机负载无异常,网络无异常,redis 无异常。

    原因猜测:

    1 、redis 单机能保证 incr 操作原子性,但是集群情况不能保证原子性

    2 、集群内部互相同步的时候丢了过期时间

    3 、Incr 和 Expire 分 2 次调用,Incr 成功,但是 Expire 失败

    目前尚无回复
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1036 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 19:18 · PVG 03:18 · LAX 12:18 · JFK 15:18
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.