微服务开发中有时需要对 API 做限流保护, 防止网络攻击, 比如做一个短信验证码 API, 限制客户端的请求速率能在一定程度上抵御短信轰炸攻击, 降低损失. 微服务网关是每个请求的必经入口, 非常适合做一些 API 限流, 认证之类的操作, 本文介绍 Zuul 如何进行限流操作, 对 Zuul 不了解的可以参考我这篇文章: SpringCloud 组件之 Zuul
一, Ratelimit 相关配置介绍
1, 限流策略
限流粒度 / 类型 | 说明 |
---|---|
Authenticated User | 使用经过身份验证的用户名或 “匿名” |
Request Origin | 使用用户原始请求 |
URL | 使用下游服务的请求路径 |
ROLE | 使用经过身份验证的用户角色 |
Request method | 使用 HTTP 请求方法 |
Global configuration per service | 这个不验证请求 Origin,Authenticated User 或 URI,要使用这个,请不要设置 type |
2, 可用的实现
存储类型 | 说明 |
---|---|
consul | 基于 consul |
redis | 基于 redis,使用时必须引入 redis 相关依赖 |
JPA | 基于 SpringDataJPA,需要用到数据库 |
MEMORY | 基于本地内存,默认 |
BUKET4J | 使用一个 Java 编写的基于令牌桶算法的限流库 |
Bucket4j 实现需要相关的 bean @Qualifier("RateLimit"):
- JCache - javax.cache.Cache
- Hazelcast - com.hazelcast.core.IMap
- Ignite - org.apache.ignite.IgniteCache
- Infinispan - org.infinispan.functional.ReadWriteMap
3, 常见的配置属性
属性名 | 值 | 默认值 |
---|---|---|
enabled | true/false | false |
behind-proxy | true/false | false |
add-response-header | true/false | false |
key-prefix | string | ${spring.application.name:rate-limit-application} |
repository | CONSUL, REDIS, JPA, BUCKET4J_JCACHE, BUCKET4J_HAZELCAST, BUCKET4J_INFINISPAN, BUCKET4J_IGNITE | - |
default-policy-list | list-of-policy | - |
policy-list | Map of Lists of Policy | - |
postFilterOrder | int | FilterConstants.SEND_RESPONSE_FILTER_ORDER - 10 |
preFilterOrder | int | FilterConstants.FORM_BODY_WRAPPER_FILTER_ORDER |
policy 的相关属性
属性名 | 值 | 默认值 |
---|---|---|
limit | number of calls | - |
quota | time of calls | - |
refresh-interval | seconds | 60 |
type | [ORIGIN, USER, URL, ROLE] | [] |
4, 发生错误如何处理
- @Bean
- public RateLimiterErrorHandler rateLimitErrorHandler() {
- return new DefaultRateLimiterErrorHandler() {
- @Override
- public void handleSaveError(String key, Exception e) {
- // custom code
- }
- @Override
- public void handleFetchError(String key, Exception e) {
- // custom code
- }
- @Override
- public void handleError(String msg, Exception e) {
- // custom code
- }
- }
- }
二, 搭建 Zuul 结合 Ratelimit 服务
1, 导入依赖
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
- </dependency>
- <dependency>
- <groupId>com.marcosbarbero.cloud</groupId>
- <artifactId>spring-cloud-zuul-ratelimit</artifactId>
- <version>2.2.3.RELEASE</version>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-data-Redis</artifactId>
- </dependency>
2, 启动类标注解
- @SpringBootApplication
- @EnableEurekaClient
- @EnableZuulProxy
- public class ZuulRatelimitApplication {
- public static void main(String[] args) {
- SpringApplication.run(ZuulRatelimitApplication.class, args);
- }
- }
3, 配置文件
- server:
- port: 8080
- spring:
- application:
- name: zuul-ratelimit
- Redis:
- host: localhost
- password:
- zuul:
- # 配置路由
- routes:
- demo:
- path: /demo/**
- serviceId: demo
- # 配置限流
- ratelimit:
- enabled: true
- # 对应存储类型 (用来统计存储统计信息)
- repository: Redis
- # 配置路由的策略
- policy-list:
- demo:
- # 每秒允许多少个请求
- - limit: 2
- # 刷新时间 (单位秒)
- refresh-interval: 1
- # 根据什么统计
- type:
- - url
4, 启动后进行访问
由于我们配置的是一秒只允许两个请求, 当我们超过时, 会抛出过多请求异常
到此本文就结束啦, 更多相关知识可以前往: spring-cloud-zuul-ratelimit, 本 demo 地址: SpringCloud-Demo
来源: https://yq.aliyun.com/articles/707059