主要使用reids的sorted set,主要命令:
zremrangebyscore:
语法:zremrangebyrank key start stop
解释:移除有续集中指定排名范围【start stop】的元素,返回移除元素个数
zincrby
语法:zincrby key increment member
解释:有续集key的member增加增量increment,返回增加后的score
zrevrank
语法:zrevrank key member
解释:根据score从高到低排序,返回member在有序集key中的index
思路:
1、每个IP或者接入应用有一个sorted set,每天一个
2、每秒一个key,一个请求增加zincrby +1,对应member名称为到秒的key比如: 2017121413131313
3、zrevrank对队列排序,返回最高的N个数值,如果不满足数量要求,不进行下面4操作
4、根据下标,删除sorted set其他的数值
存在问题: 会把当前插入的这个秒的给删除,改进建议
a)每秒单独建一个key(String的数据结构即可),设置生效时间5秒,入sorted set队列只是当前时间5秒前的数据,已经完成统计
b)针对队列中的数据排序处理不会有更新的操作,非常稳定,最多是最近这几秒的峰值统计不出来
c)要考虑排序集合排序的消耗,其中不保留很多的数据
最终伪代码如下:
1 HINCRBY Hash队列key 当前时间到秒 1
2 HGET 从Hash队列key获得小于当前时间N秒的数据
3 if 存在
4 ZADD 放到sorted set
5 ZREVRANK sorted set排序
6 ZREMRANGEBYSCORE 对sorted set 进行截断((按照排序,保留最大的),只保留最新的M条数据
7 end if
进一步修订:如果多个人获得一个秒的key,可能会会导致zset中同一秒有多个值插入,解决方法:
方法1: 使用redis的锁, 使用setnx,参考: https://www.cnblogs.com/liuyang0/p/6744076.html
方法2: 步骤2更改为一个lua脚本,获得数据的时候直接将对应的key删除,保证事务性
参考: