系统优化之限流

日常笔记

我们需要控制用户使用系统的次数,以避免超支,比如给不同等级的用户分配不同的调用次数,防止用户过度使用系统造成破产(例如给普通用户提供 50 次调用次数,会员用户提供 100 次)。但限制用户调用次数仍存在一定风险,用户仍有可能通过疯狂调用来刷量,从而导致系统成本过度消耗。 假设系统就一台服务器,能同时处理的用户对话数量是有限的,比如系统最多只能支持 10 个用户同时对话,如果某个用户一秒内使用 10 个账号登录,那么其他用户就无法使用系统。就像去自助餐厅吃饭,如果有人一股脑地把所有美食都拿光了,其他人就无法享用了。比如双 11 这种大促期间,阿里巴巴就要去限制,不能说所有的用户想抢购都能成功,在前端随机放行一部分用户,而对于其他用户则进行限制,以确保系统不会被恶意用户占满。现在要做一个解决方案,就是限流,比如说限制单个用户在每秒只能使用一次,那这里我们怎么去思考这个限流的阈值是多少?多少合适呢?

**问题:**使用系统是需要消耗成本的,用户有可能疯狂刷量,让你破产。 解决方案:

  1. 控制成本 => 限制用户调用总次数
  2. 用户在短时间内疯狂使用,导致服务器资源被占满,其他用户无法使用 => 限流

思考: 限流阈值多大合适?参考正常用户的使用,比如限制单个用户在每秒只能使用 1 次。

# 限流的算法

建议 阅读文章 (opens new window)

食堂排队举例:

  1. 规定窗口限流 你去食堂买汉堡,食堂每一小时只允许 10 个用户买汉堡,汉堡一小时只能做 10 个,第 59 分钟来了 10 个人,第 60 分钟又来 10 个人,汉堡就不够了。
  2. 滑动窗口限流 每 10 分钟食堂做一个汉堡,这样的话,假如前一个小时汉堡已经被抢光了,然后 1 小时 10 分钟来的一个新用户,他又能抢到 1 小时 10 分钟得到的那个汉堡。
  3. 漏桶限流 大家排好队,一个一个去拿汉堡,前面一个人拿完,后面一个人才能拿。
  4. 令牌桶限流 食堂事先做好 10 个汉堡,假如现在开抢了,前 10 个人能够同时拿到汉堡,不用排队,但剩下的 10 个人就只能等下一批汉堡做好才能拿。

# 限流粒度

  1. 针对某个方法限流,即单位时间内最多允许同时 XX 个操作使用这个方法
  2. 针对某个用户限流,比如单个用户单位时间内最多执行 XX 次操作
  3. 针对某个用户 x 方法限流,比如单个用户单位时间内最多执行 XX 次这个方法

# 限流实现构思

# 1)本地限流(单机限流)

每个服务器单独限流,一般适用于单体项目,就是你的**项目只有一个服务器 **。 🪔 举个例子,假设你的系统有三台服务器,每台服务器限制用户每秒只能请求一次。你可以为每台服务器单独设置限流策略,这样每个服务器都能够独立地控制用户的请求频率。但是这种限流方式并不是很可靠,因为你并不知道用户的请求会落在哪台服务器上,它的分布是有一定的偶然性的。即使你采用负载均衡技术,让用户请求轮流发送到每台服务器,仍然存在一定的风险。 在 Java 中,有很多第三方库可以用来实现单机限流:Guava RateLimiter:这是谷歌 Guava 库提供的限流工具,可以对单位时间内的请求数量进行限制。

# 2)分布式限流(多机限流)

如果项目有多个服务器,比如微服务,那么建议使用分布式限流。

  1. 把用户的使用频率等数据放到一个集中的存储进行统计; 比如 Redis,这样无论用户的请求落到了哪台服务器,都以集中存储中的数据为准。 (Redisson -- 是一个操作 Redis 的工具库 , 伙伴匹配系统讲过)
  2. 在网关集中进行限流和统计(比如 Sentinel、Spring Cloud Gateway)

# Redisson 限流实现

Redisson 内置了一个限流工具类,可以帮助你利用 Redis 来存储、来统计。 根据官方文档提示,先引入依赖。

粘贴至pom.xml。

创建 RedissonConfig 配置类,用于初始化 RedissonClient 对象单例; 在config目录下新建RedissonConfig.java。

编写配置。 去application.yml取消 redis 配置注释。

最近修改于: 2024/8/20 00:27:48
和宇宙温柔的关联
房东的猫