【微服务】服务网关----Gateway

发布于:2022-11-09 ⋅ 阅读:(9) ⋅ 点赞:(0) ⋅ 评论:(0)

1、前言

上篇文章讲解了如何实现服务容错,这篇就介绍下,服务网关—Gateway。在本篇文章中,你将了解到什么是服务网关?什么是Gateway?如何实现Gateway?Gateway的核心架构有哪些?如何实现网关限流等问题。

2、网关简介

首先,在传统的架构中,没有了网关,那么作为客户端,是怎么去调用的呢?如图所示:

在这里插入图片描述
这样的架构,会存在着诸多的问题:

  • 客户端多次请求不同的微服务,增加客户端代码或配置编写的复杂性
  • 认证复杂,每个服务都需要独立认证。
  • 存在跨域请求,在一定场景下处理相对复杂。

上面的这些问题可以借助API网关来解决。如图所示:

在这里插入图片描述
所谓的API网关,就是指系统的统一入口,它封装了应用程序的内部结构,为客户端提供统一服务,一些与业务本身功能无关的公共逻辑可以在这里实现,诸如认证、鉴权、监控、路由转发等等。

注意:
SpringCloud alibaba技术栈中并没有提供自己的网关,我们可以采用Spring Cloud Gateway 来做网关。

3、Gateway简介

Spring Cloud Gateway是Spring公司基于Spring 5.0,Spring Boot 2.0 和 Project Reactor 等技术开发的网关,它旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式。它的目标是替代NetflflixZuul,其不仅提供统一的路由方式,并且基于 Filter 链的方式提供了网关基本的功能,例如:安全,监控和限流。

优点:

  • 性能强劲:是第一代网关Zuul的1.6倍
  • 功能强大:内置了很多实用的功能,例如转发、监控、限流等
  • 设计优雅,容易扩展

缺点:

  • 其实现依赖Netty与WebFlux,不是传统的Servlet编程模型,学习成本高
  • 不能将其部署在Tomcat、Jetty等Servlet容器里,只能打成jar包执行
  • 需要Spring Boot 2.0及以上的版本,才支持

4、Gateway快速入门

要求: 通过浏览器访问api网关,然后通过网关将请求转发到商品微服务。

4.1 基础版

第1步:创建一个 api-gateway 的模块,导入相关依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<parent>
		<artifactId>springcloud-alibaba</artifactId>
		<groupId>com.itheima</groupId>
		<version>1.0-SNAPSHOT</version>
	</parent>
		
	<modelVersion>4.0.0</modelVersion>
	<artifactId>api-gateway</artifactId>
	
	<dependencies>
	<!--gateway网关--> 
		<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-gateway</artifactId>
		</dependency>
	</dependencies>
</project>

第2步: 创建主类

package com.itheima;
@SpringBootApplication
public class GatewayApplication {
	public static void main(String[] args) {
		SpringApplication.run(GatewayApplication.class, args);
	}
}

第3步: 添加配置文件

server:
port: 7000
spring:
application:
name: api-gateway
cloud:
gateway:
routes: # 路由数组[路由 就是指定当请求满足什么条件的时候转到哪个微服务]
\- id: product_route # 当前路由的标识, 要求唯一
uri: http://localhost:8081 # 请求要转发到的地址
order: 1 # 路由的优先级,数字越小级别越高
predicates: # 断言(就是路由转发要满足的条件)
\- Path=/product-serv/** # 当请求路径满足Path指定的规则时,才进行路由转发 filters: # 过滤器,请求在传递过程中可以通过过滤器对其进行一定的修改
\- StripPrefix=1 # 转发之前去掉1层路径

第4步: 启动项目, 并通过网关去访问微服务

在这里插入图片描述

4.2 增强版(引入nacos)

第1步:加入nacos依赖

<!--nacos客户端-->
<dependency>
	<groupId>com.alibaba.cloud</groupId> 
	<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> 
</dependency>

第2步:在主类上添加注解

@SpringBootApplication
@EnableDiscoveryClient
public class ApiGatewayApplication {
	public static void main(String[] args) {
		SpringApplication.run(ApiGatewayApplication.class, args);
	}
}

第3步:修改配置文件

server:
port: 7000
spring:
application:
name: api-gateway
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
gateway:
discovery:
locator:
enabled: true # 让gateway可以发现nacos中的微服务
routes:
\- id: product_route
uri: lb://service-product # lb指的是从nacos中按照名称获取微服务,并遵循负载均 衡策略
predicates:
\- Path=/product-serv/**
filters:
\- StripPrefix=1

第4步:测试

在这里插入图片描述

4.3 简写版

第1步: 去掉关于路由的配置

server:
port: 7000
spring:
application:
name: gateway
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
gateway:
discovery:
locator:
enabled: true

第2步: 启动项目,并通过网关去访问微服务

在这里插入图片描述

这时候,就发现只要按照网关地址微服务接口的格式去访问,就可以得到成功响应。

5、Gateway核心架构

5.1 路由(Route)

路由(Route) 是 gateway 中最基本的组件之一,表示一个具体的路由信息载体。主要定义了下面的几个信息:

  • id:路由标识符,区别于其他 Route。
  • uri: 路由指向的目的地 uri,即客户端请求最终被转发到的微服务。
  • order:用于多个 Route 之间的排序,数值越小排序越靠前,匹配优先级越高。
  • predicate:断言的作用是进行条件判断,只有断言都返回真,才会真正的执行路由。
  • fifilter:过滤器用于修改请求和响应信息。

5.2 执行流程

在这里插入图片描述
执行流程大体如下:

  1. Gateway Client向Gateway Server发送请求
  2. 请求首先会被HttpWebHandlerAdapter进行提取组装成网关上下文
  3. 然后网关的上下文会传递到DispatcherHandler,它负责将请求分发给
    RoutePredicateHandlerMapping
  4. RoutePredicateHandlerMapping负责路由查找,并根据路由断言判断路由是否可用
  5. 如果过断言成功,由FilteringWebHandler创建过滤器链并调用
  6. 请求会一次经过PreFilter–微服务-PostFilter的方法,最终返回响应

6、实现网关限流

网关是所有请求的公共入口,所以可以在网关进行限流,而且限流的方式也很多,我们本次采用前面学过的Sentinel组件来实现网关的限流。

Sentinel支持对SpringCloud Gateway、Zuul等主流网关进行限流。

从1.6.0版本开始,Sentinel提供了SpringCloud Gateway的适配模块,可以提供两种资源维度的限流:

  • route维度:即在Spring配置文件中配置的路由条目,资源名为对应的routeId
  • 自定义API维度:用户可以利用Sentinel提供的API来自定义一些API分组

1、导入依赖:

<dependency>
	<groupId>com.alibaba.csp</groupId>
	<artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
</dependency>

2、编写配置类

基于Sentinel 的Gateway限流是通过其提供的Filter来完成的,使用时只需注入对应的 SentinelGatewayFilter实例以及 SentinelGatewayBlockExceptionHandler 实例即可。

@Configuration
    public class GatewayConfiguration {
        private final List<ViewResolver> viewResolvers;
        private final
        ServerCodecConfigurer serverCodecConfigurer;

        public GatewayConfiguration(ObjectProvider<List<ViewResolver>> viewResolversProvider,
                                    ServerCodecConfigurer serverCodecConfigurer) {
            this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
            this.serverCodecConfigurer = serverCodecConfigurer;
        }

        // 初始化一个限流的过滤器
        @Bean
        @Order(Ordered.HIGHEST_PRECEDENCE)
        public GlobalFilter sentinelGatewayFilter() {
            return new SentinelGatewayFilter();
        }

        // 配置初始化的限流参数
        @PostConstruct
        public void initGatewayRules() {
            Set<GatewayFlowRule> rules = new HashSet<>();
            rules.add(
                    new GatewayFlowRule("product_route") //资源名称,对应路由id .setCount(1) // 限流阈值
                            .setIntervalSec(1) // 统计时间窗口,单位是秒,默认是 1 秒
            );
            GatewayRuleManager.loadRules(rules);
        }

        // 配置限流的异常处理器
        @Bean
        @Order(Ordered.HIGHEST_PRECEDENCE)
        public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
            return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
        }

        // 自定义限流异常页面
        @PostConstruct
        public void initBlockHandlers() {
            BlockRequestHandler blockRequestHandler = new BlockRequestHandler() {
                public Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) {
                    Map map = new HashMap<>();
                    map.put("code", 0);
                    map.put("message", "接口被限流了");
                    return
                            ServerResponse.status(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON_UTF8
                                    ).
                                    body(BodyInserters.fromObject(map));
                }
            };
            GatewayCallbackManager.setBlockHandler(blockRequestHandler);
        }
    }

3 测试

在一秒钟内多次访问http://localhost:7000/product-serv/product/1就可以看到限流启作用了。

在这里插入图片描述

7、总结

本篇文章介绍了微服务中服务网关的概念,如何使用Gateway搭建一个服务网关,以及怎么实现服务网关层的请求限流等。