Spring Cloud - 如何利用Zuul实现接口限流

以下为Zuul利用ratelimit在网关进行接口限流。

限流方案

方案 说明
基于用户id 根据用户标识或匿名
基于用户角色 根据用户角色
基于用户源IP 请求源IP
基于请求URL 下游服务地址
基于请求方法类型 HTTP请求方法,GET、POST等
基于请求服务 下游服务

POM引入

1
2
3
4
5
6
<!-- 请求限流 -->
<dependency>
<groupId>com.marcosbarbero.cloud</groupId>
<artifactId>spring-cloud-zuul-ratelimit</artifactId>
<version>2.0.4.RELEASE</version>
</dependency>

参数配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#60秒内允许10个访问,并且要求总请求时间小于1000秒
#seviceA在120秒内允许20个访问,并且要求总请求时间小于2000秒
#seviceA针对匿名用户,IP为10.10.10.10,角色为用户,请求URL为/api/,请求方法为GET

zuul:
ratelimit:
key-prefix: your-prefix #缓存key的前缀
enabled: true #开启限流
repository: REDIS #key存储方式为redis
behind-proxy: true # 当前网关是代理后的请求,需要获取Header中的X-FORWARDED-FOR以便获取源IP
add-response-headers: true #在response header中添加限流信息
default-policy-list: # 默认策略
- limit: 10 #每个刷新窗口请求数
quota: 1000 #每个刷新窗口总请求时间(秒)
refresh-interval: 60 #刷新窗口时间(秒),默认60秒
type:
- user #基于用户标识,默认匿名anonymous
- origin #基于用户IP
- url #基于下游服务URL
- httpmethod #基于请求方法
policy-list: #指定服务策略,优先默认
seviceA: #微服务ID
- limit: 20
quota: 2000
refresh-interval: 120
type:
- user
- origin
- url
- type: #每种类型值设定
- user=anonymous #指定用户,匿名用户
- origin=10.10.10.10 #指定源URL
- url=/api #指定下游请求URL前缀
- role=user #指定用户角色
- httpmethod=get #指定请求方法类型,大小写不敏感

其中,user=anonymousrole=user采用Shiro或者Spring Security进行维护,或者自定义request域UserPrincipal。

数据存储

  • InMemory(ConcurrentHashMap)
  • Redis
  • Consul
  • Spring Data JPA
  • JCache
  • Infinispan
  • Hazelcast
  • Ignite

将会对服务集群的请求情况同步至选择的存储中,以做到数据共享和实时存储。

源码及原理分析

自定义key

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Bean
public RateLimitKeyGenerator ratelimitKeyGenerator(RateLimitProperties properties, RateLimitUtils rateLimitUtils) {
return new DefaultRateLimitKeyGenerator(properties, rateLimitUtils) {
@Override
public String key(HttpServletRequest request, Route route, RateLimitProperties.Policy policy) {
//super.key()为默认实现
//keyPrefix+serviceId+(type1Key+...+typenKey)
String key= super.key(request, route, policy) ;

//":" + request.getMethod() 为自定义策略
key += ":" + request.getMethod();

//实现对key的重写,限流策略是以key为标识依据
return key;
}
};
}

自定义错误

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Bean
public RateLimiterErrorHandler rateLimitErrorHandler() {
return new DefaultRateLimiterErrorHandler() {
@Override
public void handleSaveError(String key, Exception e) {
// 处理存储key异常
}

@Override
public void handleFetchError(String key, Exception e) {
// 处理查询key异常
}

@Override
public void handleError(String msg, Exception e) {
// 处理异常信息
}
}
}

自定义用户和角色

SecuredRateLimitUtils.java

1
2
3
4
5
6
7
8
@Override
public Set<String> getUserRoles() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null) {
return emptySet();
}
return AuthorityUtils.authorityListToSet(authentication.getAuthorities());
}

SecurityContextHolder为Spring Security框架,可获取用户角色和标识。

Spring Security样例如下:

1
2
3
4
5
6
7
8
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user")
.password("password")
.roles("USER");
}

------ 本文结束------

本文标题:Spring Cloud - 如何利用Zuul实现接口限流

文章作者:Perkins

发布时间:2019年04月23日

原始链接:https://perkins4j2.github.io/posts/33184/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。