Spring Cloud Zuul 基础搭建

简介: 通过前几篇文章的介绍,我们了解了Spring Cloud Eureka 如何搭建注册中心,Spring Cloud Ribbon 如何做负载均衡,Spring Cloud Hystrix 断路器如何保护我们的服务,以防止雪崩效应的出现,Spring Cloud Feign进行声明式服务调用都有哪些应用,相比Ribbon和Hystrix都有哪些改善。可以说,以上几个组件都是搭建一套微服务架构所必须的。通过以上思路,能够梳理出下面这种基础架构:

Spring Cloud Zuul API服务网关一、Zuul 介绍二、构建Spring Cloud Zuul网关构建网关请求路由传统路由方式面向服务的路由请求过滤

一、Zuul 介绍

通过前几篇文章的介绍,我们了解了Spring Cloud Eureka 如何搭建注册中心,Spring Cloud Ribbon 如何做负载均衡,Spring Cloud Hystrix 断路器如何保护我们的服务,以防止雪崩效应的出现,Spring Cloud Feign进行声明式服务调用都有哪些应用,相比Ribbon和Hystrix都有哪些改善。可以说,以上几个组件都是搭建一套微服务架构所必须的。通过以上思路,能够梳理出下面这种基础架构:

27.jpg


无服务网关的架构图

在此架构中,我们的服务集群是内部ServiceAServiceB,他们都会向Eureka Server集群进行注册与订阅服务。而OpenService是一个对外的Restful API 服务,它通过F5,Nginx等网络设备或工具软件实现对各个微服务的路由与负载,公开给外部客户端调用

那么上述的架构存在什么问题呢?从运维的角度来看,当客户端单机某个功能的时候往往会发出一些请求到后端,这些请求通过F5,Nginx等设施的路由和负载均衡分配后,被转发到各个不同的实例上,而为了让这些设施能够正确的路由与分发请求,运维人员需要手动维护这些实例列表,当系统规模增大的时候,这些看似简单的维护回变得越来越不可取。从开发的角度来看,为了保证服务的安全性,我们需要在调用内部接口的时候,加一层过滤的功能,比如权限的校验,用户登陆状态的校验等;同时为了防止客户端在请求时被篡改等安全方面的考虑,还会有一些签名机制的存在。

正是由于上述架构存在的问题,API网关被提出,API网关更像是一个智能的应用服务器,它的定义类似于设计模式中的外观模式,它就像是一个门面的角色,结婚时候女方亲属堵门时候的角色,我去参加婚礼当伴郎的时候去村子里面见新娘,女方亲属会把鞋子藏起来,有可能藏在屋子里有可能藏在身上,这得需要你自己去寻找,找到了鞋子之后,你才能够给新娘穿上才能正式的会见家长。API网关真正实现的功能有请求路由负载均衡校验过滤请求转发的熔断机制服务的聚合等一系列功能。

Spring Cloud Zuul通过与Spring Cloud Euerka进行整合,将自身注册为Eureka服务治理下的应用,同时从Eureka中获得了所有的微服务的实例信息。者可以通过使用Zuul来创建各种校验过滤器,然后指定哪些规则的请求需要执行校验逻辑,只有通过校验的才会被路由到具体的微服务接口。下面我们就来搭建一下Spring Cloud Zuul服务网关

二、构建Spring Cloud Zuul网关

下面我们就来实际搭建一下Zuul网关,来体会一下网关实际的用处

构建网关

在实现各种API网关服务的高级功能之前,我们先来启动一下前几章搭建好的服务server-providerfeign-consumereureka-server,虽然之前我们一直将feign-consumer视为消费者,但是在实际情况下,每个服务既时服务消费者,也是服务提供者,之前我们访问的http://localhost:9001/feign-consumer等一系列接口就是它提供的服务。这里就来介绍一下详细的构建过程

  • 创建一个Spring Boot功能,命名为api-gateway,并在Pom.xml文件中引入如下内容
<?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">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.3.7.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.api.gateway</groupId>
    <artifactId>api-gateway</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>api-gateway</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zuul</artifactId>
            <version>1.3.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Brixton.SR5</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

对于spring-cloud-starter-zuul 依赖,可以通过查看依赖配置了解到,它不仅包含了Netflix Zuul的核心依赖zuul-core,还包括了下面这些网关的重要依赖

28.jpg


  • spring-cloud-starter-hystrix: 该依赖用在网关服务中实现对微服务转发时候的保护机制,通过线程隔离和断路器,防止因为微服务故障引发的雪崩效应
  • spring-cloud-starter-ribbon: 该依赖用在实现网关服务进行负载均衡和请求重试
  • spring-cloud-starter-actuactor: 该依赖用来提供常规的微服务管理端点。另外,Spring Cloud Zuul 中还特别提供了/routes端点来返回当前的路由规则
  • 在ApiGatewayApplication 主入口中添加@EnableZuulProxy注解开启服务网关功能
@EnableZuulProxy

@SpringBootApplication
public class ApiGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(ApiGatewayApplication.class, args);
}
}
  • 在application.properties 中配置Zuul应用的基础信息,包括应用名,端口号,具体如下
spring.application.name=api-gateway
server.port=5555

请求路由

下面,我们通过一个简单的示例来为上面构建的网关增加请求路由的功能,为了演示请求路由的功能,我们先将之前的Eureka服务注册中心和微服务应用都启动起来。观察下面的服务列表,可以看到两个微服务应用已经注册成功了

29.jpg

传统路由方式

使用Spring Cloud Zuul实现路由功能非常简单,只需要对api-gateway服务增加一些关于路由的配置规则,就能实现传统路由方式

zuul.routes.api-a-url.path=/api-a-url/**
# 映射具体的url路径
zuul.routes.api-a-url.url=http://localhost:8080/

该配置定义了发往API网关服务的请求中,所有符合/api-a-url/** 规则的访问都将被路由转发到 http://localhost:8080 的地址上,也就是说,当我们访问http://localhost:5555/api-a-url/hello 的时候,API网关服务会将该请求路由到http://localhost:8080/hello 提供的微服务接口中。其中,配置属性zuul.routes.api-a-url.path 中的api-a-url部分为路由的名字,可以任意定义,但是一组path和url映射关系的路由名要相同

面向服务的路由

很显然,传统的配置方式对我们来说并不友好,他同样需要运维人员花费大量的时间维护各个路由path 和url的关系。为了解决这个问题,Spring Cloud Zuul实现了与Spring Cloud Eureka的无缝衔接,我们可以让路由的path不是映射具体的url,而是让它映射到具体的服务,而具体的url则交给Eureka的服务发现机制去自动维护

  • 为了实现与Eureka的整合,我们需要在api-gateway的pom.xml中引入spring-cloud-starter-eureka依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
  • 在api-gateway服务中对应的application.properties文件中加入如下代码
zuul.routes.api-a.path=/api-a/**
zuul.routes.api-a.serviceId=server-provider
zuul.routes.api-b.path=/api-b/**
zuul.routes.api-b.serviceId=feign-consumer
eureka.client.service-url.defaultZone=http://localhost:1111/eureka/

针对我们之前准备的两个微服务应用server-providerfeign-consumer,在上面的配置中分别定义了api-a 和 api-b 的路由来映射它们。然后这个api-gateway的默认注册中心是默认注册中心地址

  • 完成上述配置后,我们可以将四个服务启动起来,分别是eureka-server, server-provider, feign-consumer, api-gateway服务,启动完毕,会在eureka-server信息面板中看到多了一个api-gateway网关服务。

30.jpg

  • http://localhost:5555/api-a/hello: 这个接口符合 /api-a/的规则,由api-a 路由负责转发,该路由映射的serviceId 为 server-provider,所以最终/hello请求会被发送到server-provider服务的某个实例上去
  • http://localhost:9001/api-b/feign-consumer: 这个接口符合 /api-b/的规则,由api-b 进行路由转发,实际的地址由Eureka负责映射,该路由的serviceId是feign-consumer, 所以最终 /feign-consumer 请求会被路由到 feign-consumer 服务上。

请求过滤

在实现了请求路由功能之后,我们的微服务应用提供的接口就可以通过统一的API网关入口被客户端访问到了,但是,每个客户端用户请求微服务应用提供的接口时,它们的访问权限往往都有一定限制。为了实现客户端请求的安全校验和权限控制,最简单和粗暴的方法就是为每个微服务应用都实现一套用于校验签名和鉴别权限的过滤器或拦截器。但是,这样的方法并不可取,因为同一个系统中会有很多校验逻辑相同的情况,最好的方法是将这些校验逻辑剥离出去,构成一个独立的服务。

对于上面这种问题,更好的做法是通过前置的网关服务来完成非业务性质的校验。为了在API网关中实现对客户端请求的校验,我们将继续介绍Spring Cloud Zuul的另外一个核心功能:请求过滤,实现方法比较简单,我们只需要继承ZuulFilter抽象类并实现它定义的4个抽象函数即可

下面的代码定义了一个简单的Zuul过滤器,它实现了在请求被路由之前检查HttpServletRequest中是否带有accessToken参数

public class AccessFilter extends ZuulFilter {
private static Logger log = LoggerFactory.getLogger(AccessFilter.class);
/**
* 过滤器的执行时序
* @return
*/
@Override
public String filterType() {
return "pre";
}
/**
* 过滤器的执行顺序
* @return
*/
@Override
public int filterOrder() {
return 0;
}
/**
* 判断过滤器是否应该执行
* @return
*/
@Override
public boolean shouldFilter() {
return true;
}
/**
* 过滤器的具体执行逻辑
* @return
*/
@Override
public Object run() {
RequestContext rc = RequestContext.getCurrentContext();
HttpServletRequest request = rc.getRequest();
log.info("send {} request to {}", request.getMethod(),request.getRequestURL().toString());
String accessToken = request.getParameter("accessToken");
if(null == accessToken){
log.warn("access token is null");
rc.setResponseStatusCode(401);
rc.setSendZuulResponse(false);
}
log.info("access token ok");
return null;
}
}

在上面实现的过滤器代码中,我们通过继承ZuulFilter 抽象类并重写了四个方法

  • filterType : 过滤器类型,它决定过滤器的请求在哪个生命周期中执行,这里定义为pre,意思是在请求前执行
  • filterOrder : 过滤器的执行顺序,当请求在一个阶段存在多个过滤器时,需要根据方法的返回值来判断过滤器的执行顺序
  • shouldFilter: 过滤器是否需要执行,这里直接返回true,因为该过滤器对所有的请求都生效
  • run: 过滤器的具体逻辑,这里我们通过rc.setResponseStatusCode(401)设置失效的标志,rc.setSendZuulResponse(false)令Zuul过滤该请求

在实现了自定义过滤器之后,它并不会直接生效,我们还需要为其创建具体的Bean才能启动该过滤器。

@EnableZuulProxy
@SpringBootApplication
public class ApiGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(ApiGatewayApplication.class, args);
}
@Bean
public AccessFilter filter(){
return new AccessFilter();
}
}

在对api-gateway服务完成了上面的改造之后,我们可以重新启动它,并发起下面的请求,对上面的过滤器做一个验证

  • 输入 http://localhost:5555/api-a/hello : 返回 401错误
  • 输入 http://localhost:5555/api-a/hello?accessToken=token,正确路由到server-provider的/hello 接口,并返回Hello World。

到这里,对于API网关的快速入门示例就搭建完成了,通过对Spring Cloud Zuul 网关的搭建,我们能认知到网关的重要性,可以总结如下:

  • 它作为系统的统一入口, 屏蔽了系统内部各个微服务的细节。
  • 它可以与服务治理框架结合,实现自动化的服务实例维护以及负载均衡的路由转发。
  • 它可以实现接口权限校验与微服务业务逻辑的解耦。
  • 通过服务网关中的过滤器, 在各生命周期中去校验请求的内容, 将原本在对外服务层做的校验前移, 保证了微服务的无状态性, 同时降低了微服务的测试难度, 让服务本身更集中关注业务逻辑的处理。


            </div>
目录
相关文章
|
4月前
|
负载均衡 Java API
|
9月前
|
JSON 监控 安全
SpringCloud极简入门-服务网关-spring cloud zuul
为什么要zuul 试想一下如果我们有很多的微服务,他们都需要登录之后才能访问,那么我需要在每个微服务都去做一套登录检查逻辑,这样是不是会存在大量重复的代码和工作量,我们希望的是把登录检查这种公共的逻辑进行统一的抽取,只需要做一套检查逻辑即可,而zuul就可以用来干这类事情,我们可以把zuul看做是微服务的大门,所有的请求都需要通过zuul将请求分发到其他微服务,根据这一特性我们就可以在zuul做统一的登录检查,下游的微服务不再处理登录检查逻辑。
124 0
|
10月前
|
缓存 负载均衡 安全
Spring Cloud 之 Zuul
Spring Cloud 之 Zuul
151 0
|
11月前
|
监控 负载均衡 Java
Spring Cloud【Finchley】-14 微服务网关Zuul的搭建与使用
Spring Cloud【Finchley】-14 微服务网关Zuul的搭建与使用
205 0
|
运维 负载均衡 安全
Spring Cloud Zuul 基础搭建
通过前几篇文章的介绍,我们了解了Spring Cloud Eureka 如何搭建注册中心,Spring Cloud Ribbon 如何做负载均衡,Spring Cloud Hystrix 断路器如何保护我们的服务,以防止雪崩效应的出现,Spring Cloud Feign进行声明式服务调用都有哪些应用,相比Ribbon和Hystrix都有哪些改善。可以说,以上几个组件都是搭建一套微服务架构所必须的。通过以上思路,能够梳理出下面这种基础架构:
71 0
Spring Cloud Zuul 基础搭建
|
负载均衡 安全 Java
Spring Cloud:第五章:Zuul服务网关
Spring Cloud:第五章:Zuul服务网关
125 0
|
负载均衡 监控 安全
spring cloud zuul 简介及使用(一)
Spring Cloud Zuul 是 Spring Cloud Netflix 子项目的核心组件之一,可以作为微服务架构中的 API 网关使用,支持动态路由与过滤功能
452 0
spring cloud zuul 简介及使用(一)
|
负载均衡 Java API
spring cloud zuul 简介及使用(二)
Spring Cloud Zuul 是 Spring Cloud Netflix 子项目的核心组件之一,可以作为微服务架构中的 API 网关使用,支持动态路由与过滤功能
158 0
spring cloud zuul 简介及使用(二)
|
负载均衡 Java Spring
Spring Cloud Zuul 源码解析
Spring Cloud Zuul 源码解析
1208 0
Spring Cloud Zuul 源码解析
|
Java Spring
Spring Cloud Zuul 那些你不知道的功能点
借助这个端点,可以方便、直观地查看以及管理Zuul的路由。
1783 0

热门文章

最新文章