限流

简单限流

简单限流的思路是,在规定的时间窗口内,给出规定的最大操作数量限制。使用zset结构作为一个用户行为的记录。zsetvaluescore都用来表示操作的时间戳。每次操作前,先把操作时间戳加入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个/60s
  • 1:默认值是1,表示当前添加的quota

该指令返回5个值,分别是:

  • 0:0 表示允许,1表示拒绝
  • 15:漏斗容量
  • 14:剩余空间
  • -1:被拒绝了,需要多久之后再重试
  • 2:多长时间后,漏斗完全空出来

GeoHash算法

该算法用于计算距离,算法的核心思想是把二维空间的距离映射到一维上,然后此时再指定元素时,就可以在一维的距离上进行比较了,减少了复杂度。注意,这里的映射是有损映射,但是损失的精度较小,对于附近的人等的应用,这些误差可以忽略。

总共有6个基本的操作,如下:

  • geoadd person 111 112 foofooperson集合中的经纬度是111 & 112
  • geodist person foo1 foo2 km:返回foo1foo2的距离
  • geohash person foo:获取foo的哈希值
  • georadiusbynumber person foo 20 km count 3 asc:返回foo20km内按照升序的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的遍历方式是采用比特位的高位加法。具体可以参考下面的博客。

对于hashzset等结构,也有对应的hscanzscan等的方式。

参考博客:

  • 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相关推荐

  1. Redis实现分布式限流(学习笔记

    Redis实现分布式限流(学习笔记2022.07.09) 前言: 以下实现都是基于: spring-boot-starter-web + spring-boot-starter-data-redis ...

  2. Redis 如何实现限流功能?

    "限流"这种事在生活中很常见,比如逢年过节时景点的限流,还有工作日的车辆单双号限流等,有人可能会问为什么要限流?我既然买了车子你还不让我上路开?还有我倒景点买了门票,景点不是能赚更 ...

  3. redis rua解决库存问题_库存秒杀问题-redis解决方案- 接口限流

    /** * Created by PhpStorm. * redis 销量超卖秒杀解决方案 * redis 文档:http://doc.redisfans.com/ * ab -n 10000 -c ...

  4. Redis做接口限流

    Redis 除了做缓存,还能干很多很多事情:分布式锁.限流.处理请求接口幂等性...太多太多了-,今天想和小伙伴们聊聊用 Redis 处理接口限流. 1. 准备工作 首先我们创建一个 Spring B ...

  5. Redis 做接口限流

    Redis 除了做缓存,还能干很多很多事情:分布式锁.限流.处理请求接口幂等性...太多太多了- 今天想和小伙伴们聊聊用 Redis 处理接口限流,这也是最近的 TienChin 项目涉及到这个知识点 ...

  6. 基于Redis的分布式限流详解

    前言 Redis除了能用作缓存外,还有很多其他用途,比如分布式锁,分布式限流,分布式唯一主键等,本文将和大家分享下基于Redis分布式限流的各种实现方案. 一.为什么需要限流 用最简单的话来说:外部请 ...

  7. 基于Redis实现分布式应用限流--转

    原文地址:https://my.oschina.net/giegie/blog/1525931 摘要: 限流的目的是通过对并发访问/请求进行限速或者一个时间窗口内的的请求进行限速来保护系统,一旦达到限 ...

  8. Spring自定义注解+redis实现接口限流

    在实际开发中,有时候我们需要对某些接口进行限流,防止有人恶意攻击或者是因为某些接口自身的原因,比如发短信接口,IO处理的接口. 这里我们通过自定义一个注解,并利用Spring的AOP拦截器功能来实现限 ...

  9. redis实现简单限流

    首先我们给出限流的定义: 1. 限定某个行为在指定时间内被允许的最大次数 2. 限定某个用户的某个行为在指定时间内被允许的最大次数 其实二者差不多,前面一句是限定所有人,后面的是限定了每个用户 注意 ...

最新文章

  1. linux 下根据cpp文件快速书写头文件
  2. Codeforces Global Round 9 A-D题解
  3. python小课堂28_python学习28——课后练习
  4. 调用方法[manageapp]时发生异常_探讨通过Feign配合Hystrix进行调用时异常的处理
  5. C++ vector的初始化、添加、遍历、插入、删除、查找、排序、释放操作
  6. 如何在ASP.NET Core程序启动时运行异步任务(3)
  7. js如何上传大文件到服务器,js将文件上传到远程服务器
  8. python基础--综合练习(之王者荣耀小游戏)
  9. 创建与维护MySQL数据库
  10. 三、GDT和IDT的配置
  11. Oracle | 初级-第二章 Oracle安装配置
  12. 局域网电脑设置固定ip
  13. 楚留香获取服务器信息卡主,楚留香手游沧海主线任务bug原因及解决方法一览
  14. CityMaker研修之路 02 伟景行(CityMaker)的倾斜之路
  15. 纵观Tensorflow、Keras、Pytorch的发展史
  16. JavaWeb-13 (购物车项目2)
  17. 计算机3000元配置表,预算3000吃鸡电脑推荐 2018游戏主机3000元左右配置清单
  18. 易观 OLAP 大赛揭晓 PingCAP 斩获商业组桂冠
  19. 滨州智能dcs系统推荐_几种主流DCS系统对比分析
  20. 512_盟德插件googleplayservice

热门文章

  1. 2015年C语言组混搭 C/C++
  2. python网络爬虫学习笔记(九):Beautiful Soup的使用
  3. 自动驾驶——传感器的配置参数
  4. 远程桌面——TeamViewer中“显示黑屏”的功能框无法使用
  5. ODrive踩坑(三)AS5047P磁编码器的ABI接口
  6. 【Qt教程】1.2 - Qt5 新建工程
  7. ROS学习笔记十一:ROS中数据的记录与重放
  8. 【Java】equals源码分析
  9. 同行压力(兼谈敏捷团队,绩效管理,自组织团队)
  10. CSS学习笔记----选择器与字体(字系)