请教一个 redis 原子性问题

2021-06-07 10:51:14 +08:00
 sadfQED2

问题背景:线上有一个分布式计数器(统计每 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 失败

381 次点击
所在节点    问与答
0 条回复

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/781820

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX