乐趣区

关于java:项目如何实现限流

我是 3y,一年 CRUD 教训用十年的 markdown 程序员👨🏻‍💻长年被誉为职业八股文选手

明天持续来更新 austin 我的项目的内容,次要讲讲 限流 这块

01、为什么 AUSTIN 我的项目须要限流

家喻户晓,服务器能解决的申请数是无限的,如果申请量特地大,咱们就可能须要做限流。

限流解决的姿态:要么就让申请期待,要么就把申请给扔了

从零碎架构来看,咱们的 对立解决入口 austin-api接入层上,austin-api接入层做完简略的参数校验以及参数拼接后,就将申请转发到 音讯队列 上了

按失常来说,因为接了音讯队列且接入层没有什么耗时的操作,那 对外的接口 压力不大的。

没错的,austin 要接入限流也并不是在 austin-api 接入层上做,是在 austin-handler 音讯解决下发层。austin-handler音讯解决下发层咱们是用线程池去 隔离不同的音讯渠道不同的音讯类型

在零碎 自身上 其实没有性能相干的问题,但咱们 下发的渠道 可能就须要咱们去 管制调用的速率

腾讯云短信默认限度 3000 次 / 秒 调用下发接口

钉钉渠道对利用音讯和群机器人音讯都有接口调用的限度

….

在保障下发速度的前提下,为了让业务方所下发的音讯其用户能失常接管到和上游渠道的稳定性,咱们须要给 某些渠道进行限流

于是在这个背景下,我目前定义了两种限流策略:

1、依照 申请数 限流

2、依照 下发用户数 限流

02、如何实现限流?

想要实现限流,摆在咱们背后有两个抉择:

1、单机限流

2、分布式限流

咋一看,线上不可能只部署一台机器去发送整个公司的音讯推送的,咱们的零碎利用在线上环境相对是集群部署的,那必定就须要上 分布式限流 了,对吧?

但实际上 分布式限流 实现并不简略,目前分布式限流的计划个别借助两个中间件

1、Redis

2、Sentinel

咱们可能会用 Redis 的setnx/incrby+expire 命令(从而实现计数器、令牌桶限流)/zset 数据结构(从而实现滑动窗口限流)

Redis 实现的限流想要比拟精确,无论是哪种形式,都要依附 lua 脚本

而 Sentinel 反对单机限流和分布式限流,Sentinel 分布式限流须要 部署 Token 服务器

对于分布式限流而言,不论用哪一种计划,应用的老本和技术挑战都是比拟大的。

如果用单机限流的话,那就简略得多了,省事间接用 Guava 包下的 RateLimiter 就完了。毛病就在于:它只能管制单机的限流,如果产生了服务器扩容和缩容,它是感知不到的

有的人就给出了计划:那我用 Zookeeper 监听服务器的数量不就好了吗 。实践上的确是这样的: 每台机器限流值 = 限流总值 / 服务器数量

不过这又要去依赖 Zookeeper,Zookeeper 集群自身也有一堆状态相干的问题。

我是怎么实现的?单机限流一把梭

03、代码设计

从下面的形容能够看到,austin 的限流我是要做在具体渠道上的,依据现有的代码设计我要的就是在各个的 Handler 上写下限流的代码。

我自身就设计了 BaseHandler 抽象类作为模板办法设计模式,此次限流的设计我的是:

1、将 flowControl 定义为 abstract 形象办法,子类渠道去实现限流的代码

2、子类在初始化的时候定义限流参数,BaseHandler 父类依据限流参数对立实现限流的逻辑

我抉择了第二种形式,次要是我认为对于各个渠道而言,只是限流值是不同的,限流的逻辑应该都是一样的,没必要在每个子类上实现相似的逻辑。

而限流的逻辑就比较简单了,次要就应用 RateLimit 提供的易用 API 实现

没错,限流值的大小我是配置在 apollo 分布式配置核心的。假如当前真的要扩缩容了,那到时候提前把分布式配置核心的值给改掉,也能解决一部分的问题。

04、总结

扯了半天,原来就用了 Guava 包的 RateLimit 实现了单机限流,就这么简略,只是把限流值配置在分布式配置核心上而已。

很多时候,设计简略的代码可能实现并不完满,并不智能,并不优雅,但它付出的代价往往是最小的。

虽说如此,如果大家想要理解 Redis+lua 实现的同学能够 fetch 下 austin 最新的代码,就我写文章这段时间里,曾经有老哥提了 pull requestRedis+lua实现了 滑动窗口 去重的性能了,实质上是一样的。我曾经 merge 到 master 分支了。

austin 音讯推送平台 我的项目源码Gitee 链接:gitee.com/austin

austin 音讯推送平台 我的项目源码GitHub 链接:github.com/austin

退出移动版