服务网关Gateway
内容纲要
服务网关在微服务中的应用
- 官方主推
- 底层Netty构建
- 社区维护
Gateway做什么
- 路由寻址(主要)
- 负载均衡(Ribbon)
- 限流
- 鉴权
第二代网关组件Gateway介绍(Zuul的对比)
Gateway Zuul 1.x Zuul 1.x 靠谱性 官方支持 曾经靠谱过 专业放鸽子 性能 Netty 同步阻塞性能慢 Netty RPS >32000 20000左右 25000左右 Spring Cloud 已整合 已整合 占无整合计划 长链接 支持 不支持 支持 编程体验 略难 简单易上手 略难 调试&链路追踪 略难 无压力 略难
- 用Gateway
Gateway急速落地
创建gateway-sample项目
- 引入依赖
<dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis-reactive</artifactId> </dependency> </dependencies>
- 创建启动类
@EnableDiscoveryClient @SpringBootApplication public class GatewayApplication { public static void main(String[] args) { SpringApplication.run(GatewayApplication.class,args); } }
- 配置文件
server: port: 65000 spring: rabbitmq: username: gateway-service cloud: gateway: discovery: locator: enabled: true eureka: instance: preferIpAddress: true instance-id: ${spring.cloud.client.ip-address}:${server.port} client: service-url: defaultZone: http://localhost:20000/eureka/ management: security: enabled: false endpoints: web: exposure: include: "*" endpoint: health: show-details: always
连接Eureka自动创建路由
- 启动服务
- 验证路由规则
- 设置小写访问
spring: application: name: gateway-service cloud: gateway: discovery: locator: enabled: true # 新增 lower-case-service-id: true
- 验证路由规则
- 访问: http://localhost:65000/{服务名称(小写)}/sayHi
通过Actuator实现动态路由功能
- 访问: http://localhost:65000/{服务名称(小写)}/sayHi
- 引入依赖
- url: http://localhost:65000/actuator/gateway/routes/{动态路由名称}
- 传参格式: application/json
- 传参数据
{ "predicates":[ { "name":"Path", "args":{ "_genkey_0":"/dynamic/**" } } ], "filters":[ { "name":"StripPrefix", "args":{ "_genkey_0":"1" } } ], "uri":"lb://FEIGN-CLIENT", "order":0 }
Gateway断言功能
Path断言
- 使用Path断言转发请求(yml配置+java配置)
- yml配置
spring: application: name: gateway-service cloud: gateway: discovery: locator: enabled: true lower-case-service-id: true # 新增 routes: - id: feignclient uri: lb://FEIGN-CLIENT predicates: - Path=/yml/** filters: - StripPrefix=1
-
java配置
@Configuration public class GatewayConfiguration { @Bean @Order public RouteLocator customizedRoutes(RouteLocatorBuilder builder){ return builder.routes() .route(r-> r.path("/java/**") .and().method(HttpMethod.GET) .and().header("name") .filters(f->f.stripPrefix(1) .addRequestHeader("java-param","gateway-config") ) .uri("lb://FEIGN-CLIENT") ).build(); } }
After断言
- 创建模拟下单接口
@RestController @Slf4j @RequestMapping("/gateway") public class GatewayController { public static final Map<Long, Product> items = new ConcurrentHashMap<>();
@GetMapping("/details")
public Product get(@RequestParam("pid") Long pid) {
if (items.containsKey(pid)) {
Product prod = Product.builder()
.productId(pid)
.description("好吃不贵")
.stock(100L)
.build();
items.putIfAbsent(pid, prod);
}
return items.get(pid);
}@PostMapping("/placeOrder")
public String buy(@RequestParam("pid") String pid) {
Product prod = items.get(pid);
if (prod == null) {
return "Product not found";
} else if (prod.getStock() <= 0L) {
return "Sold out";
}
synchronized (prod) {
if (prod.getStock() <= 0L) {
return "Sold out";
}
prod.setStock(prod.getStock()-1);
}
return "Order Placed";
}
} - 创建模拟下单接口
-
通过After断言设置生效时间
@Configuration public class GatewayConfiguration { @Bean @Order public RouteLocator customizedRoutes(RouteLocatorBuilder builder) { return builder.routes() .route(r -> r.path("/java/**") .and().method(HttpMethod.GET) .and().header("name") .filters(f -> f.stripPrefix(1) .addRequestHeader("java-param", "gateway-config") ) .uri("lb://FEIGN-CLIENT") ) .route(r -> r.path("/seckill/**") .and().after(ZonedDateTime.now().plusMinutes(1)) // .and().before() // .and().between() .filters(f -> f.stripPrefix(1)) .uri("lb://FEIGN-CLIENT")) .build(); } }
Gat过滤器原理和生命周期
自定义过滤器
@Slf4j @Component public class TimerFilter implements GatewayFilter, Ordered { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { StopWatch timer = new StopWatch(); timer.start(exchange.getRequest().getURI().getRawPath()); // exchange.getAttributes().put("requestTimeBegain",System.currentTimeMillis()); return chain.filter(exchange).then( Mono.fromRunnable(()->{ timer.stop(); log.info(timer.prettyPrint()); }) ); } @Override public int getOrder() { return 0; } }
添加TimerFilter到路由
- 局部filter
.route(r -> r.path("/java/**") .and().method(HttpMethod.GET) .and().header("name") .filters(f -> f.stripPrefix(1) .addRequestHeader("java-param", "gateway-config") .filter(timerFilter) ) .uri("lb://FEIGN-CLIENT") )
- 全局filter
将TimerFilter实现的GatewayFilter换为GlobalFilter
- 局部filter
共有 0 条评论