限流,我在项目中还没用到过,熔断用过,但是没在网关中用到过,刷博客,看到了这一篇,看着是能够实现的;
限流:
Gateway通过内置的RequestRateLimiter过滤器实现限流,使用令牌桶算法,借助Redis保存中间数据。用户可通过自定义KeyResolver设置限流维度,例如:
对请求的目标URL进行限流
对来源IP进行限流
特定用户进行限流
本例针对来源IP限流。
添加Redis依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
在application.yml中添加Redis配置:
server:
port: 8084
spring:
redis:
host: 127.0.0.1
port: 6379
SpringBoot自动配置的RedisTemplate生成的key中会包含特殊字符,所以创建一个RedisTemplate替换
@Configuration
public class RedisConfiguration {
@Bean("redisTemplate")
public RedisTemplate redisTemplate(@Value("${spring.redis.host}") String host,
@Value("${spring.redis.port}") int port) {
RedisTemplate redisTemplate = new RedisTemplate();
RedisSerializer stringRedisSerializer = new StringRedisSerializer();
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
redisTemplate.setKeySerializer(stringRedisSerializer);
redisTemplate.setHashKeySerializer(stringRedisSerializer);
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setConnectionFactory(standaloneConnectionFactory(host, port));
return redisTemplate;
}
protected JedisConnectionFactory standaloneConnectionFactory(String host, int port) {
RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
redisStandaloneConfiguration.setHostName(host);
redisStandaloneConfiguration.setPort(port);
return new JedisConnectionFactory(redisStandaloneConfiguration);
}
}
自定义KeyResolver
@Configuration
public class RateLimiterConfiguration {
@Bean(value = "ipKeyResolver")
public KeyResolver ipKeyResolver() {
return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());
}
}
最后一步,在bootstrap.yml的payment-router路由中加入限流过滤器
...
routes:
- id: payment-router
uri: lb://payment-service
predicates:
- Path=/pay/**
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 1
redis-rate-limiter.burstCapacity: 5
key-resolver: '#{@ipKeyResolver}'
其
中令牌桶容量redis-rate-limiter.burstCapacity设置为5,即1秒内最大请求通行数为5个,令牌桶填充速率redis-rate-limiter.replenishRate设置为1。使用jmeter测试:
第一次,5个线程
第二次,10个线程
熔断:
网关是所有请求的入口,如果部分后端服务延时严重,则可能导致大量请求堆积在网关上,拖垮网关进而瘫痪整个系统。这就需要对响应慢的服务做超时快速失败处理,即熔断。
添加hystrix依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
在bootstrap.yml中添加默认过滤器
spring:
...
cloud:
...
gateway:
discovery:
locator:
enabled: true
default-filters:
- name: Hystrix
args:
name : default
fallbackUri: 'forward:/defaultFallback'
...
hystrix:
command:
default:
execution:
isolation:
strategy: SEMAPHORE
thread:
timeoutInMilliseconds: 2000
创建降级处理FallbackController.java
@RestController
public class FallbackController {
@RequestMapping("/defaultFallback")
public Map defaultFallback() {
Map map = new HashMap<>();
map.put("code", 1);
map.put("message", "服务异常");
return map;
}
}
在Nacos后台中把payment-service-dev.properties的sleep值修改为2000模拟服务延时效果,然后测试
本期源码
链接:https://pan.baidu.com/s/1ZHn59CIMTuDO3YC34AM-KQ
提取码:3ob9