Gateway+Sentinel

Gateway+Sentinel

_

简介

Gateway: Spring cloud Gateway是Spring公司基于Spring5.0,SpringBoot 2.0 和Project Reactor等技术开发的网关。它旨在为微服务架构提供一中简单有效且统一的Api路由管理方式。它的目标是代替NetflixZuul .

Sentinel: Sentinel 是面向分布式服务架构的高可用防护组件,主要以流量为切入点,从流量控制、熔断降级、系统自适应保护等多个维度来帮助用户保障微服务的稳定性。

sentinel主要特征

案例

SpringCloud + SpringCloud AliBaBa, Nacos做注册中心,Gateway网关,Sentinel熔断限流

nacos传送门

创建主项目

创建普通maven项目

删除src文件夹

<?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>

    <groupId>com.qc</groupId>
    <artifactId>iaas</artifactId>
    <packaging>pom</packaging>
    <version>1.0</version>
    <modules>
        <module>gateway-server</module>
        <module>authorization-server</module>
    </modules>


    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <spring-cloud.version>2021.0.3</spring-cloud.version>
        <cloud.alibaba.version>2021.0.1.0</cloud.alibaba.version>
        <spring.boot.version>2.7.0</spring.boot.version>
        <nacos.version>2021.1</nacos.version>
    </properties>


    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${cloud.alibaba.version}</version>
                <scope>import</scope>
                <type>pom</type>
            </dependency>

            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring.boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
                <version>${nacos.version}</version>
            </dependency>

        </dependencies>

    </dependencyManagement>


</project>

创建子Module

gateway-server authorization-server

项目结构:

项目结构

gateway-server

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">
    <parent>
        <artifactId>iaas</artifactId>
        <groupId>com.qc</groupId>
        <version>1.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>gateway-server</artifactId>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
    </properties>


    <dependencies>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>


        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
            <version>1.8.4</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
            <version>2021.1</version>
        </dependency>

        <!-- gateway 路由负载均衡支持 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
        </dependency>

        <!-- loadbalancer缓存 -->
        <dependency>
            <groupId>com.github.ben-manes.caffeine</groupId>
            <artifactId>caffeine</artifactId>
            <version>3.1.1</version>
        </dependency>


    </dependencies>

</project>

application.yml文件

server:
  port: 80
spring:
  application:
    name: gateway-server
  cloud:
    nacos:
      discovery:
        server-addr: nacos-server:8848

    gateway:
      discovery:
        locator:
          # 启用getaway网关发现功能
          enabled: true
          # 启用小驼峰的服务名称访问服务
          lower-case-service-id: true

      #路由数组
      routes:
        # 路由标识  全局唯一
        - id: authorization-server-router
          # 转发到的地址  lb表示自动负载均衡
          #authorization-server
          uri: lb://authorization-server
          # 优先级
          order: 1
          # 断言(就是路由转发需要的条件)
          predicates:
            # 当请求路径满足这个条件的时候进行转发
            - Path=/test/**
          # 过滤器  请求在转发过程中可以通过过滤器进行一定的修改
          filters:
            # 转发的时候去掉一层路径  比如前端访问/admin/login   转发的时候就成了/login
            - StripPrefix=1


    sentinel:
      transport:
        dashboard: localhost:8888


gatewayconfiguration 配置文件

package com.qc.config;

import com.alibaba.csp.sentinel.adapter.gateway.common.SentinelGatewayConstants;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiDefinition;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiPathPredicateItem;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiPredicateItem;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.GatewayApiDefinitionManager;
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule;
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayRuleManager;
import com.alibaba.csp.sentinel.adapter.gateway.sc.SentinelGatewayFilter;
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.BlockRequestHandler;
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager;
import com.alibaba.csp.sentinel.adapter.gateway.sc.exception.SentinelGatewayBlockExceptionHandler;
import com.alibaba.fastjson.JSON;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.reactive.result.view.ViewResolver;

import javax.annotation.PostConstruct;
import java.util.*;

/**
 * @author c
 * @date 2022-06-08 02:07
 */
@Configuration
public class GatewayConfiguration {

    private final List<ViewResolver> viewResolvers;
    private final ServerCodecConfigurer serverCodecConfigurer;

    public GatewayConfiguration(ObjectProvider<List<ViewResolver>> viewResolversProvider,
                                ServerCodecConfigurer serverCodecConfigurer) {
        this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
        this.serverCodecConfigurer = serverCodecConfigurer;
    }

    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
        // Register the block exception handler for Spring Cloud Gateway.
        return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
    }

    @Bean
    @Order(-1)
    public GlobalFilter sentinelGatewayFilter() {
        return new SentinelGatewayFilter();
    }

    /**
     * 配置限流规则
     */
    @PostConstruct
    private void initGatewayRules(){

        //根据路由 id 限流
//        Set<GatewayFlowRule> rules = new HashSet<>();
////        限流的路径     gateway配置的路由标识
//        rules.add(new GatewayFlowRule("authorization-server-router")
//                //限流阈值
//                .setCount(2)
//                //多长时间
//                .setIntervalSec(10));
        //加载规则
//        GatewayRuleManager.loadRules(rules);

        //根据api分组限流
        Set<GatewayFlowRule> rules = new HashSet<>();
        //对分组为test_api的分组限流策略        setCount=多少次    setIntervalSec=多少秒
        rules.add(new GatewayFlowRule("test_api").setCount(2).setIntervalSec(10));
        GatewayRuleManager.loadRules(rules);

    }

    /**
     * 自定义api分组
     */
    @PostConstruct
    public void  initCustomizedApis(){

        //创建一个集合存放具体的分组信息
        Set<ApiDefinition> definitions = new HashSet<>();

        //用户自定义的 API 定义分组
        ApiDefinition apiDefinition = new ApiDefinition("test_api");

        //分组包含的路径集合
        Set<ApiPredicateItem> apiPredicateItems = new HashSet<>();

        //创建配置那些路径匹配规则类对象
        ApiPathPredicateItem apiPathPredicateItem = new ApiPathPredicateItem();

        // /test/**这类路径根据URL_MATCH_STRATEGY_PREFIX来匹配
        apiPathPredicateItem.setPattern("/test/**").setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX);

        //添加到集合
        apiPredicateItems.add(apiPathPredicateItem);

        //添加到分组
        apiDefinition.setPredicateItems(apiPredicateItems);

        //添加到存放分组信息集合
        definitions.add(apiDefinition);

        //加载自定义api分组
        GatewayApiDefinitionManager.loadApiDefinitions(definitions);

    }


    /**
     * 限流返回信息
     */
    @PostConstruct
    public void initBlockHandlers(){
        BlockRequestHandler blockRequestHandler = (serverWebExchange, throwable) ->
                ServerResponse.status(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON).bodyValue("{" +
                        " \"msg\":\"被限流了!\" " +
                        "}");

        GatewayCallbackManager.setBlockHandler(blockRequestHandler);
    }




}

package com.qc;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

/**
 * @author c
 * @date 2022-06-06 15:14
 */
@SpringBootApplication
@EnableDiscoveryClient
public class GatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(GatewayApplication.class,args);
    }
}

authorization-server

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">
    <parent>
        <artifactId>iaas</artifactId>
        <groupId>com.qc</groupId>
        <version>1.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>authorization-server</artifactId>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
    </properties>

    <dependencies>

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

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>


    </dependencies>

</project>

application.yml配置文件

server:
  port: 8080

spring:
  application:
    name: authorization-server
  cloud:
    nacos:
      discovery:
        server-addr: nacos-server

controller

package com.qc.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author c
 * @date 2022-06-06 15:20
 */
@RestController
public class Hello {

    @RequestMapping("/hello")
    public String hello(){
        return "hello";
    }
}
package com.qc;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

/**
 * @author c
 * @date 2022-06-06 15:30
 */
@SpringBootApplication
@EnableDiscoveryClient
public class AuthorizationApplication {
    public static void main(String[] args) {
        SpringApplication.run(AuthorizationApplication.class,args);
    }
}

下载sentinel控制台(可下可不下)

下载地址:https://github.com/alibaba/Sentinel/releases

运行指令:

#官方

java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar

# 测试环境 本地装的jdk17  17不允许反射,需要额外参数--add-exports=java.base/sun.net.util=ALL-UNNAMED
java -jar --add-exports=java.base/sun.net.util=ALL-UNNAMED -Dserver.port=8888 sentinel-dashboard-1.8.4.jar

访问本地 localhost:8888

帐号密码默认都是: sentinel

sentinel控制台

结果

访问1

访问 网关 符合/test/**的请求转发到authorization-server服务去了 说明网关实现

访问2

连续访问3次以上,返回限流信息,说明sentinel限流成功。

ShardingJDBC 2022-04-22
Shiro 2022-06-09

评论区