Spring Cloud (七):API 网关

在微服务架构中,不同服务有不同的地址,客户端需要和多个服务交互,这会带来一些问题

  • 客户端需要多次请求不同的微服务,增加复杂性
  • 存在跨域请求
  • 每个微服务都有独立认证
  • 微服务重构时,客户端也要跟着改

API 网关就是客户端和服务端的中间层,所有请求都会先经过 API 网关,再由 API 网关发给后端的微服务

使用了 API 网关后可以做统一的登录、认证、监控、日志、限流、负载均衡、转发,简化了前后端的交互和开发

API 网关有 nginx,kong,zuul,Spring Cloud Gateway,F5 等




zuul

zuul 是 Netflix 开源的微服务网关组件,它可以和 Eureka、Robbin、Hystrix 等组件配合使用

zuul 的功能

  • 认证和安全
  • 预警和监控
  • 动态路由
  • 压力测试
  • 负载均衡
  • 静态处理
  • 多区域弹性

启动 zuul 的代码如下

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
        </dependency>
@SpringBootApplication
@EnableZuulProxy
public class ZuulServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ZuulServerApplication.class, args);
    }
}
server:
  port: 9000

zuul:
  prefix: /api   # 访问网关路径的前缀
  routes:
    service-01:                       # 服务的名字,可以是任意名字,不会出现在 zuul 的 url 中
      path: /product-service/**       # 将服务的这个 path,映射到下面的 URL,或是 service id (如果使用了 Consul 或 Eureka)
      url: http://localhost:8501      # 比如 zuul-host:zuul-port/api/product-service/product/1 会被映射成 http://localhost:8501/product/1
      # service-id: consul-service-1
    service-02:
      path: /hello-service/**
      url: http://localhost:8505
      # service-id: consul-service-1
  retryable: true

访问 http://localhost:9000/api/product-service/product/1
实际上会被转发到 http://localhost:8501/product/1


Spring Cloud Gateway

zuul 有版本 1 和版本 2,spring cloud 集成的是版本 1,后续可能不会再改,而是推出 Spring Cloud Gateway

Spring Cloud Gateway 是基于 WebFlux 框架实现的,而 WebFlux 框架底层则使用了高性能的 Reactor 模式通信框架 Netty

Spring Cloud Gateway 的特性 (https://github.com/spring-cloud/spring-cloud-gateway)

  • 基于Spring 5, Spring Boot 2 and Project Reactor
  • 动态路由
  • 基于 HTTP 请求的任意属性(Path, Method, Header, Host, etc…)做路由匹配
  • Filters 作用于匹配路由
  • Filters 可以修改 HTTP 请求和响应
  • 支持 Spring Cloud DiscoveryClient
  • 支持负载均衡、限流熔断等功能

spring cloud gateway 的匹配机制比较强大,启动 spring cloud gateway 的代码如下

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>

注意需要移除 spring-boot-starter-web,并且如果有一些 dependency 间接依赖 spring-boot-starter-web,那么需要通过 exclude 排除掉,不然会报错:Consider defining a bean of type 'org.springframework.http.codec.ServerCodecConfigurer' in your configuration.

如果用到了 hystrix 的容错功能,那么还要把 hystrix 的依赖添加上

@SpringBootApplication
public class SpringCloudGatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringCloudGatewayApplication.class, args);
    }
}
server:
  port: 9000

spring:
  cloud:
    gateway:
      routes:
      - id: service-01               ## 每个路由的 id,任意名字,不会出现在 url 中
        uri: http://localhost:8501   ## 和这个路由匹配的请求都转发到 http://localhost:8501
        order: 0                     ## 优先级,一个请求有可能和多个路由匹配,会执行高优先级的路由
          
        predicates:                  ## 谓词,满足下面列举的条件的请求,就和这个路由匹配上
        - Path=/product-service/**   ## 匹配 url 为 /product-service/** 的请求
                                     ## 即 gateway-host:gateway-port/product-service/** 会被转发到 http://localhost:8501/**
          
        filters:                     ## 过滤,对请求做一些处理(下面这里是两个过滤器)
        - StripPrefix=1              ## 第一个过滤器:截断路径中的第一个字段,比如 /test/abc 变成 /abc
        - name: Hystrix              ## 第二个过滤器:通过 Hystrix 做熔断
          args:
            name: fallbackCmdA  
            fallbackUri: forward:/fallbackA    ## 将 forward 服务的 fallbackA 路径的输出作为熔断的返回

hystrix:
  command:
    fallbackCmdA:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 5000

也可以通过代码实现这些配置功能

spring cloud gateway 的配置功能很强,下面再举一些例子

# 请求中包含 id 参数的即可匹配路由,比如
# localhost:9000?id=2
predicates:
- Query=id
# 请求中包含 id 参数,且 id 参数以 abc 开头的即可匹配路由,比如
# localhost:9000?id=abc123
# 注意这里的 abc. 是正则表达式
predicates:
- Query=id, abc.
# 请求的 header 中包含 X-Request-Id 参数,且参数的值是数字,即可匹配路由,比如
# curl -H "X-Request-Id:88" localhost:9000
predicates:
- Header=X-Request-Id, d+
# 请求的 cookie 中包含 sessionId,且值为 test,即可匹配路由,比如
# curl --cookie "sessionId=test" localhost:9000
predicates:
- Cookie=sessionId, test
# GET 请求即可匹配路由
predicates:
- Method=GET
# 请求的路径满足要求,即可匹配路由,比如
# curl localhost:9000/foo/1
# curl localhost:9000/foo/test
predicates:
- Path=/foo/{segment}
# 请求的远程地址满足要求即可匹配路由
predicates:
- RemoteAddr=192.168.1.1/24
# 可以组合使用
predicates:
- Path=/product-service
- Method=GET
- Query=id

Spring Cloud Gateway 的功能配置比 zuul 要多


nginx

nginx 的作用

  • 负载均衡
  • 地址映射和端口映射
  • 静态文件支持、伪静态
  • 缓存静态和伪静态页面
  • 缓冲请求和响应
  • 高可用性,高并发抗压能力,都比较强
  • 访问控制、限速等功能

安装 Nginx

sudo apt-get install nginx

Nginx 配置

/etc/nginx/nginx.conf

这个配置文件会引入下面两个目录的配置文件

include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;

创建 /etc/nginx/conf.d/test.conf (配置文件可以有多个)

server {
    listen       80;
    server_name  localhost;

    # location 的 URL 匹配语法
    # ~* 表示正则表达式,不区分大小写
    # ~  表示正则表达式,要区分大小写
    # =  表示精确匹配
    # 没有修饰符的,以指定模式开始,比如 location / 匹配所有以 / 开始的 URL

    # 静态页面,直接读取 html 文件
    location ~* .*.html$ {
        gzip on;
        root /usr/share/nginx/html;
    }
        
    # 动态页面,转发给后端
    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

Nginx 性能强,稳定性高,适合作为全局的网关,但有的功能不具备,比如熔断等


kong

kong 是一个基于 nginx 的,用 nginx_lua 模块编写扩展插件的网关
kong 可以使用 Cassandra/PostgreSQL 数据库来存储数据

https://docs.konghq.com/install/ubuntu/

 $ sudo apt-get update
 $ sudo apt-get install -y apt-transport-https curl lsb-core
 $ echo "deb https://kong.bintray.com/kong-deb `lsb_release -sc` main" | sudo tee -a /etc/apt/sources.list
 $ curl -o bintray.key https://bintray.com/user/downloadSubjectPublicKey?username=bintray
 $ sudo apt-key add bintray.key
 $ sudo apt-get update
 $ sudo apt-get install -y kong

配置文件

cp /etc/kong/kong.conf.default /etc/kong/kong.conf

如果配置数据库

CREATE USER kong;
CREATE DATABASE kong OWNER kong;
kong migrations bootstrap [-c /etc/kong/kong.conf]

如果不配置数据库

## 会在当前路径生成 kong.yml
kong config init
## 在 kong.conf 文件里把数据库选项关掉
database = off
declarative_config = /path/to/kong.yml

启动 kong

kong start [-c /etc/kong/kong.conf] [--nginx-conf /path/to/custom_nginx.template]

kong 默认监听以下端口

  • 8000:监听客户端的 HTTP 请求,转发到后端服务
  • 8443:监听客户端的 HTTPS 请求,转发到后端服务,可以 disable
  • 8001:监听 Admin API HTTP 请求,用于配置 Kong
  • 8444:监听 Admin API HTTPS 请求,用于配置 Kong

可以通过向 8001 端口发送 POST 请求进行配置

重载 kong

kong reload

停止 kong

kong stop

kong 可以通过 --nginx-conf 指定 nginx 配置


F5

F5 是直接通过硬件实现,和系统及应用无关,只从网络层判断处理,性能强,缺点是成本高,配置可能比其他的复杂



原文地址:https://www.cnblogs.com/moonlight-lin/p/14226264.html