1月30日作业
- 跑通ratelimiter插件
- 能够对流量进行限制,控制
- 总结
Demo
- 首先启动项目soul-admin以及soul-bootstrap,以
soul-examples
中的soul-example-http
为例,注册到soul网关上。同时在soul-admin插件管理中心开启rate_limiter
插件。由于开启限流插件需要开启redis,那么就需要现在本地开启redis服务。本次示例的redis是本地的redis单例。因此需要在rate_limiter中选择standalone
mode并且配置相应的redis节点信息。
启动服务顺序: soul-admin-->soul-bootstrap-->soul-examples-http-->redis-cluster(本地docker启动)
- 正确配置rate_limiter插件.
- 配置selector
- 自定义相关规则
这里为了接下来更容易演示,将capacity设置为2,rate设置为1。
- 测试限流策略是否生效
- 使用
Postman
进行测试, 对http://localhost:9195/http/order/findById?id=1
进行测试转发
可以看到soul网关控制台打出以下日志:
2021-01-30 13:45:32.865 INFO 29956 --- [-work-threads-1] o.d.soul.plugin.base.AbstractSoulPlugin : rate_limiter selector success match , selector name :/rate_limiter
2021-01-30 13:45:32.866 INFO 29956 --- [-work-threads-1] o.d.soul.plugin.base.AbstractSoulPlugin : rate_limiter rule success match , rule name :/rate_limiter_test
2021-01-30 13:45:32.891 INFO 29956 --- [oEventLoop-18-1] o.d.s.p.r.executor.RedisRateLimiter : RateLimiter response:Response{allowed=true, tokensRemaining=1}
2021-01-30 13:45:32.892 INFO 29956 --- [oEventLoop-18-1] o.d.soul.plugin.base.AbstractSoulPlugin : divide selector success match , selector name :/http
2021-01-30 13:45:32.897 INFO 29956 --- [oEventLoop-18-1] o.d.soul.plugin.base.AbstractSoulPlugin : divide rule success match , rule name :/http/order/findById
2021-01-30 13:45:32.898 INFO 29956 --- [oEventLoop-18-1] o.d.s.plugin.httpclient.WebClientPlugin : The request urlPath is http://172.19.0.1:8188/order/findById?id=1, retryTimes is 0
说明rate_limiter
插件匹配成功。
- 触发限流。我们可以选择工具压测或者我们可以手动触发限流器限流。这里为了更好地演示,使用手动触发。
并且在soul网关控制台看到以下日志输出:
2021-01-30 13:39:47.633 INFO 29956 --- [work-threads-22] o.d.soul.plugin.base.AbstractSoulPlugin : rate_limiter selector success match , selector name :/rate_limiter
2021-01-30 13:39:47.633 INFO 29956 --- [work-threads-22] o.d.soul.plugin.base.AbstractSoulPlugin : rate_limiter rule success match , rule name :/rate_limiter_test
2021-01-30 13:39:47.642 INFO 29956 --- [oEventLoop-18-1] o.d.s.p.r.executor.RedisRateLimiter : RateLimiter response:Response{allowed=false, tokensRemaining=0}
说明限流器已经生效, rate_limiter
插件已经跑通。
rate-limiter插件底层原理初探
rate-limiter插件和其他插件相同,都会执行 AbstractSoulPlugin 类的 execute() 方法,然后在RateLimiterPlugin
中覆写doExecute
方法,核心代码如下:
从代码中可以看到如果redisRateLimiter
判断可以执行,则该插件链可以继续执行,如果不可以,那么就返回429
状态码表明已经发送太多请求,从而起到限流效果。
因此redisRateLimiter
是整个限流处理中的核心类,我们着重看一下核心处理方法isAllowed
关键代码
Flux<List<Long>> resultFlux = Singleton.INST.get(ReactiveRedisTemplate.class).execute(this.script, keys, scriptArgs);
说明redis执行lua脚本,并根据resultFlux
来判断该插件是否执行还是中断并限流。lua脚本在路径META-INF/scripts/request_rate_limiter.lua
可找到
local rate = tonumber(ARGV[1])
local capacity = tonumber(ARGV[2])
lua脚本中的rate和capacity分别对应我们在soul-admin
中设置的值。rate是redis指令牌桶的填充速率,capacity对应令牌桶可以保存的令牌数。
限流核心流程大概就是这样。那么rate-limiter-plugin
又是如何和soul-admin数据同步并连接redis呢?
我们注意到在RateLimiterPluginDataHandler
中会通过soul-admin同步来的pluginData的json字符串来parse生成RateLimiterConfig
对象,里面包含了我们在soul-admin中配置的所有信息,包括master, mode, url, password
等信息。然后通过Lettuce
客户端来连接redis
。核心代码如下
至此,rate-limiter插件从上游到下游的路径已经基本打通。
总结
RateLimiterPlugin
核心是ratelimiter通过redis+lua脚本执行令牌桶算法来判断是否应该对请求进行处理或者抛弃(即起到限流作用)令牌桶算法还需要进一步学习,具体可以参考redis-令牌桶算法介绍