redis笔记2 限流、GeoHash和Scan
限流
简单限流
简单限流的思路是,在规定的时间窗口内,给出规定的最大操作数量限制。使用zset
结构作为一个用户行为的记录。zset
的value
和score
都用来表示操作的时间戳。每次操作前,先把操作时间戳加入zset
结构,然后移除超时的操作时间戳;之后比较总的个数和最大个数的关系,用来表示是否可以操作。
import time
import redisclient = redis.StrictRedis()def is_action_allowed(usr_id, action_key, priod, max_count):key = 'hist:%s:%s' % (user_id, action_key)now_ts = int(time.time() * 1000) # 毫秒时间戳with client.pipiline() as pipe:pipe.zadd(key, now_ts, now_ts)# 移除超时时间pipe.zremrangebyscore(key, 0, now_ts - period * 1000)pipe.zcard(key) # 获取当前时间段内总的操作次数# 设置超时时间,移除冷操作节约空间pipe.expore(key, period + 1) _, _, current_count, _ = pipe.execute()return current_count <= max_count
这种做法的缺陷是,如果规定时间段内允许的操作数非常多,假设1s内可以操作10510^5105次操作,那么需要对应数量的时间戳来存储,浪费空间。
漏斗限流
介绍漏斗限流的思路。漏斗的滴水速度是匀速的,我们可以往漏斗中加水,如果加水的速度小于漏水的速度,那么这个行为是可以允许的;但是如果超过了这个速度,那么是不允许的。
给出单机漏斗限流的基本实现:
import timeclass Funnel(object):def __init__(self, capacity, leaking_rate):self.capacity = capacity # 漏斗的容量self.leaking_rate = leaking_rate # 漏水的速度self.left_quota = capacity # 初始化的水量self.leaking_ts = time.time() # 上次漏水的时间# 加水顺便检验空间,算法的核心def make_space(self):now_ts = time.time()delta_ts = now_ts - self.leaking_ts # 距离上次加水时间的间隔delta_quota = delta_ts * self.leaking_rate # 减少的水量,可以认为是腾出的空间if delta_quota < 1: # 腾出的空间太少returnself.left_quota += delta_quota # 增加剩余的空间self.leaking_ts = now_ts # 更新漏水的时间戳if self.left_quota > self.capacity: # 不能超过容量self.left_quota = self.capacitydef watering(self, quota): # 判断加入的水是否满足self.make_space()if self.left_quota >= quota: # 判断剩余的空间是否充足self.left_quota -= quotareturn Truereturn Falsefunnels = {}def is_action_allowed(user_id, action_key, capacity, leaking_rate):key = '%s:%s' % (user_id, action_key)funnel = funnels.get(key)if not funnel:funnel = Funnel(capacity, leaking_rate)funnels[key] = funnelreturn funnel.watering(1)for i in range(20):print is_action_allowed('erick', 'reply', 15, 0.5)
漏斗限流的缺陷:该方式不适用于分布式的系统。因为从funnels
这个hash
中取出结构,然后把数据放到内存中计算,最后再放回数据的过程不是原子的。这意味着我们需要加锁操作。如果加锁失败,需要重试或者放弃,复杂度高。
Redis-Cell实现漏斗限流
redis
的漏斗限流算法,而且提供了原子限流指令。只有一条指令:
cl.throttle erick:reply 15 30 60 1
意义分别是:
erick:reply
:键值15
:漏斗的容量30
:规定时间内最大的操作个数60
:规定的时间,这里是30个/60s1
:默认值是1,表示当前添加的quota
该指令返回5个值,分别是:
0
:0 表示允许,1表示拒绝15
:漏斗容量14
:剩余空间-1
:被拒绝了,需要多久之后再重试2
:多长时间后,漏斗完全空出来
GeoHash算法
该算法用于计算距离,算法的核心思想是把二维空间的距离映射到一维上,然后此时再指定元素时,就可以在一维的距离上进行比较了,减少了复杂度。注意,这里的映射是有损映射,但是损失的精度较小,对于附近的人等的应用,这些误差可以忽略。
总共有6个基本的操作,如下:
geoadd person 111 112 foo
:foo
在person
集合中的经纬度是111 & 112geodist person foo1 foo2 km
:返回foo1
和foo2
的距离geohash person foo
:获取foo
的哈希值georadiusbynumber person foo 20 km count 3 asc
:返回foo
20km内按照升序的3个人,desc
表示降序georadius 111 112 20 km withdist count 3 asc
:把名称换成了经纬度
注意,GeoHash
的底层数据结构是zset
,集群环境中,如果单个key
的数据量过多,会对数据迁移造成卡顿。同时,key
集合的大小一般也不要超过1MB。所以实际部署GeoHash
时,最好单独部署一套,不要和集群混合在一起。
Scan
keys regex
是搜索出所有满足regex
正则表达式的key
值,但是该方式一般在key
很少的时候使用,该方式复杂度是O(N)O(N)O(N),会阻塞redis。
一般对于线上服务来说,更多的是使用scan
命令,该命令的特点
- 复杂度
O(N)
,通过游标分步,不会阻塞线程。 - 提供
limit
参数,控制返回结果的最大数量 - 提供模式匹配
- 返回结果可能有重复,需要客户端去重
- 遍历过程中,如果数据有修改,则结果是不确定的
- 单次返回结果为空,不意味着遍历结束,需要看游标是否是0
比如:
scan 0 match key99* count 1000
redis采用渐进式的rehash技术,每次只是同步部分hash数据;同时,redis的遍历方式是采用比特位的高位加法。具体可以参考下面的博客。
对于hash
和zset
等结构,也有对应的hscan
和zscan
等的方式。
参考博客:
- http://tech-happen.site/32ad6396.html
大key扫描
redis中,如果有很大的hash
或者set
等的结构,那么可能会造成卡顿,可能的原因如下:
- 如果
key
的结构空间不够,则需要重新分配空间,并拷贝数据,耗费时间 - 集群之间迁移数据,速度变慢、
如果redis的内存消耗出现较大波动,或者耗时出现较大波动,说明可能出现大key,此时需要借助scan
的方式扫描并判断:
redis-cli -h 127.0.0.1 -p 6379 --bigkeys -i 0.1
redis笔记2 限流、GeoHash和Scan相关推荐
- Redis实现分布式限流(学习笔记
Redis实现分布式限流(学习笔记2022.07.09) 前言: 以下实现都是基于: spring-boot-starter-web + spring-boot-starter-data-redis ...
- Redis 如何实现限流功能?
"限流"这种事在生活中很常见,比如逢年过节时景点的限流,还有工作日的车辆单双号限流等,有人可能会问为什么要限流?我既然买了车子你还不让我上路开?还有我倒景点买了门票,景点不是能赚更 ...
- redis rua解决库存问题_库存秒杀问题-redis解决方案- 接口限流
/** * Created by PhpStorm. * redis 销量超卖秒杀解决方案 * redis 文档:http://doc.redisfans.com/ * ab -n 10000 -c ...
- Redis做接口限流
Redis 除了做缓存,还能干很多很多事情:分布式锁.限流.处理请求接口幂等性...太多太多了-,今天想和小伙伴们聊聊用 Redis 处理接口限流. 1. 准备工作 首先我们创建一个 Spring B ...
- Redis 做接口限流
Redis 除了做缓存,还能干很多很多事情:分布式锁.限流.处理请求接口幂等性...太多太多了- 今天想和小伙伴们聊聊用 Redis 处理接口限流,这也是最近的 TienChin 项目涉及到这个知识点 ...
- 基于Redis的分布式限流详解
前言 Redis除了能用作缓存外,还有很多其他用途,比如分布式锁,分布式限流,分布式唯一主键等,本文将和大家分享下基于Redis分布式限流的各种实现方案. 一.为什么需要限流 用最简单的话来说:外部请 ...
- 基于Redis实现分布式应用限流--转
原文地址:https://my.oschina.net/giegie/blog/1525931 摘要: 限流的目的是通过对并发访问/请求进行限速或者一个时间窗口内的的请求进行限速来保护系统,一旦达到限 ...
- Spring自定义注解+redis实现接口限流
在实际开发中,有时候我们需要对某些接口进行限流,防止有人恶意攻击或者是因为某些接口自身的原因,比如发短信接口,IO处理的接口. 这里我们通过自定义一个注解,并利用Spring的AOP拦截器功能来实现限 ...
- redis实现简单限流
首先我们给出限流的定义: 1. 限定某个行为在指定时间内被允许的最大次数 2. 限定某个用户的某个行为在指定时间内被允许的最大次数 其实二者差不多,前面一句是限定所有人,后面的是限定了每个用户 注意 ...
最新文章
- linux 下根据cpp文件快速书写头文件
- Codeforces Global Round 9 A-D题解
- python小课堂28_python学习28——课后练习
- 调用方法[manageapp]时发生异常_探讨通过Feign配合Hystrix进行调用时异常的处理
- C++ vector的初始化、添加、遍历、插入、删除、查找、排序、释放操作
- 如何在ASP.NET Core程序启动时运行异步任务(3)
- js如何上传大文件到服务器,js将文件上传到远程服务器
- python基础--综合练习(之王者荣耀小游戏)
- 创建与维护MySQL数据库
- 三、GDT和IDT的配置
- Oracle | 初级-第二章 Oracle安装配置
- 局域网电脑设置固定ip
- 楚留香获取服务器信息卡主,楚留香手游沧海主线任务bug原因及解决方法一览
- CityMaker研修之路 02 伟景行(CityMaker)的倾斜之路
- 纵观Tensorflow、Keras、Pytorch的发展史
- JavaWeb-13 (购物车项目2)
- 计算机3000元配置表,预算3000吃鸡电脑推荐 2018游戏主机3000元左右配置清单
- 易观 OLAP 大赛揭晓 PingCAP 斩获商业组桂冠
- 滨州智能dcs系统推荐_几种主流DCS系统对比分析
- 512_盟德插件googleplayservice