• 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映射的方式已可以进行跳转。 
  • 相关阅读:
    iBatis——自动生成DAO层接口提供操作函数(详解)
    【Spring Boot项目】Win7+JDK8+Tomcat8环境下的War包部署
    MySQL使用小记
    DB迁移:从SQL Server 2005到MySQL
    【文章学习】监控网页卡顿、崩溃
    为什么执行x in range(y)如此之快
    python笔试题(三)
    python笔试题(二)
    python笔试题(-)
    rest-framework(2)
  • 原文地址:https://www.cnblogs.com/ooo0/p/11197210.html
Copyright © 2020-2023  润新知