1.Redis计数器实现方案
1.1.INCR命令
使用Redis内置的INCR和INCRBY命令可以实现对计数器的自增和自减,是最简单和高效的方案之一。
1.2.HyperLogLog
Redis的HyperLogLog数据类型可以用于实现计数器,用于统计一个数据集合中的元素个数,计数时使用PFADD命令将元素添加到HyperLogLog中,使用PFCOUNT命令计算元素个数的近似值。
1.3.方案对比
- INCR命令实现计数器,简单,但是无法去重,例如统计每天独立IP数量。
- HyperLogLog实现计数器,支持海量数据统计,占用内存小,但是计数器是估算值,支持去重,例如统计每天独立IP数量。
2.简单计数器
> SET counter 0
OK
> INCR counter
(integer) 1
> INCR counter
(integer) 2
3.基于HyperLogLog的计数器
假设有一个在线游戏,需要统计每天登录游戏的独立用户数。
使用PFADD命令,用户登录的时候,添加用户ID即可,game:loginday1
是key
PFADD game:loginday1 user1 user2 user3 user4 user5
再添加一个
PFADD game:loginday1 user6
使用PFCOUNT统计数量
PFCOUNT game:loginday1
4.避免计数器出现负数
HyperLogLog计数器不会出现负数,DECR递减命令,可能会导致负数,避免负数的核心思路就是在递减之前做下条件检测。
Redis支持LUA脚本,下面是基于lua脚本避免负数的例子
-- 如果计数器 key 不存在,则初始化为 0
if redis.call('exists', KEYS[1]) == 0 then
redis.call('set', KEYS[1], 0)
end
-- 增加计数器值,并检查是否超过最大值
local count = redis.call('incrby', KEYS[1], ARGV[1])
if count < 0 then
redis.call('set', KEYS[1], 0)
count = 0
end
return count
这是一段lua脚本避免计数器出现负数的代码,实际业务场景,会把这段代码封装下,执行计数器请求的时候一起执行。
提示:除了基于lua脚本,也可以在业务代码检测负数。