SpringCloudGateway网关 学习记录

 

微服务网关的概念:

 
什么是微服务网关:
       现在流行的微服务架构中,对大多数的服务进行指量上的拓展增多以应对服务的工作量需求。对此每个微服务都会有对应的ip端口。
在大型的项目中可能这种对外的访问ip端口是成百上千的。对访问与管理是很不方便的。对这种情况应对的方案就是配置一个微服务
网关。让所有的请求访问到微服务网关中再由网关进行同一的管理(权监、负载均衡、日志等等..)。这样对我们的维护与使用也是
极大的遍历。
 
作用和应用场景:
       网关的作业:负载均衡、监控、用户权限鉴定、缓存等等...   其中最主要的就是与外界取得联系对服务暴露进行统一管理
 
常见的API网关实现方式:
       SpringCloudGateway: SpringCloud提供的网关服务
       Nginx:使用Nginx的反向代理和负载均衡可实现对api服务器的负载均衡及高可用
                    问题:自注册的问题和网关本身的扩展性
       Zuul:Netflflix开源,功能丰富,使用JAVA开发,易于二次开发;需要运行在web容器中,如Tomcat。
                    问题:缺乏管控,无法动态配置;依赖组件较多;处理Http请求依赖的是Web容器,性能不如Nginx;

 

 

 

微服务网关GateWay

ZUUL是一个基于阻塞IO的微服务网关。其内在原理也依赖Servlet。所以其整体的性能并不是很良好。

对于JAVA项目来说SpringCloudGateWay是主场作战。在Spring大家庭中融入的比较好。所以使用起来相对方便。

 

在SpringCloudGateWay中有三个比较核心的概念:

 

 

 

 

1. 路由(route)
路由是网关最基础的部分,路由信息由一个ID、一个目的URL、一组断言工厂和一
组Filter组成。如果断言为真,则说明请求URL和配置的路由匹配。
2. 断言(predicates)
Java8中的断言函数,Spring Cloud Gateway中的断言函数输入类型是
Spring5.0框架中的ServerWebExchange。Spring Cloud Gateway中的断言函数允许开发者去定
义匹配来自Http Request中的任何信息,比如请求头和参数等。
3. 过滤器(fifilter)
一个标准的Spring webFilter,Spring Cloud Gateway中的Filter分为两种类型,
分别是Gateway Filter和Global Filter。过滤器Filter可以对请求和响应进行处理

 


 

SpringCloud Gateway的使用:

(1)导入依赖

  <!-- 网关依赖 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>

(2)配置启动类

package com.kerry.gateway;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

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

(3)编写application.yml配置文件

server:
  port: 8001

spring:
  application:
    name: server-gateway #服务名称
  cloud:
    gateway:
      routes:
      - id: category-service   #自定义的路由id,保持唯一
        uri: http://127.0.0.1:9001  #目标服务地址
        predicates:  #路由条件 可于网上搜索更多
        - Path=/category/**,/admin/category/**
      - id: headline-service
        uri: http://127.0.0.1:9002
        predicates:
        - Path=/headline/**,/admin/headline/**

到此简简单单的路由功能已经实现了,但是我们可以注意到在目标服务地址上我们填写的对应的ip端口,这样写死的话

明显是不够完善的。对此我们可以引入动态路由

 

动态路由

(1)添加注册中心依赖
        <!-- eureka网关-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

(2)修改application.yml配置文件

server:
  port: 8001

spring:
  application:
    name: server-gateway #服务名称
  cloud:
    gateway:
      routes:
      - id: category-service
        uri: lb://service-category
        predicates:
        - Path=/category/**,/admin/category/**
      - id: headline-service
        uri:  lb://service-headline
        predicates:
        - Path=/headline/**,/admin/headline/**

eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:8000/eureka #,http://127.0.0.1:8999/eureka/
      registry-fetch-interval-seconds: 5 # 获取服务列表的周期:5s
  instance:
    prefer-ip-address: true #使用ip注册
    ip-address: 127.0.0.1
uri : uri以 lb: //开头(lb代表从注册中心获取服务),后面接的就是你需要转发到的服务名称 

 

 

重写转发路径

在SpringCloud Gateway中,路由转发是直接将匹配的路由path直接拼接到映射路径(URI)之后,那么在微服务开发中往往没有那么便利。
这里就可以通过RewritePath机制来进行路径重写。 
 
(1)案例改造 
修改 application.yml ,将匹配路径改为 /product-service/** 
重新启动网关,我们在浏览器访问http://127.0.0.1:8080/product-service/product/1,会抛出404。这是由于路由转发规则默认转发到商品微服务
http://127.0.0.1:9002/product-service/product/1 )路径上,而商品微服务又没有 product-service 对应的映射配置。 
(2)添加RewritePath重写转发路径 
spring:
  application:
    name: api-gateway #指定服务名
  cloud:
    gateway:
      routes:
      - id: product-service
        uri: lb://shop-service-product
        predicates:
        - Path=/product-service/**
        filters:
        - RewritePath=/product-service/(?<segment>.*), /$\{segment}
通过RewritePath配置重写转发的url,将/product-service/(?.*),重写为{segment},然后转发到订单
微服务。比如在网页上请求http://localhost:8080/product-service/product,此时会将请求转发到
http://127.0.0.1:9002/product/1( 值得注意的是在yml文档中 $ 要写成 $\ )
 
 
 

过滤器

SpringCloudGateway中不仅有路由功能还支持对请求的过滤。相比Zuul网关,SpringCloudGateway的过滤器功能就相对较少
只有:"pre"和"post"两个。  
  pre:这种过滤器在请求被路由之前调用。我们可利用这种过滤器实现身份验证、在集群中选择请求的微服务、记录调试信息等。
  post:这种过滤器在路由到微服务以后执行。这种过滤器可用来为响应添加标准的 HTTPHeader、收集统计信息和指标、将响应从微服务发送给客户端等。
 
SpringCloudGateway的过滤器类型有两种:

  GatewayFilter:应用到单个路由或者一个分组的路由上
  GlobalFilter:应用到所有的路由上。

 

我们可以通过GlobalFilter类来实现统一鉴权:

开发中的鉴权逻辑:
    1.当客户端第一次请求服务时,服务端对用户进行信息认证(登录)
    2.认证通过,将用户信息进行加密形成token,返回给客户端,作为登录凭证
    3.以后每次请求,客户端都携带认证的token
    4.服务端对token进行解密,判断是否有效。

 

 

 

代码实现:

package com.kerry.gateway.filter;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;


/*
* 该类为用户登录权监过滤器  todo后期将token参数改到session或者是redis中。
* 目前的代码效果为:当请求链接来到网关的时候会判断请求参数中是否有token参数,如果无的话则视为没有权限,如果有则视为有权限
* 例子:
*    http://localhost:8001/admin/category/demo.do/1            效果:访问失败
*    http://localhost:8001/admin/category/demo.do/1?token=1    效果:访问成功
* */
@Slf4j
@Component
public class LoginFilter implements GlobalFilter, Ordered {



    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("执行了自定义的登录权监全局过滤器");
        //String url = exchange.getRequest().getURI().getPath();
        // 忽略以下url请求
        // if(url.indexOf("/login") >= 0){
          // return chain.filter(exchange);
        // }
        String token = exchange.getRequest().getQueryParams().getFirst("token");
        if (StringUtils.isBlank(token)) {
            log.info( "token is empty ..." );
            exchange.getResponse().setStatusCode( HttpStatus.UNAUTHORIZED );
            return exchange.getResponse().setComplete();
        }
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return 0;
    }
}

 


学习小记:

 
SpringCloud Gateway底层使用的web框架是webflux和SpringMVC不兼容引入的限流组件是hystrix。redis底层不再使用jedis,而是lettuce。

由于SpringCloud Gateway在SpringCloud上是主场作战,所以在进行网关上的使用上相对于ZUUL等其他技术上更为简单有效。它是基于Nttey的响应式开发模式

 

SpringCloud Gateway的核心概念有路由(route)断言(predicates)过滤器(filter)

 

Gateway的路由功能上很强大,支持各种各样的条件匹配同时也支持动态路由【动态路由需引入Eureka服务】。

 

Gateway在过滤器的功能上比不上ZUUL那么丰富,只要'pre'和'post'。一个是请求被路由之前调用,一个是路由到微服务之后调用。

过滤器的类型有GatewayFilter(局部)和 GlobalFilter(全局)。全局过滤器较为常用,可作用于用户信息认证校验token。

 

SpringCloud Gateway过滤器不止可以用作用户信息校验,还可以作为网关限流

限流算法:计数器、漏桶算法、令牌桶算法
      计算器算法:规定时间内只能访问到最大阈值,到时间会重置累计数重新增加
      漏桶算法:这个算法跟线程池隔离类似,规定一个容量池的大小,限制住访问量
      令牌桶算法:是漏桶算法的一种改进更好的控制访问量的灵活度。

网关限流中
   1.基于Filter的限流,是Gateway官方提供的基于令牌桶的限流法,需要引入
      redis依赖,在配置中可以调整令牌桶的容量与数度还有对象来源
   2.基于Sentinel的限流,也是需要引入依赖,编写配置类,网关配置。基于Sentinel
      的Gateway限流底层也是依靠Filter功能,只需要在配置类中注入实例定义好限流方法
      即可实习限流功能。

在分布式架构体系中,高可用是非常关键的存在。网关统一了服务的对外访问。那如
果说是单一的网关服务万一宕机,那对整个项目的影响是巨大的。所以我们应该
对网关也进行高可用的部署。然后将网关交给nginx进行统一管理,还能进行负载均衡
这样就可以大大的降低网关服务层的错误率。

 

 

posted @ 2022-04-20 09:53  _kerry  阅读(106)  评论(0编辑  收藏  举报