如何理解spring-cloud-gateway自带redis限流脚本
发表于:2025-01-16 作者:千家信息网编辑
千家信息网最后更新 2025年01月16日,这篇文章主要讲解了"如何理解spring-cloud-gateway自带redis限流脚本",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"如何理解spr
千家信息网最后更新 2025年01月16日如何理解spring-cloud-gateway自带redis限流脚本
这篇文章主要讲解了"如何理解spring-cloud-gateway自带redis限流脚本",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"如何理解spring-cloud-gateway自带redis限流脚本"吧!
filter入口: org.springframework.cloud.gateway.filter.factory.RequestRateLimiterGatewayFilterFactory#apply
限流判断入口: org.springframework.cloud.gateway.filter.ratelimit.RedisRateLimiter#isAllowed
@Override @SuppressWarnings("unchecked") public MonoisAllowed(String routeId, String id) { if (!this.initialized.get()) { throw new IllegalStateException("RedisRateLimiter is not initialized"); } Config routeConfig = loadConfiguration(routeId); // How many requests per second do you want a user to be allowed to do? int replenishRate = routeConfig.getReplenishRate(); // How much bursting do you want to allow? int burstCapacity = routeConfig.getBurstCapacity(); try { List keys = getKeys(id); // The arguments to the LUA script. time() returns unixtime in seconds. List scriptArgs = Arrays.asList(replenishRate + "", burstCapacity + "", Instant.now().getEpochSecond() + "", "1"); // allowed, tokens_left = redis.eval(SCRIPT, keys, args) Flux > flux = this.redisTemplate.execute(this.script, keys, scriptArgs); // .log("redisratelimiter", Level.FINER); return flux.onErrorResume(throwable -> Flux.just(Arrays.asList(1L, -1L))) .reduce(new ArrayList
(), (longs, l) -> { longs.addAll(l); return longs; }).map(results -> { boolean allowed = results.get(0) == 1L; Long tokensLeft = results.get(1); Response response = new Response(allowed, getHeaders(routeConfig, tokensLeft)); if (log.isDebugEnabled()) { log.debug("response: " + response); } return response; }); } catch (Exception e) { /* * We don't want a hard dependency on Redis to allow traffic. Make sure to set * an alert so you know if this is happening too much. Stripe's observed * failure rate is 0.01%. */ log.error("Error determining if user allowed from redis", e); } return Mono.just(new Response(true, getHeaders(routeConfig, -1L))); }
lua脚本加载入口: org.springframework.cloud.gateway.config.GatewayRedisAutoConfiguration#redisRequestRateLimiterScript
@Bean @SuppressWarnings("unchecked") public RedisScript redisRequestRateLimiterScript() { DefaultRedisScript redisScript = new DefaultRedisScript<>(); redisScript.setScriptSource(new ResourceScriptSource( new ClassPathResource("META-INF/scripts/request_rate_limiter.lua"))); redisScript.setResultType(List.class); return redisScript; }
request_rate_limiter.lua脚本
local tokens_key = KEYS[1]local timestamp_key = KEYS[2]--redis.log(redis.LOG_WARNING, "tokens_key " .. tokens_key)local rate = tonumber(ARGV[1])local capacity = tonumber(ARGV[2])local now = tonumber(ARGV[3])local requested = tonumber(ARGV[4])local fill_time = capacity/ratelocal ttl = math.floor(fill_time*2)--redis.log(redis.LOG_WARNING, "rate " .. ARGV[1])--redis.log(redis.LOG_WARNING, "capacity " .. ARGV[2])--redis.log(redis.LOG_WARNING, "now " .. ARGV[3])--redis.log(redis.LOG_WARNING, "requested " .. ARGV[4])--redis.log(redis.LOG_WARNING, "filltime " .. fill_time)--redis.log(redis.LOG_WARNING, "ttl " .. ttl)local last_tokens = tonumber(redis.call("get", tokens_key))if last_tokens == nil then last_tokens = capacityend--redis.log(redis.LOG_WARNING, "last_tokens " .. last_tokens)local last_refreshed = tonumber(redis.call("get", timestamp_key))if last_refreshed == nil then last_refreshed = 0end--redis.log(redis.LOG_WARNING, "last_refreshed " .. last_refreshed)local delta = math.max(0, now-last_refreshed)--重点是这里,rate是相对于capacity而言,如果大于等于capacity,那么每秒的并发量就是capacity,--如果小于capacity,那么才会每秒固定添加rate个令牌到桶中。--正常限流建议设置小于capacity,否则当capacity瞬间用完,这个时候说明已经达到了系统最大并发阀值,--下一秒瞬间又恢复最大令牌桶阀值,速率过大反而起不到限流作用。local filled_tokens = math.min(capacity, last_tokens+(delta*rate))local allowed = filled_tokens >= requestedlocal new_tokens = filled_tokenslocal allowed_num = 0if allowed then new_tokens = filled_tokens - requested allowed_num = 1end--redis.log(redis.LOG_WARNING, "delta " .. delta)--redis.log(redis.LOG_WARNING, "filled_tokens " .. filled_tokens)--redis.log(redis.LOG_WARNING, "allowed_num " .. allowed_num)--redis.log(redis.LOG_WARNING, "new_tokens " .. new_tokens)redis.call("setex", tokens_key, ttl, new_tokens)redis.call("setex", timestamp_key, ttl, now)return { allowed_num, new_tokens }
感谢各位的阅读,以上就是"如何理解spring-cloud-gateway自带redis限流脚本"的内容了,经过本文的学习后,相信大家对如何理解spring-cloud-gateway自带redis限流脚本这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是,小编将为大家推送更多相关知识点的文章,欢迎关注!
脚本
入口
学习
最大
令牌
内容
就是
作用
建议
思路
情况
文章
时候
更多
知识
知识点
篇文章
系统
跟着
速率
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
武威商城分销软件开发多少钱
免费阅读公益性社会学刊的数据库
电池阻抗数据库
北京海仓无忧网络技术
苹果11设置邮件收件服务器
怎么找网络安全工作
靖江一小网络安全作业平台
CBD网络安全
oracl怎么删除数据库
公司有数据库系统吗
网络安全教育小细节
ts服务器购
软件开发是税率多少钱
单位网络安全目标责任书
第七届网络安全宣传周主题
浪潮服务器与新生态大战
企业网络安全损失统计
BS软件开发框架
数据库关系分解模式
服务器租赁托管和云主机哪个好
应用程序显示数据库没有开启
网络安全小组头像
工业网络技术专业人培
excleif表格数据库
天基互联网科技股
智能还信用卡软件开发
工程项目软件开发公司
福建易联众系统软件开发有限公司
美篇服务器出错
网络安全专业就业薪酬