Spring Cloud API网关服务 5.2

为什么需要API网关

  通过前面内容的学习,我们已经可以构建一个简单的微服务架构系统。这个系统可以使用Spring Boot实现微服务的开发,使用Spring Cloud Eureka实现注册中心以及服务的注册与发现,使用Spring Cloud Ribbon实现服务间的负载均衡,使用Spring Cloud Hystrix实现线程的隔离和断路器功能。通过这些技术,可以设计出如图5-11所示的基础架构。

  在图5-11中,集群包含了Service A和Service B两种服务,它们会向Eureka Server注册和订阅服务,Open Service是一个对外的RESTful API服务,客户端会通过负载均衡技术(如Nginx)实现对Open Service的调用,同时服务之间也会通过Ribbon技术实现服务之间负载均衡的调用。
虽然通过这种方式实现系统功能是没有问题的,但在实际使用时,客户端与微服务进行直接的交互还是存在着一些困难和限制的,具体表现如下。

  1. 增加开发和维护成本
  在大多数情况下,为了保证对外服务的安全性,开发人员在服务端实现的服务接口会有一定的权限校验机制(如用户登录状态校验等),并且为了防止客户端在发起请求时被篡改等安全方面的考虑,还会编写一些签名校验功能。在微服务中,我们会将原来处于一个应用中的多个模块拆分成多个应用服务,而这些拆分出来的应用服务接口也需要原来的校验逻辑,这就导致我们不得不在这些应用中全部实现这样的一套逻辑。随着微服务规模的不断扩大,这些校验逻辑的冗余将越来越多,一旦校验规则有了变化或者出了问题,我们将不得不去每一个应用中修改这些逻辑。

  2. 微服务重构困难
  随着时间的推移,我们可能需要改变系统服务目前的拆分方案(如将两个服务合并或将一个服务拆分为多个),但如果客户端直接与微服务交互,那么这种重构就很难实施。

  3. 微服务协议限制
  客户端直接请求的微服务可能使用的是与Web无关的协议。一个服务可能是用Thrift的RPC协议,而另一个服务可能是用AMQP消息协议,两种协议都不是特别适合浏览器或防火墙,最好是内部使用。应用应该在防火墙外采用HTTP或者WEBSocket之类的协议。

  由于上述原因,客户端直接与服务器端通信的方式几乎不会在实际应用中使用。那么我们要如何解决上面这些问题呢?
  通常来说,一个很好的解决办法就是采用API Gateway(网关)的方式。API Gateway是一个服务器,也可以说是进入系统的唯一节点,它封装了内部系统的架构,并且提供了API给各个客户端。它还可以有其他功能,如授权、监控、负载均衡、缓存、请求分片和管理、静态响应处理等。

 

  图5-12展示了一个适应当前架构的API Gateway。

  在图5-12中,API Gateway负责请求转发、合成和协议转换。所有来自客户端的请求都要先经过API Gateway,然后负载均衡这些请求到对应的微服务。
API Gateway的一个最大好处是封装了应用的内部结构,与调用指定的服务相比,客户端直接跟Gateway交互会更简单。API Gateway提供给每一个客户端一个特定API,这样减少了客户端与服务器端的通信次数,也简化了客户端代码。API Gateway还可以在Web协议与内部使用的非Web协议间进行转换,如HTTP协议、WebSocket协议。
  API Gateway可以有很多实现方法,如Nginx、Zuul、Node.js等。本书中使用的是Spring Cloud Netflix中的Zuul,下一小节我们将对Spring Cloud Zuul的使用进行详细讲解。

如何使用Zuul构建API网关服务

  Zuul原是Netflix公司开发的基于JVM的路由器和服务器端负载均衡器,后来被加入到了Spring Cloud中。Zuul属于边缘服务,可以用来执行认证、动态路由、服务迁移、负载均衡、安全和动态响应处理等操作。
了解了Zuul的概念和作用后,接下来通过一个具体的应用案例来讲解如何在微服务中使用Zuul。
  本案例主要涉及到3个工程,其作用分别如下。
  ·xcservice-eureka-server工程:服务注册中心,端口为8761。
  ·xcservice-eureka-order工程:服务提供者,需要启动一个订单实例,其端口号为7900。
  ·xcservice-gateway-zuul工程:使用Zuul实现的APIGateway,端口号为8050。
  上面3个工程中,注册中心和服务提供者可以使用前面所创建的工程,而网关服务需要重新创建,其实现过程如下。
  (1)创建工程,添加依赖。在父工程xcservice-spring-cloud下创建子模块xcservice-gateway-zuul工程,并在其pom.xml中添加eureka和Zuul的依赖,如文件5-8所示。
  文件5-8 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>com.xc</groupId>
        <artifactId>xcservice-springcloud</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <groupId>com.xc</groupId>
    <artifactId>xcservice-gateway-zuul</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>xcservice-gateway-zuul</name>
    <description>网关服务</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

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

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

 

  (2)编辑配置文件。在配置文件中编写Eureka服务实例的端口号、服务端地址等信息,如文件5-9所示。
  文件5-9 application.yml
server:
  port: 8050 # 指定该Eureka实例的端口号

eureka:
  instance:
    prefer-ip-address: true  # 是否显示主机的IP
    #instance-id: ${spring.cloud.client.ipAddress}:${server.port} #将Status中的显示内容也以“IP:端口号”的形式显示
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/ # 指定Eureka服务端地址

spring:
  application:
    name: xcservice-gateway-zuul # 指定应用名称

zuul:
  routes:
    order-serviceId: # zuul的唯一标识
      path: /order/**   # 需要映射的路径
      service-id: xcservice-eureka-order  # Eureka中的serviceId

  在上述配置信息中,zuul就是API网关服务的路由配置。其中order-serviceId为Zuul的唯一标识,可以任意设置名称,但必须唯一,如果该值与service-id的名称相同时,service-id的值可以省略。path属性后面的值表示需要映射的路径,service-id后面的值为Eureka中的serviceId,应用在运行时,所有符合映射路径的URL都会被转发到xcservice-eureka-order中。

  需要注意的是,Zuul的配置方式有很多,这里只是针对本案例实现的一种方式。如果读者想要了解更多的配置方式,可以参考官方文档中Zuul的配置进一步学习。


  (3)在工程主类Application中使用@EnableZuulProxy注解开启Zuul的API网关功能,其代码如文件5-10所示。
package com.xc.xcservicegatewayzuul;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;

/**
 * http://localhost:8050/xcservice-eureka-order/order/1
 */
@EnableZuulProxy
@SpringBootApplication
@EnableEurekaClient
public class XcserviceGatewayZuulApplication {

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

}

 

  (4)分别启动注册中心、服务提供者和网关服务后,注册中心已注册的服务如图5-13所示。

  此时可以通过地址http://localhost:7900/order/1单独访问订单服务
  下面通过Zuul来验证路由功能,通过网关服务来访问订单信息。在浏览器地址栏中输入地址http://localhost:8050/xcservice-eureka-order/order/1后,浏览器已经显示出来所要访问的订单信息。这说明使用Zuul配置的路由功能已经生效,通过服务ID映射的方式已可以进行跳转。 
posted @ 2019-07-16 20:16 草木物语 阅读(...) 评论(...) 编辑 收藏