• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

微服务二gateway网关的使用

武飞扬头像
长舒36
帮助1

目录

1:什么是网关

1.1:网关组件有哪些

 1.2:spring cloud gateway简介

2:gateway的使用

 3:进行断言

 4:负载均衡

 5:自定义网关过滤器

6:限流ratelimiter

6.1:常见的限流算法:

 6.2:限流实现

 7:灰度发布:


1:什么是网关

        是整个微服务API请求的入口,负责拦截所有请求,分发到服务上去;

        作用:分发请求、权限控制(鉴权)、限流、统一返回数据、日志拦截、缓存、灰度发布

1.1:网关组件有哪些

    • OpenResty:就是基于nginx lua脚本集成的组件,通过在不同的阶段挂在定义的lua脚本来实现自定义处理行为
    • kong:基于OpenResty编写的网关,nginx支持并大在5w左右,Nginx更适合做外部一层的网关
    • zuul:全称springbloud zuul1.x采用servlet进行通信,底层是同步io,新来一个请求就会新增一个线程,并且不会进行回收,所以占用资源,所以资源占用较高,也就意味着支持的并发量不高。虽然在zuul2.x将通信调整为了netty servlet来实现,并且支持异步,但是性能上差别不是很大
    • spring cloud gateway:gateway底层是Netty,支持的请求数在1w~1.5w左右,性能要比zuul高很多

 1.2:spring cloud gateway简介

        Spring Cloud Gateway是Spring Cloud推出的用来替代Zuul的网关产品,如同zuul综合了ribbon、hystrix的负载均衡、熔断、降级、限流能力,Spring Cloud Gateway也整合了hystrix

2:gateway的使用

        构建gateway项目不需要引入spring web依赖

        导入与springboot版本相对应的依赖:

  1.  
    <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-gateway -->
  2.  
    <dependency>
  3.  
    <groupId>org.springframework.cloud</groupId>
  4.  
    <artifactId>spring-cloud-starter-gateway</artifactId>
  5.  
    <version>3.1.1</version>
  6.  
    </dependency>

2.1:创建三个模块,一个为网关,两个为服务

        使用spring boot项目创建

学新通

 2.2:创建多个启动实例的方法

        学新通

学新通

 复制一份yml文件修改端口

学新通

 启动学新通

 这样两个启动实例就成功了

接下来我们在controller层验证一下是否可以访问成功

学新通

 访问成功学新通

 学新通

 3:进行断言

表示的意思就是通过配置规则来判断请求会分发到哪个服务上。

yml配置项

  1.  
    server:
  2.  
    port: 8083
  3.  
    spring:
  4.  
    cloud:
  5.  
    gateway:
  6.  
    discovery:
  7.  
    locator:
  8.  
    # 开启从注册中心动态创建路由的功能,利用微服务名进行路由,默认false
  9.  
    enabled: false
  10.  
    routes:
  11.  
    # 路由ID,唯一即可,一般建议服务名
  12.  
    - id: product-server
  13.  
    uri: http://localhost:9090
  14.  
    predicates:
  15.  
    - Path=/product-server/**
  16.  
    filters:
  17.  
    - StripPrefix=1
  18.  
    - id: order
  19.  
    uri: http://localhost:8080
  20.  
    predicates:
  21.  
    - Path=/order/**
  22.  
    filters:
  23.  
    # 去除路径前缀的个数
  24.  
    - StripPrefix=2
学新通

 就可以使用网关的端口访问order的端口了,这里为什么多了个”xxx“,因为配置文件中StripPrefix去除前缀的个数;如果为一的话,就可以不要”xxx“即可访问

学新通

 4:负载均衡

        负载均衡(Load Balance,简称 LB)是高并发、高可用系统必不可少的关键组件,目标是 尽力将网络流量平均分发到多个服务器上,以提高系统整体的响应速度和可用性

导入依赖:

        

  1.  
    <dependency>
  2.  
    <groupId>org.springframework.cloud</groupId>
  3.  
    <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
  4.  
    </dependency>

 yml配置文件:

  1.  
    #负载均衡
  2.  
    - id: prder-server-lb
  3.  
    uri: lb://order-server
  4.  
    #断言
  5.  
    predicates:
  6.  
    - Path=/order-lb/**
  7.  
    filters:
  8.  
    - StripPrefix=1
  9.  
    order-server:
  10.  
    ribbon:
  11.  
    #随机策略
  12.  
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
  13.  
    listOfServers: http://localhost:8080,http://localhost:8081,http://localhost:8082

 5:自定义网关过滤器

 自定义网关过滤器需要实现以下两个接口 :GatewayFilter,Ordered

新建一个filter文件夹:

  1.  
    import com.alibaba.fastjson.JSONObject;
  2.  
    import com.alibaba.fastjson.serializer.SerializerFeature;
  3.  
    import lombok.AllArgsConstructor;
  4.  
    import org.springframework.cloud.gateway.filter.GatewayFilterChain;
  5.  
    import org.springframework.cloud.gateway.filter.GlobalFilter;
  6.  
    import org.springframework.core.Ordered;
  7.  
    import org.springframework.core.io.buffer.DataBuffer;
  8.  
    import org.springframework.http.HttpStatus;
  9.  
    import org.springframework.http.server.reactive.ServerHttpResponse;
  10.  
    import org.springframework.stereotype.Component;
  11.  
    import org.springframework.util.StringUtils;
  12.  
    import org.springframework.web.server.ServerWebExchange;
  13.  
    import reactor.core.publisher.Flux;
  14.  
    import reactor.core.publisher.Mono;
  15.  
    import org.springframework.util.AntPathMatcher;
  16.  
     
  17.  
    import java.nio.charset.StandardCharsets;
  18.  
    import java.util.Arrays;
  19.  
    import java.util.List;
  20.  
     
  21.  
    /**
  22.  
    * @author lcy
  23.  
    * @version 1.0
  24.  
    * @date 2023/3/7 17:51
  25.  
    */
  26.  
    @Component
  27.  
    @AllArgsConstructor
  28.  
    public class AuthFilter implements Ordered, GlobalFilter {
  29.  
    //路径匹配器
  30.  
    private final AntPathMatcher matcher=new AntPathMatcher();
  31.  
     
  32.  
    //跳过token校验的url
  33.  
    static List<String> skipUrlList= Arrays.asList("/user-server/login/*");
  34.  
     
  35.  
    @Override
  36.  
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
  37.  
    //拿到本次响应的数据,响应体
  38.  
    ServerHttpResponse response = exchange.getResponse();
  39.  
    //请求路径
  40.  
    String path = exchange.getRequest().getURI().getPath();
  41.  
    if (isSkip(path)){
  42.  
    return chain.filter(exchange);
  43.  
    }
  44.  
    //鉴权
  45.  
    String token = exchange.getRequest().getHeaders().getFirst("Authorization");
  46.  
    if (StringUtils.isEmpty(token)){
  47.  
    return unAuth(response,"token为空");
  48.  
    }
  49.  
    //判断token是否合法
  50.  
     
  51.  
    return chain.filter(exchange);
  52.  
    }
  53.  
     
  54.  
    @Override
  55.  
    public int getOrder() {
  56.  
    return 0;
  57.  
    }
  58.  
     
  59.  
    /**
  60.  
    * 判断path是否在跳过校验的路径中
  61.  
    * @param path
  62.  
    * @return
  63.  
    */
  64.  
    private boolean isSkip(String path){
  65.  
    return skipUrlList.stream().anyMatch(pattern->matcher.match(pattern,path));
  66.  
    }
  67.  
     
  68.  
    /**
  69.  
    * 返回鉴权不通过结果
  70.  
    * @param response
  71.  
    * @param message
  72.  
    * @return
  73.  
    */
  74.  
    private Mono<Void> unAuth(ServerHttpResponse response,String message){
  75.  
    response.setStatusCode(HttpStatus.UNAUTHORIZED);
  76.  
    DataBuffer wrap = response.bufferFactory().wrap(buildResult(HttpStatus.UNAUTHORIZED.value(),message).getBytes(StandardCharsets.UTF_8));
  77.  
    return response.writeWith(Flux.just(wrap));
  78.  
    }
  79.  
     
  80.  
    /**
  81.  
    * 包装返回体
  82.  
    * @param code
  83.  
    * @param message
  84.  
    * @return
  85.  
    */
  86.  
    private String buildResult(int code,String message){
  87.  
    JSONObject jsonObject = new JSONObject();
  88.  
    jsonObject.put("code",code);
  89.  
    jsonObject.put("message",message);
  90.  
    jsonObject.put("data",null);
  91.  
    return jsonObject.toString(SerializerFeature.WriteMapNullValue);
  92.  
    }
  93.  
    }
学新通

6:限流ratelimiter

防止一大批请求进来,出现服务宕机;防止恶意攻击

6.1:常见的限流算法:

        计数器算法

        漏桶算法

        令牌桶算法:一定速率产生令牌,拿到才可以访问,桶有最大阈值,装满就不能生产了,适用于突发流量;假设桶最大1000个令牌,同时来了1001个,另外一个只能放弃或者等待

 6.2:限流实现

1:gateway可以结合sentine组件实现限流

2:也可以通过KeyResolver类来结合Redis实现令牌桶限流

3:Guava ReteLimiter限流

使用第二种来实现限流,创建限流类,用于说明根据什么规则进行限流,比如根据ip进行限流,设置一个ip每秒只能访问3次

依赖:

  1.  
    <dependency>
  2.  
    <groupId>org.springframework.boot</groupId>
  3.  
    <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
  4.  
    </dependency>

 yml配置文件:

  1.  
    spring:
  2.  
    redis:
  3.  
    host: localhost
  4.  
    port: 6379
  5.  
     
  6.  
     
  7.  
    - id: order-server-limit
  8.  
    uri: lb://order-server
  9.  
    predicates:
  10.  
    - Path=/order-lb-limit/**
  11.  
    filters:
  12.  
    #去除路径前缀的个数
  13.  
    - StripPrefix=1
  14.  
    - name: RequestRateLimiter #过滤器工厂RequestRateLimiter
  15.  
    args:
  16.  
    #通过SPEL表达式来指定使用哪一个KeyResolver
  17.  
    key-resolver: '#{@ipKeyResolver}'
  18.  
    #一共3个牌子,每秒发1个,领到牌子请求才能正常转发到服务
  19.  
    redis-rate-limiter.replenishRate: 1 #生产令牌的速率,每秒允许访问个数
  20.  
    redis-rate-limiter.burstCapacity: 3 #桶大小,即峰值流量来临时最大访问数
学新通

 config配置类:

  1.  
    @Configuration
  2.  
    public class RateLimitConfig {
  3.  
     
  4.  
    @Bean
  5.  
    public KeyResolver ipKeyResolver(){
  6.  
    return new KeyResolver() {
  7.  
    @Override
  8.  
    public Mono<String> resolve(ServerWebExchange exchange) {
  9.  
    return Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
  10.  
    }
  11.  
    };//根据ip地址来限流
  12.  
    }
  13.  
    }

 6.3:自定义限流异常返回数据:

继承RequestRateLimiterGatewayFilterFactory,实现apply方法,配置文件修改filters.name为新工厂名称(剔除后缀GatewayFilterFactory)

在过滤器中统一返回结果单独提取出来,定义在工具类中:

  1.  
    package com.example.Util;
  2.  
     
  3.  
    import com.alibaba.fastjson.JSONObject;
  4.  
    import com.alibaba.fastjson.serializer.SerializerFeature;
  5.  
     
  6.  
    /**
  7.  
    * @author lcy
  8.  
    * @version 1.0
  9.  
    * @date 2023/3/9 16:41
  10.  
    */
  11.  
    public class AuthResultUtil {
  12.  
    /**
  13.  
    * 包装返回体
  14.  
    * @param code
  15.  
    * @param message
  16.  
    * @return
  17.  
    */
  18.  
    public static String buildResult(int code,String message){
  19.  
    JSONObject jsonObject = new JSONObject();
  20.  
    jsonObject.put("code",code);
  21.  
    jsonObject.put("message",message);
  22.  
    jsonObject.put("data",null);
  23.  
    return jsonObject.toString(SerializerFeature.WriteMapNullValue);
  24.  
    }
  25.  
    }
学新通

 接下来自定义异常限流:

  1.  
    package com.example.config;
  2.  
     
  3.  
    import org.springframework.cloud.gateway.filter.GatewayFilter;
  4.  
    import org.springframework.cloud.gateway.filter.factory.RequestRateLimiterGatewayFilterFactory;
  5.  
    import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
  6.  
    import org.springframework.cloud.gateway.route.Route;
  7.  
    import org.springframework.cloud.gateway.filter.ratelimit.RateLimiter;
  8.  
    import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
  9.  
    import org.springframework.core.io.buffer.DataBuffer;
  10.  
    import org.springframework.http.HttpStatus;
  11.  
    import org.springframework.http.server.reactive.ServerHttpResponse;
  12.  
    import reactor.core.publisher.Mono;
  13.  
    import org.springframework.stereotype.Component;
  14.  
     
  15.  
    import java.nio.charset.StandardCharsets;
  16.  
    import java.util.Map;
  17.  
     
  18.  
    import static com.example.Util.AuthResultUtil.buildResult;
  19.  
     
  20.  
    /**
  21.  
    * @author lcy
  22.  
    * @version 1.0
  23.  
    * @date 2023/3/9 16:28
  24.  
    */@Component
  25.  
    public class GatewayRequestRateLimiterGatewayFilterFactory extends RequestRateLimiterGatewayFilterFactory {
  26.  
    private final RateLimiter defaultRateLimiter;
  27.  
    private final KeyResolver defaultKeyResolver;
  28.  
     
  29.  
    public GatewayRequestRateLimiterGatewayFilterFactory(RateLimiter defaultRateLimiter, KeyResolver defaultKeyResolver) {
  30.  
    super(defaultRateLimiter, defaultKeyResolver);
  31.  
    this.defaultRateLimiter = defaultRateLimiter;
  32.  
    this.defaultKeyResolver = defaultKeyResolver;
  33.  
    }
  34.  
     
  35.  
    @Override
  36.  
    public GatewayFilter apply(Config config) {
  37.  
    KeyResolver resolver = getOrDefault(config.getKeyResolver(), defaultKeyResolver);
  38.  
    RateLimiter<Object> limiter = getOrDefault(config.getRateLimiter(), defaultRateLimiter);
  39.  
    return (exchange, chain) -> resolver.resolve(exchange).flatMap(key -> {
  40.  
    String routeId = config.getRouteId();
  41.  
    if (routeId == null) {
  42.  
    Route route = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR);
  43.  
    routeId = route.getId();
  44.  
    }
  45.  
    return limiter.isAllowed(routeId, key).flatMap(response -> {
  46.  
    for (Map.Entry<String, String> header : response.getHeaders().entrySet()) {
  47.  
    exchange.getResponse().getHeaders().add(header.getKey(), header.getValue());
  48.  
    }
  49.  
    if (response.isAllowed()) {
  50.  
    return chain.filter(exchange);
  51.  
    }
  52.  
    ServerHttpResponse httpResponse = exchange.getResponse();
  53.  
    // 设置响应code500
  54.  
    httpResponse.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
  55.  
    if (!httpResponse.getHeaders().containsKey("Content-Type")) {
  56.  
    httpResponse.getHeaders().add("Content-Type", "application/json");
  57.  
    }
  58.  
    // 自定义返回信息
  59.  
    DataBuffer buffer = httpResponse.bufferFactory().wrap(buildResult(HttpStatus.INTERNAL_SERVER_ERROR.value(), "请求繁忙,请稍后重试").getBytes(StandardCharsets.UTF_8));
  60.  
    return httpResponse.writeWith(Mono.just(buffer));
  61.  
    });
  62.  
    });
  63.  
     
  64.  
    }
  65.  
     
  66.  
    /**
  67.  
    * 设置默认值
  68.  
    * @param configValue
  69.  
    * @param defaultValue
  70.  
    * @param <T>
  71.  
    * @return
  72.  
    */
  73.  
    private <T> T getOrDefault(T configValue, T defaultValue){
  74.  
    return configValue != null ? configValue : defaultValue;
  75.  
    }
  76.  
    }
学新通

更改yml文件name

学新通

 7:灰度发布:

体验服和正式服的差别,小部分体验服,测试bug。权重来声明

  1.  
    # 权重,灰度发布
  2.  
    - id: order1
  3.  
    uri: http://localhost:8080
  4.  
    predicates:
  5.  
    - Path=/order/**
  6.  
    # 分组名,权重
  7.  
    - Weight=order,80
  8.  
    filters:
  9.  
    - StripPrefix=2
  10.  
    - id: order2
  11.  
    uri: http://localhost:8081
  12.  
    predicates:
  13.  
    - Path=/order/sss/**
  14.  
    - Weight=order,20
  15.  
    filters:
  16.  
    - StripPrefix=2
学新通

百分之二十体验服

个人笔记-----方便温习

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhfjbjef
系列文章
更多 icon
同类精品
更多 icon
继续加载