目录
(一)Nacos动态配置
(二)Nacos注册中心
(三)Sentinel之限流
(四)Sentinel之熔断
(五)Gateway之路由、限流
(六)Gateway之鉴权、日志
(七)Gateway搭配Nacos实现动态路由
(八)Dubbo + Nacos
正文
在微服务架构中,网关的职责包括路由、鉴权、限流、日志、监控、灰度发布等,目前主流的方案有Neflix Zuul和Spring Cloud Gateway。
需要注意的是,从性能上看,无论是Zuul、Zuul2还是Spring的亲儿子Gateway,都和直接用Nignx的方式有较大的差距。先看看Spring Cloud Gateway提供了什么样的功能,值得为它牺牲性能。
一、路由
1 准备工作
参考 Spring Cloud Alibaba实战(二) - Nacos注册中心 启动Nacos和两个payment-service服务。
2 创建项目
创建一个SpringBoot项目,添加Cloud Gateway和Nacos相关依赖,不要添加Web依赖。完成后的pom如下:
1.8
Greenwich.SR1
0.9.0.RELEASE
org.springframework.boot
spring-boot-starter-web
org.springframework.cloud
spring-cloud-starter-alibaba-nacos-config
${alibaba.version}
org.springframework.cloud
spring-cloud-starter-alibaba-nacos-discovery
${alibaba.version}
org.springframework.cloud
spring-cloud-starter-alibaba-sentinel
${alibaba.version}
com.alibaba.csp
sentinel-datasource-nacos
1.6.0
org.springframework.boot
spring-boot-starter-test
test
org.springframework.cloud
spring-cloud-dependencies
${spring-cloud.version}
pom
import
application.yml
server:
port: 8084
bootstrap.yml
spring:
application:
name: gateway
cloud:
nacos:
config:
server-addr: 127.0.0.1:8848
discovery:
server-addr: 127.0.0.1:8848
gateway:
discovery:
locator:
enabled: true
routes:
- id: payment-router
uri: lb://payment-service
predicates:
- Path=/pay/**
在上面的配置中:
id: payment-router 值随意,方便记忆并且在所有路由定义中唯一即可
uri: lb://payment-service lb://为固定写法,表示开启负载均衡;payment-service即服务在Nacos中注册的名字
predicates:- Path=/pay/** 使用"Path Route Predicate Factory",规则为/pay开头的任意URI
最后一步,在启动类上增加@EnableDiscoveryClient注解
@SpringBootApplication
@EnableDiscoveryClient
public class GatewayApplication {
启动应用并测试
返回结果表明请求被转发到payment-service上,同时查看两个payment服务的输出窗口:
可以看出多次请求被平均分配到两个实例上。
除了Path Route Predicate Factory,Gateway还支持多种设置方式:
类型 | 示例 |
---|---|
After | After=2017-01-20T17:42:47.789-07:00[America/Denver] |
Before | Before=2017-01-20T17:42:47.789-07:00[America/Denver] |
Between | 2017-01-20T17:42:47.789-07:00[America/Denver], 2017-01-21T17:42:47.789-07:00[America/Denver] |
Cookie | Cookie=chocolate, ch.p |
Header | Header=X-Request-Id, \d+ |
Host | Host=**.somehost.org |
Method | Method=GET |
Path | Path=/foo/{segment} |
Query | Query=baz |
RemoteAddr | RemoteAddr=192.168.1.1/24 |
二、限流
Gateway通过内置的RequestRateLimiter过滤器实现限流,使用令牌桶算法,借助Redis保存中间数据。用户可通过自定义KeyResolver设置限流维度,例如:
本例针对来源IP限流。
添加Redis依赖:
org.springframework.boot
spring-boot-starter-data-redis
org.springframework.boot
spring-boot-starter-data-redis-reactive
redis.clients
jedis
在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个线程
三、熔断
网关是所有请求的入口,如果部分后端服务延时严重,则可能导致大量请求堆积在网关上,拖垮网关进而瘫痪整个系统。这就需要对响应慢的服务做超时快速失败处理,即熔断。
添加hystrix依赖
org.springframework.cloud
spring-cloud-starter-netflix-hystrix
在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