背景
刚开始工作时的业务场景:授权某教育系统五千台设备(允许同时在线连接的数量),可以这样理解,
当五千台中的五百台关闭后,可以允许其他的不超过五百台连接服务,因此需要定期检查
电脑与服务的连接情况,同时针对连接授权的允许使用,针对断开的,从授权中剔除,允许
新的电脑连接进来。
使用redis的键过期策略
为了检测电脑连接情况,需要高频的检测心跳,设计有客户端即电脑
每隔2秒向服务端发起请求,服务端设置过期时间为4秒,使用电脑唯一
识别的uuid作为key,由于后续需要获取这个uuid统计电脑数量与授权
用,而uuid是无规则的,针对key进行了优化:
使用vm_uuid:real_uuid作为key,这样正则匹配以vm_uuid开头的keys,
使用keys vm_uuid:* 匹配,然后服务端针对这些uuid依次授权并统计数量,
这样设计并提交部署了。
刚开始时,生成环境keys的数量并不多,所以这样用了,没有发生大的问
题,但是随着业务增多,其他key的数量不断增加,这样做问题很大的,因为keys 命令
阻塞的,而redis是单线程,执行这个命令会阻塞生产上其他的命令的,并且
其时间复杂度为O(N),会一直匹配查找完所有的key才结束,比较耗时,后果严重。
那该怎么办了?
注:keys的介绍,官网地址https://redis.io/commands/keys,官网推荐的解决办法是
使用scan与sets
改进方法一:scan
使用SCAN cursor [MATCH pattern] [COUNT count]命令以迭代的方
式进行key遍历(限制单次查询的key数量)
这个 count 不是限定返回结果的数量,而是限定服务器单次遍历的字典槽位数量(约等于)。
缺点:依然要不停迭代查询到遍历所有的key或者满足的key数量等于500,最后放弃
这一方案,还有没有其他的缺点呢?
改进方法二:
维护一个集合,sadd vm_uuid uuid1,uuid2,
通过 smembers 获取所有的uuid,然后遍历,
若vm_uuid:uuid1存在,则授权并统计,若不存在
则srem vm_uuid uuid1 然后跳过检验下一个
思考:
为什么keys 命令的是阻塞的?redis的单线程epoll
为啥没起作用呢?