美文网首页
服务网关Zuul

服务网关Zuul

作者: 放开那个BUG | 来源:发表于2019-01-27 00:32 被阅读9次

在前面的学习中,我们使用Spring Cloud实现微服务的架构基本成型,大致是这样的:


我们使用Spring Cloud Netflix中的Eureka实现了服务注册中心以及服务注册与发现;而服务间通过Ribbon或Feign实现服务的消费以及负载均衡;为了使得服务集群更为健壮,使用Hystrix的熔断机制 来避免在微服务架构中个别服务出现异常时引起的故障蔓延。

在该架构中,我们的服务集群包括:内部服务Service A和Service B,他们都会注册与订阅服务至Eureka Server,而Open Servc时一个对外的服务,通过负载均衡公开至服务调用方。我们把焦点聚集在对外服务这块,这种实现方式是否合理,有没有更好的实现方式呢?

这种架构不足之处:

  • 首先,破坏了服务无状态特点

i.为了保证对外服务的安全性,我们需要实现对服务访问的权限控制,而开放服务的权限控制机制会贯穿并污染整个开放服务的业务逻辑,这会带来的最直接的问题是,破坏了服务集群中REST API无状态的特点。
ii.从具体开发和测试的角度来说,在工作中除了要考虑实际的业务逻辑之外,还需要额外可续对接口访问的控制处理。

  • 其实,无法直接复用既有接口

i.当我们需要对一个既有的集群内访问接口,实现外部服务访问时,我们不得不通过在原因有接口上增加校验逻辑,或者增加一个代理调用来实现权限控制,无法直接复用原有的接口。

对于上面的问题,最好的解决方法是——服务网关。

为了解决上面的问题,我们需要将权限控制这样的东西从我们的服务单元中抽离出去,而最适合这些逻辑的地方就是处于对外访问最前端的地方,我们需要一个更加强大的负载均衡器——服务网关。

服务网关是微服务架构中不可或缺的的部分。通过服务网关统一向外系统提供REST API的过程中,除了具备服务路由、负载均衡之外,它还具备了权限控制等功能。Spring Cloud NetFlix中的Zuul就具备这样的功能。

Zuul简介

Zuul是NetFlix开源的微服务网关,它可以和Eureka、Ribbon、Hystrix等组件配合使用。Zuul的核心是一些列的过滤器,这些过滤器可以完成以下功能。

  • 身份认证与安全:识别每个资源的验证要求,并拒绝那些与要求不符合的请求。
  • 审查与监控:在边缘位置追踪有意义的数据和统计结果,从而带来精确的生产视图。
  • 动态路由:动态的将请求路由到不同的后端集群。
  • 压力测试:逐渐增加指向集群的流量,以了解性能。
  • 负载分配:为每一种负载类型分配对应容量,并弃用超出限定值的请求。
  • 静态响应处理:在边缘位置直接建立部分响应,从而避免其转发到内部集群。
  • 多区域弹性:跨越AWS Region进行请求路由,旨在实现ELB(Elastic Load Balancing)使用的多样化,以及让系统的便越更贴近系统的使用者。

Spring Cloud对Zuul进行了整合与增强。目前,Zuul使用的默认HTTP客户端是Apache HTTP Client,也可以使用使用其他的。

使用Zuul之后的架构如图所示:


从图中可以看出,客户端请求微服务时,先经过Zuul之后再请求,这样就可以将一些类似于校验的业务逻辑放到zuul中去完成,而微服务本身只需要关注自己的业务逻辑即可。

快速使用

首先新建一个gateway模块,并且导入相关的依赖

         <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zuul</artifactId>
        </dependency>
    </dependencies>

    <!-- 导入Spring Cloud的依赖管理 -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

然后再编写启动类增加@EnableZuulProxy注解。

接着编写application.yml文件,并添加路由规则

server:
  port: 6677 #服务端口

spring: 
  application:  
    name: itcasst-microservice-api-gateway #指定服务名

zuul: 
  routes: 
    item-service: #item-service这个名字是任意写的
      path: /item-service/** #配置请求URL的请求规则
      url: http://127.0.0.1:8081 #真正的微服务地址

然后启动测试,发现可以通过zuul访问到商品微服务地址


面向服务的路由

在上面的配置中,我们通过路由规则的配置,访问到了商品微服务。但是如果商品微服务的地址发生变化,我们要修改配置问题。所以,我们应该通过走Eureka注册中心来获取地址。首先,我们需要添加Eureka依赖。

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>com.fasterxml.jackson.dataformat</groupId>
                    <artifactId>jackson-dataformat-xml</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

然后修改application.yml配置文件,将自己注册到注册中心。


随后,通过测试发现可以通过zuul访问商品微服务,一切正常。

Zuul 配置详解

指定服务id

忽略指定服务

忽略所有服务,只是又路由指定

同时配置path和url

面向服务配置,不破坏Hystrix、Ribbon特性

使用正则表达式指定路由规则

路由前缀

忽略某些路径

过滤器

过滤器是Zuul的重要组件。在我们的一般的单体应用中,也会使用过滤器过滤请求,或者完成相关的权限配置等,例如shiro框架就是用过滤器管理权限的。Zuul中的过滤器名为ZuulFilter:


ZuulFilter是一个抽象类,其实现类需要实现4个方法:

1、shouldFilter:返回一个Boolean值,判断该过滤器是否需要执行。返回true执行,返回false不执行。
2、run:过滤器的具体业务逻辑。
3、filterType:返回字符串代表过滤器的类型

i.pre:请求在被路由之前执行
ii.routing:在路由请求时调用
iii.post:在routing和error过滤器之后调用
iiii.error:处理请求时发生错误调用
4、filterOrder:通过返回的int值来定义过滤器的执行顺序,数字越小优先级越高。

执行流程

过滤器的执行流程如图所示:



过滤器实战

需求:通过编写过滤器实现用户是否登录的检查
实现:通过判断请求中是否有token,如果有认为就是已经登录的,如果没有就认为时非法请求,响应401.

接下来,我们需要编写一个UserLoginZuulFilter,逻辑如下:

package com.example.gateway.filter;

import com.netflix.client.http.HttpRequest;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;

@Component   //加入到Spring容器
public class UserLoginZuulFilter extends ZuulFilter {
    @Override
    public String filterType() {
        return "pre";  //设置过滤器类型为pre
    }

    @Override
    public int filterOrder() {
        return 0;  //设置执行顺序
    }

    @Override
    public boolean shouldFilter() {
        return true;  //该过滤器需要执行
    }

    /**
     * 编写业务逻辑
     * @return
     * @throws ZuulException
     */
    @Override
    public Object run() throws ZuulException {
        RequestContext requestContext = RequestContext.getCurrentContext();
        HttpServletRequest request = requestContext.getRequest();
        String token = request.getParameter("token");
        if(StringUtils.isEmpty(token)){
            requestContext.setSendZuulResponse(false); // 过滤该请求,不对其进行路由
            requestContext.setResponseStatusCode(401); // 设置响应状态码
            return null;
        }

        return null;
    }
}

随后,我们打开浏览器进行测试,可以看到过滤器已经生效:



相关文章

网友评论

      本文标题:服务网关Zuul

      本文链接:https://www.haomeiwen.com/subject/cgptrqtx.html