【网关】网关

网关

  • Kong
  • Zuul
  • Traefik
  • Spring Cloud Gateway
  • Nginx+lua
一,Nginx

简单配置一下,
在这里插入图片描述

二,Zuul
1.介绍

Zuul是Netflix开源的微服务网关,他可以和Eureka,Ribbon,Hystrix等组件配合使用。Zuul组件的核心是一系列的过滤器,这些过滤器可以完成以下功能:

  • 身份认证和安全:识别每一个资源的验证要求,并拒绝那些不符的请求
  • 审查与监控:在服务边界追踪并统计数据,提供精确的生产视图
  • 动态路由:动态将请求路由到不同后端集群
  • 压力测试:逐渐增加指向集群的流量,以了解性能
  • 负载分配:为每一种负载类型分配对应容量,并弃用超出限定值的请求
  • 静态响应处理:边缘位置进行响应,避免转发到内部集群
  • 多区域弹性:跨域AWS Region进行请求路由,旨在实现ELB(ElasticLoad Balancing)使用多样化
2.搭建Zuul网关服务器
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
    <version>2.0.7.RELEASE</version>
</dependency>
//开启zuul网关功能
@EnableZuulProxy
server:
  port: 8080
spring:
  application:
    name: api_zuul_server


3.路由
zuul:
  prefix: /yyong
  ignored-services: "*"
  routes: 
    mydept: #路由id,随便写
      serviceId: mydept-service #指定Eureka注册中心中的服务id
      path: /mydept/**#映射路径
  • 添加eureka的依赖
  • 开启服务发现
  • 相当于大门
4.过滤器
/**
 * 自定义的zuul过滤器
 *   继承抽象父类
 */
@Component
public class LoginFilter extends ZuulFilter {

    /**
     * 定义过滤器类型
     *  pre:转发到微服务之前执行的过滤器
     *  routing:在路由请求是执行的过滤器
     *  post:执行微服务获取返回值之后执行的过滤器
     *  error:在整个阶段抛出异常的时候执行的过滤器
     * @return
     */
    @Override
    public String filterType() {
        return "pre";
    }

    /**
     * 指定过滤器的执行顺序
     *  返回值越少,执行顺寻越高
     * @return
     */
    @Override
    public int filterOrder() {
        return 1;
    }

    /**
     * 当前过滤器是否生效
     * true:使用此过滤器
     * flase:不使用此过滤器
     * @return
     */
    @Override
    public boolean shouldFilter() {
        return true;
    }

    /**
     * 指定过滤器中的业务逻辑
     * @return
     * @throws ZuulException
     */
    @Override
    public Object run() throws ZuulException {
        System.out.println("执行了过滤器");
        return null;
    }
}

小小的案例

/**
 * 指定过滤器中的业务逻辑
 *  身份认证:
 *    1.所有的请求需要携带一个参数:access-token
 *    2.获取request请求
 *    3.通过request获取参数access-token
 *    4.判断token是否为空
 *    4.1 token==null:身份验证失败
 *    4.2 token!==null:执行后续操作
 *  在zuul网关中,通过RequestContext的上下文对象,可以获取对象request对象
 * @return
 * @throws ZuulException
 */
@Override
public Object run() throws ZuulException {
    System.out.println("执行了过滤器");
    //1.获取zuul提供的上下文对象RequestContext
    RequestContext ctx = RequestContext.getCurrentContext();
    //2.从RequestContext中获取request
    HttpServletRequest request = ctx.getRequest();
    //3.获取请求参数access-token
    String token = request.getParameter("access-token");
    //4.判断
    if (token == null){
        //4.1 token==null:身份验证失败
        ctx.setSendZuulResponse(false);//拦截请求
        ctx.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
    }
    //4.2 token!==null:执行后续操作
    return null;
}
5.源码
三,Spring Cloud Gateway

在实际使用中我们会发现直接使用Zuul会存在诸多问题,包括:

  • 性能问题
  • 不支持任何长连接,如websocket

Zuul网关的替换方案

  • zuul2.x
  • Spring Cloud Gateway
1.路由配置
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
#配置SpringCloudGateway的路由
spring:
  cloud:
    gateway:
      routes:
        #配置路由:路由id,路由到微服务的uri,断言(判断条件)
      - id: xxxx-dept #保持唯一
        uri: http://127.0.0.1 #目标微服务请求地址
        predicates:
        - Path=/product/** #路由匹配条件

断言条件

2)动态路由(面向服务的路由):

#配置SpringCloudGateway的路由
spring:
  cloud:
    gateway:
      routes:
        #配置路由:路由id,路由到微服务的uri,断言(判断条件)
      - id: xxxx-dept #保持唯一
        # uri: http://127.0.0.1 #目标微服务请求地址
        uri: lb://service-product #lb:// 根据微服务名称从注册中心中拉取服务请求路径
        predicates:
        - Path=/product-service/** #路由匹配条件
        filters: #配置路由过滤器,http://127.0.0.1:8080/product-service/product/1 ---> http://127.0.0.1:9001/product/1
        - RewritePath=/product-service/(?<segment>.*),/$\{segment} #路径重写的过滤器
      #配置自动的根据微服务名称进行路由转发
      discovery: 
      	locator: 
      	  enabled: true #开启根据服务名称自动转发
      	  lower-case-service-id: true #微服务名称已小写形式呈现
        
2.过滤器

1)过滤器的生命周期

  • PRE,之前
  • POST,之后

2)过滤器类型

  • GatewayFilter:应用到单个路由或者一个分组的路由上
  • GlobalFilter:应用到所有的路由上
/**
 * 自定义一个全局过滤器
 *   实现 globalfilter,ordered
 */
public class LoginGlobalFilter implements GlobalFilter, Ordered {

    /**
     * 执行过滤器的业务逻辑
     * @param exchange
     * @param chain
     * @return
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        System.out.println("执行了自定义的全局过滤器");
        return chain.filter(exchange);//继续向下执行
    }

    /**
     * 指定过滤器的执行顺序,返回值越小,执行优先级越高
     * @return
     */
    @Override
    public int getOrder() {
        return 1;
    }
}
/**
 * 执行过滤器的业务逻辑
 *  对请求参数中的access-token进行判断
 *   如果存在此参数:代表已经认证成功
 *   如果不存在此参数:认证失败
 * ServerWebExchange:相当于请求和响应的上下文(zuul中的RequestContext)
 * @param exchange
 * @param chain
 * @return
 */
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    System.out.println("执行了自定义的全局过滤器");
    //1.获取请求参数
    String first = exchange.getRequest().getQueryParams().getFirst("access-token");
    //2.判断是否存在:
    if(first == null){
        //3.如果不存在:认证失败
        System.out.println("没有登录");
        exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
        return exchange.getResponse().setComplete();
    }
    //4.如果存在:继续执行
    return chain.filter(exchange);//继续向下执行
}
3.统一鉴权
4.网关限流

1)常见的限流算法
(1)计数器:不平滑
(2)漏桶算法
(3)令牌桶算法
2)基于 Filter 的限流
(1)准备工作
redis
在工程中引入redis相应的依赖

<!--actuator监控信息完善-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- redis依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>

(2)修改网关中的application.yml配置


spring:
  application: api-server #服务名称
  redis:
    host: 127.0.0.1
    pool: 6379
    database: 0
  cloud: #配置SpringCloudGateway的路由
    gateway:
      routes:
        - id: payment-router
          uri: lb://payment-service
          predicates:
            - Path=/pay/**
          filters:
              # RequestRateLimiter:使用限流过滤器,是springcloud gateway提供的
              # 参数 replenishRate:向令牌桶中填充的速率
              # burstCapacity :令牌桶的容量 
            - name: RequestRateLimiter
              args:
                # 令牌桶每秒填充平均速率
                redis-rate-limiter.replenishRate: 1
                # 令牌桶的上限
                redis-rate-limiter.burstCapacity: 5
                # 使用SpEL从容器中获取对象
                key-resolver: '#{@pathKeyResolver}'

(3)配置redis中解析器keySesolver


@Configuration
public class KeyResolverConfiguration {

    /**
     * 编写基于请求路径的限流规则
     * //abc
     * //基于请求ip 127.0.0.1
     * //基于参数
     * @return
     */
    @Bean
    public KeyResolver pathKeyResolver(){
        //自定义的KeyResolver
        return new KeyResolver(){

            /**
             * ServerWebExchange:
             *  上下文参数
             * @param exchange
             * @return
             */
            @Override
            public Mono<String> resolve(ServerWebExchange exchange) {
                return Mono.just(exchange.getRequest().getPath().toString());
            }
        };
    }

/**
     * 基于请求参数的限流
     *  请求 abc ? userId=1
     * @return
     */
    @Bean
    public KeyResolver userKeyResolver(){
        return new KeyResolver(){

            @Override
            public Mono<String> resolve(ServerWebExchange exchange) {
                return Mono.just(exchange.getRequest().getQueryParams().getFirst("userId"));
            }
        };

    }
     /**
     * 基于请求ip的限流
     *  请求 abc ? userId=1
     * @return
     */
    @Bean
    public KeyResolver userKeyResolver(){
        return new KeyResolver(){

            @Override
            public Mono<String> resolve(ServerWebExchange exchange) {
                return Mono.just(exchange.getRequest().getHeaders().getFirst("X-Forwarded-For"));
            }
        };

    }
}

3)基于 Sentinel 的限流


 <!--sentinel限流-->
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
    <version>1.6.3</version>
</dependency>

配置类


@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;
    }

    /**
     * 配置限流的异常处理器:SentinelGatewayBlockExceptionHandler
     * @return
     */
    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler(){
        return new SentinelGatewayBlockExceptionHandler(viewResolvers,serverCodecConfigurer);
    }

    /**
     * 配置限流过滤器
     * @return
     */
    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public GlobalFilter sentinelGlobalFilter() {
        return new SentinelGatewayFilter();
    }

    /**
     * 配置初始化的限流参数
     * 用户指定资源的限流的规则
     *  1.资源名称(路由id)
     *  2.配置统计时间
     *  3.配置限流阈值
     */
    @PostConstruct
    public void initGatewayRules(){
        Set<GatewayFlowRule> rules = new HashSet<>();
       /* rules.add(
                new GatewayFlowRule("order-service")//资源名称
                        .setCount(1)//限流阈值
                    .setIntervalSec(1)//统计事件窗口,单位秒,默认是一秒
        );
        rules.add(
                new GatewayFlowRule("order-service")//资源名称
                        .setCount(1)//限流阈值
                        .setIntervalSec(1)//统计事件窗口,单位秒,默认是一秒
                .setParamItem(new GatewayParamFlowItem()
                        .setParseStrategy(SentinelGatewayConstants.PARAM_PARSE_STRATEGY_URL_PARAM).setFieldName("id"))
        );*/
        rules.add(
                new GatewayFlowRule("product_api")
                        .setCount(1)
                        .setIntervalSec(1)
        );
        rules.add(
                new GatewayFlowRule("order_api")
                        .setCount(1)
                        .setIntervalSec(1)
        );
        GatewayRuleManager.loadRules(rules);
    }

/*    @PostConstruct
    public void initBlockhandlers(){
        BlockRequestHandler blockRequestHandler = new BlockRequestHandler(){

            @Override
            public Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) {
                Map map = new HashMap<>();
                map.put("code",001);
                map.put("message","对不起,接口限流了");

                return ServerResponse.status(HttpStatus.OK)
                        .contentType(MediaType.APPLICATION_JSON_UTF8)
                        .body(BodyInserters.fromObject(map));
            }
        };
        GatewayCallbackManager.setBlockHandler(blockRequestHandler);
    }

    @PostConstruct
    public void initCustomizedApis(){
        Set<ApiDefinition> definitions = new HashSet<>();
        ApiDefinition api1 = new ApiDefinition("product_api")
                .setPredicateItems(new HashSet<ApiPredicateItem>(){{
                 add(new ApiPathPredicateItem().setPattern("/product-service/product/**")
                    .setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX));
                }});
        ApiDefinition api2 = new ApiDefinition("order_api")
                .setPredicateItems(new HashSet<ApiPredicateItem>(){{
                    add(new ApiPathPredicateItem().setPattern("/order-service/order"));
                }});
        definitions.add(api1);
        definitions.add(api2);
        GatewayApiDefinitionManager.loadApiDefinitions(definitions);
    }*/

}
5.网关的高可用
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值