springcloud之微服务zuul/GateWay组件实现

67 篇文章 0 订阅

springcloud常用组件
1、服务注册与发现:Eureka       ---由nacos替换
2、服务网关: Zuul    ---版本不更新,由
 GateWay替换
3、服务负载均衡:Ribbon
4、服务之间调用:Feign   ----
Feign是在2019就已经不再更新了,随之取代的是OpenFeign,从名字上就可以知道,它是Feign的升级版
5、服务熔断:Hystrix   ---因官网不继续维护,可以使用阿里提供的Alibaba Sentinel 轻量级的流量控制、熔断降级 Java 库
6、配置中心:config     ---如果不想自己维护,可以使用阿里云nacos作为配置中心
7、服务链路追踪:Sleuth     
8、链路日志服务:Zipkin      ---Sleuth和Zipkin一起组合使用
9、分布式事务:Seata 
 

2、zuul路由网管
主要权限验证和限流,
(1)、权限验证:这里具体用ZuulFilter实现

方法说明
filterType : filter类型,分为pre、error、post、 route
filterOrder: filter执行顺序,通过数字指定,数字越小,执行顺序越先
shouldFilter: filter是否需要执行 true执行 false 不执行
run : filter具体逻辑(上面为true那么这里就是具体执行逻辑)

filter类型说明
pre: 请求执行之前filter
route: 处理请求,进行路由
post: 请求处理完成后执行的filter
error: 出现错误时执行的filter


 

/**
 * 登录过滤器
 *记得类上加Component注解
 */
@Component
public class LoginFilter extends ZuulFilter {

    /**
     * 过滤器类型,前置过滤器
     */
    @Override
    public String filterType() {
        return PRE_TYPE;
    }

    /**
     * 过滤器顺序,越小越先执行
     */
    @Override
    public int filterOrder() {
        return 4;
    }

    /**
     * 过滤器是否生效
     * 返回true代表需要权限校验,false代表不需要用户校验即可访问
     */
    @Override
    public boolean shouldFilter() {

        //共享RequestContext,上下文对象
        RequestContext requestContext = RequestContext.getCurrentContext();
        HttpServletRequest request = requestContext.getRequest();

        System.out.println(request.getRequestURI());
        //需要权限校验URL
        if ("/apigateway/order/api/v1/order/save".equalsIgnoreCase(request.getRequestURI())) {
            return true;
        } else if ("/apigateway/order/api/v1/order/list".equalsIgnoreCase(request.getRequestURI())) {
            return true;
        } else if ("/apigateway/order/api/v1/order/find".equalsIgnoreCase(request.getRequestURI())) {
            return true;
        }
        return false;
    }

    /**
     * 业务逻辑
     * 只有上面返回true的时候,才会进入到该方法
     */
    @Override
    public Object run() throws ZuulException {

        //JWT
        RequestContext requestContext = RequestContext.getCurrentContext();
        HttpServletRequest request = requestContext.getRequest();

        //token对象,有可能在请求头传递过来,也有可能是通过参数传过来,实际开发一般都是请求头方式
        String token = request.getHeader("token");

        if (StringUtils.isBlank((token))) {
            token = request.getParameter("token");
        }
        System.out.println("页面传来的token值为:" + token);
        //登录校验逻辑  如果token为null,则直接返回客户端,而不进行下一步接口调用
        if (StringUtils.isBlank(token)) {
            // 过滤该请求,不对其进行路由
            requestContext.setSendZuulResponse(false);
            //返回错误代码
            requestContext.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
        }
        return null;
    }
}


具体操作用如下代码
原文章地址:SpringCloud(8)---zuul权限校验、接口限流 - 雨点的名字 - 博客园

(2)、限流:这里采用ZuulFilter + RateLimiter(基于guava框架来做网关限流),RateLimiter是令牌桶算法

 

/**
 * 订单限流
 *其它和上面都一样,只是run()中逻辑不一样
 */
@Component
public class OrderRateLimiterFilter extends ZuulFilter {


    //每秒产生1000个令牌
    private static final RateLimiter RATE_LIMITER = RateLimiter.create(1000);

    @Override
    public String filterType() {
        return PRE_TYPE;
    }

    @Override
    public int filterOrder() {
        return -4;
    }

    @Override
    public boolean shouldFilter() {
        RequestContext requestContext = RequestContext.getCurrentContext();
        HttpServletRequest request = requestContext.getRequest();

        //只对订单接口限流
        if ("/apigateway/order/api/v1/order/save".equalsIgnoreCase(request.getRequestURI())) {
            return true;
        }
        return false;
    }

    @Override
    public Object run() throws ZuulException {
        RequestContext requestContext = RequestContext.getCurrentContext();

        //就相当于每调用一次tryAcquire()方法,令牌数量减1,当1000个用完后,那么后面进来的用户无法访问上面接口
        //当然这里只写类上面一个接口,可以这么写,实际可以在这里要加一层接口判断。
        if (!RATE_LIMITER.tryAcquire()) {
            requestContext.setSendZuulResponse(false);
            //HttpStatus.TOO_MANY_REQUESTS.value()里面有静态代码常量
            requestContext.setResponseStatusCode(HttpStatus.TOO_MANY_REQUESTS.value());
        }
        return null;
    }
}

文章来源:SpringCloud(8)---zuul权限校验、接口限流 - 雨点的名字 - 博客园

GateWay

Spring Cloud GateWay是Spring Cloud的⼀个全新项⽬,⽬标是取代Netflix Zuul,它基于Spring5.0+SpringBoot2.0+WebFlux(基于⾼性能的Reactor模式响应式通信框架Netty,异步⾮阻塞模型)等技术开发,性能⾼于Zuul,官⽅测试,GateWay是Zuul的1.6倍,旨在为微服务架构提供⼀种简单有效的统⼀的API路由管理⽅式。

Spring Cloud GateWay不仅提供统⼀的路由⽅式(反向代理)并且基于 Filter(定义过滤器对请求过滤,完成⼀些功能) 链的⽅式提供了⽹关基本的功能,例如:鉴权、流量控制、熔断、路径重写、⽇志监控等。

网关应当具备以下功能:

  • 性能:API高可用,负载均衡,容错机制。跟Ribbon一起做负载均衡
  • 安全:权限身份认证、脱敏,流量清洗,后端签名(保证全链路可信调用),黑名单(非法调用的限制)。
  • 日志:日志记录(spainid,traceid)一旦涉及分布式,全链路跟踪必不可少。
  • 缓存:数据缓存。
  • 监控:记录请求响应数据,api耗时分析,性能监控。
  • 限流:流量控制,错峰流控,可以定义多种限流规则。
  • 灰度:线上灰度部署,可以减小风险。
  • 路由:动态路由规则

Zuul1.x 阻塞式IO 2.x 基于Netty
Spring Cloud GateWay天⽣就是异步⾮阻塞的,基于Reactor模型;

⼀个请求—>⽹关根据⼀定的条件匹配—匹配成功之后可以将请求转发到指定的服务
地址;⽽在这个过程中,我们可以进⾏⼀些⽐较具体的控制(限流、⽇志、⿊⽩名
单)

路由(route): ⽹关最基础的部分,也是⽹关⽐较基础的⼯作单元。路由由⼀个ID、⼀个⽬标URL(最终路由到的地址)、⼀系列的断⾔(匹配条件判断)和Filter过滤器(精细化控制)组成。如果断⾔为true,则匹配该路由。

断⾔(predicates):参考了Java8中的断⾔java.util.function.Predicate,开发⼈员可以匹配Http请求中的所有内容(包括请求头、请求参数等)(类似于nginx中的location匹配⼀样),如果断⾔与请求相匹配则路由。

过滤器(filter):⼀个标准的Spring webFilter,使⽤过滤器,可以在请求之前
或者之后执⾏业务逻辑。

Predicates断⾔就是我们的匹配条件,⽽Filter就可以理解为⼀个⽆所不能的拦截器,有了这两个元素,结合⽬标URL,就可以实现⼀个具体的路由转发。

gateway工作流程(原理)

 

① 路由判断;客户端的请求到达网关后,先经过 Gateway Handler Mapping 处理,这里面会做断言(Predicate)判断,看下符合哪个路由规则,这个路由映射后端的某个服务。

② 请求过滤:然后请求到达 Gateway Web Handler,这里面有很多过滤器,组成过滤器链(Filter Chain),这些过滤器可以对请求进行拦截和修改,比如添加请求头、参数校验等等,有点像净化污水。然后将请求转发到实际的后端服务。这些过滤器逻辑上可以称作 Pre-Filters,Pre 可以理解为“在...之前”。

③ 服务处理:后端服务会对请求进行处理。

④ 响应过滤:后端处理完结果后,返回给 Gateway 的过滤器再次做处理,逻辑上可以称作 Post-Filters,Post 可以理解为“在...之后”。

⑤ 响应返回:响应经过过滤处理后,返回给客户端。

小结:客户端的请求先通过匹配规则找到合适的路由,就能映射到具体的服务。然后请求经过过滤器处理后转发给具体的服务,服务处理后,再次经过过滤器处理,最后返回给客户端。

限流:Redis RateLimiter

需要引用 spring-boot-starter-data-redis-reactive

这个逻辑使用令牌桶算法

  • redis-rate-limiter.replenishRate : 允许用户每秒处理多少个请求。这是令牌桶被填充的速率。
  • redis-rate-limiter.burstCapacity : 用户在一秒钟内允许执行的最大请求数。这是令牌桶可以容纳的令牌数量。将此值设置为0将阻塞所有请求。

一个稳定的速率是通过将replenishRate 和 burstCapacity设为相同的值来实现的。也可以将burstCapacity设得比replenishRate大,以应对临时爆发的流量。在这种情况下,需要允许速率限制器在突发事件之间间隔一段时间,因为连续两次突发事件将导致丢弃请求(HTTP 429 - Too Many Requests)

application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: requestratelimiter_route
        uri: https://example.org
        filters:
        - name: RequestRateLimiter
          args:
            redis-rate-limiter.replenishRate: 10
            redis-rate-limiter.burstCapacity: 20

Spring Cloud 使用 GateWay 作为服务网关_今晚就不加班!-CSDN博客
微服务网关 Spring Cloud Gateway - 废物大师兄 - 博客园


Zuul和GateWay区别

Zuul:

使用的是阻塞式的 API,不支持长连接,比如 websockets。

底层是servlet,Zuul处理的是http请求

没有提供异步支持,流控等均由hystrix支持。

依赖包spring-cloud-starter-netflix-zuul。

Gateway:

Spring Boot和Spring Webflux提供的Netty底层环境,不能和传统的Servlet容器一起使用,也不能打包成一个WAR包。

依赖spring-boot-starter-webflux和/ spring-cloud-starter-gateway

提供了异步支持,提供了抽象负载均衡,提供了抽象流控,并默认实现了RedisRateLimiter。

二、相同点:

1、底层都是servlet

2、两者均是web网关,处理的是http请求

三、不同点:

1、内部实现:

  gateway对比zuul多依赖了spring-webflux,在spring的支持下,功能更强大,内部实现了限流、负载均衡等,扩展性也更强,但同时也限制了仅适合于Spring Cloud套件
  zuul则可以扩展至其他微服务框架中,其内部没有实现限流、负载均衡等。
2、是否支持异步
  zuul仅支持同步
  gateway支持异步。理论上gateway则更适合于提高系统吞吐量(但不一定能有更好的性能),最终性能还需要通过严密的压测来决定
3、框架设计的角度
  gateway具有更好的扩展性,并且其已经发布了2.0.0的RELESE版本,稳定性也是非常好的
4、性能
  WebFlux 模块的名称是 spring-webflux,名称中的 Flux 来源于 Reactor 中的类 Flux。Spring webflux 有一个全新的非堵塞的函数式 Reactive Web 框架,可以用来构建异步的、非堵塞的、事件驱动的服务,在伸缩性方面表现非常好。使用非阻塞API。 Websockets得到支持,并且由于它与Spring紧密集成,所以将会是一个更好的 开发 体验。
  Zuul 1.x,是一个基于阻塞io的API Gateway。Zuul已经发布了Zuul 2.x,基于Netty,也是非阻塞的,支持长连接,但Spring Cloud暂时还没有整合计划。



下一篇文章介绍漏桶算法和令牌桶算法区别

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值