Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
S
spring-boot-starter-dsp
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
shenjiaqing
spring-boot-starter-dsp
Commits
6a1ba44a
Commit
6a1ba44a
authored
Apr 28, 2022
by
shenjiaqing
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
提交代码
parent
da3b426e
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
80 additions
and
4 deletions
+80
-4
build.gradle
build.gradle
+1
-1
LimitAspect.java
...uiba/spring/boot/starter/dsp/rateLimiter/LimitAspect.java
+22
-3
limit.lua
...boot-starter-dsp-rateLimiter/src/main/resources/limit.lua
+57
-0
No files found.
build.gradle
View file @
6a1ba44a
...
...
@@ -38,7 +38,7 @@ allprojects {
}
group
=
"cn.com.duiba.boot"
version
=
"0.0.7
3
-sjq-SNAPSHOT"
version
=
"0.0.7
4
-sjq-SNAPSHOT"
}
subprojects
{
...
...
spring-boot-starter-dsp-rateLimiter/src/main/java/cn/com/duiba/spring/boot/starter/dsp/rateLimiter/LimitAspect.java
View file @
6a1ba44a
...
...
@@ -23,6 +23,8 @@ import java.util.concurrent.atomic.AtomicLong;
@Component
public
class
LimitAspect
{
private
final
static
Map
<
Long
,
Integer
>
redisNodeIndex
=
new
ConcurrentHashMap
<>();
private
final
static
Logger
logger
=
LoggerFactory
.
getLogger
(
LimitAspect
.
class
);
private
final
static
Map
<
String
,
AtomicLong
>
map
=
new
ConcurrentHashMap
<>();
...
...
@@ -31,6 +33,23 @@ public class LimitAspect {
static
{
map
.
put
(
"rate.limit:com.duiba.tuia.adx.web.service.algo.impl.AdxAlgoServiceImpl-hello-limit"
,
new
AtomicLong
());
redisNodeIndex
.
put
(
0L
,
14
);
redisNodeIndex
.
put
(
1L
,
18
);
redisNodeIndex
.
put
(
2L
,
296
);
redisNodeIndex
.
put
(
3L
,
346
);
redisNodeIndex
.
put
(
4L
,
29
);
redisNodeIndex
.
put
(
5L
,
21
);
redisNodeIndex
.
put
(
6L
,
32
);
redisNodeIndex
.
put
(
7L
,
122
);
redisNodeIndex
.
put
(
8L
,
69
);
redisNodeIndex
.
put
(
9L
,
65
);
redisNodeIndex
.
put
(
10L
,
76
);
redisNodeIndex
.
put
(
11L
,
197
);
redisNodeIndex
.
put
(
12L
,
50
);
redisNodeIndex
.
put
(
13L
,
58
);
redisNodeIndex
.
put
(
14L
,
223
);
redisNodeIndex
.
put
(
15L
,
47
);
}
@Resource
(
name
=
"redis03StringRedisTemplate"
)
...
...
@@ -68,11 +87,11 @@ public class LimitAspect {
.
append
(
method
.
getName
()).
append
(
"-"
)
.
append
(
rateLimit
.
key
());
String
s
=
stringBuilder
.
toString
();
String
commonRedisKey
=
stringBuilder
.
toString
();
long
index
=
map
.
get
(
s
).
getAndIncrement
()
%
REDIS_NODE_NUM
;
long
index
=
map
.
get
(
commonRedisKey
).
getAndIncrement
()
%
REDIS_NODE_NUM
;
String
redisKey
=
s
+
index
;
String
redisKey
=
commonRedisKey
+
"{"
+
redisNodeIndex
.
get
(
index
)
+
"}"
;
logger
.
info
(
"限流啦, redis key{}"
,
redisKey
);
List
<
String
>
keys
=
Collections
.
singletonList
(
redisKey
);
...
...
spring-boot-starter-dsp-rateLimiter/src/main/resources/limit.lua
View file @
6a1ba44a
...
...
@@ -7,3 +7,60 @@ else --请求数+1,并设置2秒过期
redis
.
call
(
"expire"
,
KEYS
[
1
],
"2"
)
return
current
+
1
end
--
--
-- -- LUA脚本会以单线程执行,不会有并发问题,一个脚本中的执行过程中如果报错,那么已执行的操作不会回滚
-- -- KEYS和ARGV是外部传入进来需要操作的redis数据库中的key,下标从1开始
-- -- 参数结构: KEYS = [限流的key] ARGV = [最大令牌数, 每秒生成的令牌数, 本次请求的毫秒数]
-- local info = redis.pcall('HMGET', KEYS[1], 'last_time', 'stored_token_nums')
-- local last_time = info[1] --最后一次通过限流的时间
-- local stored_token_nums = tonumber(info[2]) -- 剩余的令牌数量
-- local max_token = tonumber(ARGV[1])
-- local token_rate = tonumber(ARGV[2])
-- local current_time = tonumber(ARGV[3])
-- local past_time = 0
-- local rateOfperMills = token_rate/1000 -- 每毫秒生产令牌速率
--
-- if stored_token_nums == nil then
-- -- 第一次请求或者键已经过期
-- stored_token_nums = max_token --令牌恢复至最大数量
-- last_time = current_time --记录请求时间
-- else
-- -- 处于流量中
-- past_time = current_time - last_time --经过了多少时间
--
-- if past_time <= 0 then
-- --高并发下每个服务的时间可能不一致
-- past_time = 0 -- 强制变成0 此处可能会出现少量误差
-- end
-- -- 两次请求期间内应该生成多少个token
-- local generated_nums = math.floor(past_time * rateOfperMills) -- 向下取整,多余的认为还没生成完
-- stored_token_nums = math.min((stored_token_nums + generated_nums), max_token) -- 合并所有的令牌后不能超过设定的最大令牌数
-- end
--
-- local returnVal = 0 -- 返回值
--
-- if stored_token_nums > 0 then
-- returnVal = 1 -- 通过限流
-- stored_token_nums = stored_token_nums - 1 -- 减少令牌
-- -- 必须要在获得令牌后才能重新记录时间。举例: 当每隔2ms请求一次时,只要第一次没有获取到token,那么后续会无法生产token,永远只过去了2ms
-- last_time = last_time + past_time
-- end
--
-- -- 更新缓存
-- redis.call('HMSET', KEYS[1], 'last_time', last_time, 'stored_token_nums', stored_token_nums)
-- -- 设置超时时间
-- -- 令牌桶满额的时间(超时时间)(ms) = 空缺的令牌数 * 生成一枚令牌所需要的毫秒数(1 / 每毫秒生产令牌速率)
-- redis.call('PEXPIRE', KEYS[1], math.ceil((1/rateOfperMills) * (max_token - stored_token_nums)))
--
-- return returnVal
--
-- --实现平滑限流
-- --出自:https://www.jianshu.com/p/89822f8d5c69
-- --https://blog.csdn.net/teavamc/article/details/113359632
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment