MyBatis+SpringMVC+SpringBootJavaJava 杂谈

微服务网关 Spring Cloud Gateway

2019-11-04  本文已影响0人  一觉睡到丶小时候

什么是网关

假设你现在要做一个电商应用,前端是移动端的APP,后端是各种微服务。那你可能某个页面需要调用多个服务的数据来展示。如果没有网关,你的系统看起来就是这个样子的:


图片.png

而如果加上了网关,你的系统就会变成这个样子:


图片.png

Spring Cloud Gateway

Spring Cloud Gateway 是 Spring Cloud 的一个全新项目,该项目是基于 Spring 5.0,Spring Boot 2.0 和 Project Reactor 等技术开发的网关,它旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式。

Spring Cloud Gateway 作为 Spring Cloud 生态系统中的网关,目标是替代 Netflix Zuul,其不仅提供统一的路由方式,并且基于 Filter 链的方式提供了网关基本的功能,例如:安全,监控/指标,和限流。

相关概念
工作流程
gateway.png

(PS:看到这张图是不是很熟悉,没错,很像SpringMVC的请求处理过程)

简而言之:


图片.png

客户端向 Spring Cloud Gateway 发出请求。如果 Gateway Handler Mapping 中找到与请求相匹配的路由,将其发送到 Gateway Web Handler。Handler 再通过指定的过滤器链来将请求发送到我们实际的服务执行业务逻辑,然后返回。 过滤器之间用虚线分开是因为过滤器可能会在发送代理请求之前(“pre”)或之后(“post”)执行业务逻辑。

快速开始

1.新建一个项目gatewayTest,在项目中添加3个moduleeureka,producer,gateway

项目结构


图片.png
2.rureka

新建module

step1.png
step2.png
step3.png
step4.png
step5.png

添加eureka依赖

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

完整pom

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example.eureka</groupId>
    <artifactId>eureka</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>
    <name>eureka</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>com.gateway.test</groupId>
        <artifactId>gatewayTest</artifactId>
        <version>1.0-SNAPSHOT</version>
        <relativePath>..</relativePath> <!-- lookup parent from repository -->
    </parent>

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

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

</project>

配置文件

spring:
  application:
    name: eureka

server:
  port: 8761
eureka:
  instance:
    hostname: localhost
  client:
    fetch-registry: false
    register-with-eureka: false
    service-url:
      defaultZone: http://localhost:8761/eureka/

启动类

package com.example.eureka.eureka;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@EnableEurekaServer
@SpringBootApplication
public class EurekaApplication {

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

}

启动程序,访问http://localhost:8761/

图片.png
现在还没有服务进行注册
3.producer

新建producer的module,同创建rureka,不同处如下图,其他都一样。


图片.png

完整pom

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example.producer</groupId>
    <artifactId>producer</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>producer</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>com.gateway.test</groupId>
        <artifactId>gatewayTest</artifactId>
        <version>1.0-SNAPSHOT</version>
        <relativePath>..</relativePath> <!-- lookup parent from repository -->
    </parent>

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

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

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

</project>

配置文件

spring:
  application:
    name: producer
server:
  port: 8081

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/

启动类

package com.example.producer.producer;

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

@EnableEurekaClient
@SpringBootApplication
public class ProducerApplication {

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

}

新建2个类控制器

图片.png
HelloController
@RestController
@RequestMapping("/hello")
public class HelloController {

    @RequestMapping("say")
    public String say() {
        return "Hello Every Buddy";
    }
}

GoodByeController

@RestController
@RequestMapping("/goodbye")
public class GoodByeController {

    @RequestMapping("say")
    public String say() {
        return "Bye Bye";
    }
}

启动程序,访问http://localhost:8761/

图片.png
4.gateway

创建过程同eureka
完整pom

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example.gateway</groupId>
    <artifactId>gateway</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>gateway</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>com.gateway.test</groupId>
        <artifactId>gatewayTest</artifactId>
        <version>1.0-SNAPSHOT</version>
        <relativePath>..</relativePath> <!-- lookup parent from repository -->
    </parent>

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

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

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

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

</project>

配置文件

test:
  uri: lb://producer

spring:
  application:
    name: gateway
#  cloud:
#    gateway:
#      routes:
#        - id: route_producer_hello
#          uri: ${test.uri} # uri以lb://开头(lb代表从注册中心获取服务),后面接的就是你需要转发到的服务名称
#          predicates:
#            - Path=/api-hello/**
#          filters:
#            - StripPrefix=1 # 表示在转发时去掉api
#
#        - id: route_producer_goodbye
#          uri: ${test.uri}
#          predicates:
#            - Path=/api-goodbye/**
#          filters:
#            - StripPrefix=1
#            - name: Hystrix
#              args:
#                name: myfallbackcmd
#                fallbackUri: forward:/user/fallback


server:
  port: 8080

logging:
  level:
    org.springframework.cloud.gateway: TRACE
    org.springframework.http.server.reactive: DEBUG
    org.springframework.web.reactive: DEBUG
    reactor.ipc.netty: DEBUG
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
    enabled: true # 是否启用注册服务 默认为true, false是不启用
  instance:
    prefer-ip-address: true

启动类

package com.example.gateway.gateway;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class GatewayApplication {

    @Value("${test.uri}")
    private String uri;

    @Bean
    public RouteLocator routeLocator(RouteLocatorBuilder builder){
        return builder.routes()
                .route(r ->r.path("/hello/**").uri(uri))
                .route(r ->r.path("/goodbye/**").uri(uri)).build();
    }

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

}

启动程序,访问http://localhost:8761/

图片.png
5.测试

服务都已经注册到reureka,我们定义了hello和goodbye开头的请求都会转发到lb://producer服务,我们定义gateway的端口是8080,producer的端口是8081
直接请求producer服务
http://localhost:8081/hello/say

图片.png
http://localhost:8081/goodbye/say
图片.png

通过网关请求
http://localhost:8080/hello/say

hello.png
http://localhost:8080/goodbye/say
goodbye.png

网关本身的负载均衡

那所有微服务就只有一个网关,万一并发量上去了,网关承受不住怎么办?
Spring Cloud Gateway底层是Netty的,它本身就能承受比较大的并发。如果还是承受不了并发量,那可以注册多个Gateway实例,然后在前面弄一个Nginx或者F5等负载均衡器。大概图是这样:


图片.png
上一篇下一篇

猜你喜欢

热点阅读