微服务之Zuul(二)过滤器的使用

目录

一:过滤器介绍

二:简单使用

三:服务熔断配置

四:高可用:

代码:代码

 


一:过滤器介绍

Zuul的主要功能由过滤器实现的,ZuulFilter为过滤器的顶层类,是个抽象类。我们继承它可以看到最最重要的四个方法如下:


public class FilterTest extends ZuulFilter {

    /**
     * 过滤器类型,包含如下四种:
     * pre:请求在路由之前执行
     * routing:在路由请求时执行
     * post:后置,在routing和error过滤器之后执行
     * error: 处理请求发生错误时调用
       使用时可以从FilterConstants中取
     * @return
     */

    public String filterType() {
        return null;
    }

    /**
     * 过滤器顺序即优先级  数字越大优先级越小
     * 负数优先级最高
     * @return
     */
    public int filterOrder() {
        return 0;
    }

    /**
     * 判断过滤器是否需要执行
     * @return
     */
    public boolean shouldFilter() {
        return false;
    }

    /**
     * 过滤器的的具体业务逻辑
     * @return
     * @throws ZuulException
     */
    public Object run() throws ZuulException {
        return null;
    }
}

过滤器的生命周期执行流程参见下图:

 

注意:"custom" filters不止可以放在前置过滤器上,也可以放在其它位置。"error" filters指无论那个过滤器出错都会执行error过滤器。post过滤器报错,执行完error过滤器之后会执行后续的post过滤器,跳过报错的post过滤器。

我们一般实现都是前置过滤器也就是"pre"filter。进行身份验证,资源过滤,限流等控制。

二:简单使用

自定义一个简单的过滤器,进行身份验证。一般是使用sessionID和cookie携带来认证同意用户。这里只是测试过滤器是否生效,就很简单的使用参数判断。判断前端是否传递一个present_user参数,如果有就放行,如果没有就拒绝。

1:定义过滤器类。

 过滤器类型选Pre。但是过滤器的顺序的选择我们要参考已有的过滤器顺序来。

我们看到一些请求处理过程中的过滤器顺序,我们要选择的应该要在参数处理完之后执行,但是我们可以在请求头处理之前执行。因此

我们可以设置过滤器顺序:FilterConstants.PRE_DECORATION_FILTER_ORDER-1

注意要把这个类交给spring来管理。


@Component
public class LoginFilter extends ZuulFilter {

    /**
     * 过滤器类型,包含如下四种:
     * pre:请求在路由之前执行
     * routing:在路由请求时执行
     * post:后置,在routing和error过滤器之后执行
     * error: 处理请求发生错误时调用
     * @return
     */

    public String filterType() {
        return FilterConstants.PRE_TYPE;
    }

    /**
     * 过滤器顺序即优先级  数字越大优先级越小
     * 负数优先级最高
     * 这里我们把它放在请求头之前执行
     * @return
     */
    public int filterOrder() {
        return FilterConstants.PRE_DECORATION_FILTER_ORDER-1;
    }

    /**
     * 判断过滤器是否需要执行
     * @return
     */
    public boolean shouldFilter() {
        return true;
    }

    /**
     * 过滤器的的具体业务逻辑
     * @return
     * @throws ZuulException
     */
    public Object run() throws ZuulException {
        //获取请求的上下文
        RequestContext currentContext = RequestContext.getCurrentContext();
        //获取请求
        HttpServletRequest request = currentContext.getRequest();
       //获取请求参数
        String present_user = request.getParameter("present_user");
        if (StringUtils.isBlank(present_user)){
            //不存在,则阻拦
            currentContext.setSendZuulResponse(false);
            //返回状态 403
            currentContext.setResponseStatusCode(HttpStatus.SC_FORBIDDEN);
        }
        //默认是放行,不设置就行
        return null;
    }
}

这样我们访问:http://localhost:10010/consumer_service/getFeign/1会请求失败。

加上参数之后访问可以正常返回:http://localhost:10010/consumer_service/getFeign/1?present_user=12

 

三:服务熔断配置

zuul的依赖内部已经继承了Hystrix了,而且是默认开启的,但是使用之前,我们需要需要设置超时时间。

我们需要设置hystrix的超时时间和ribbon的超时时间,而且还要注意ribbon的超时时间要小于hystrix的超时时间,因为底层的配置会比较两个时长,而且默认是rbbon的两倍时长(连接和读取之和的两倍)和hystrix相比。可以在AbstractRibbonCommand看到,在获取这两个时间的会比较并且抛出警告。

  protected static int getHystrixTimeout(IClientConfig config, String commandKey) {
        int ribbonTimeout = getRibbonTimeout(config, commandKey);
        DynamicPropertyFactory dynamicPropertyFactory = DynamicPropertyFactory.getInstance();
        int defaultHystrixTimeout = dynamicPropertyFactory.getIntProperty("hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds", 0).get();
        int commandHystrixTimeout = dynamicPropertyFactory.getIntProperty("hystrix.command." + commandKey + ".execution.isolation.thread.timeoutInMilliseconds", 0).get();
        int hystrixTimeout;
        if(commandHystrixTimeout > 0) {
            hystrixTimeout = commandHystrixTimeout;
        } else if(defaultHystrixTimeout > 0) {
            hystrixTimeout = defaultHystrixTimeout;
        } else {
            hystrixTimeout = ribbonTimeout;
        }

        if(hystrixTimeout < ribbonTimeout) {
            LOGGER.warn("The Hystrix timeout of " + hystrixTimeout + "ms for the command " + commandKey + " is set lower than the combination of the Ribbon read and connect timeout, " + ribbonTimeout + "ms.");
        }

        return hystrixTimeout;
    }

    protected static int getRibbonTimeout(IClientConfig config, String commandKey) {
        int ribbonTimeout;
        if(config == null) {
            ribbonTimeout = 2000;
        } else {
            int ribbonReadTimeout = getTimeout(config, commandKey, "ReadTimeout", Keys.ReadTimeout, 1000);
            int ribbonConnectTimeout = getTimeout(config, commandKey, "ConnectTimeout", Keys.ConnectTimeout, 1000);
            int maxAutoRetries = getTimeout(config, commandKey, "MaxAutoRetries", Keys.MaxAutoRetries, 0);
            int maxAutoRetriesNextServer = getTimeout(config, commandKey, "MaxAutoRetriesNextServer", Keys.MaxAutoRetriesNextServer, 1);
            ribbonTimeout = (ribbonReadTimeout + ribbonConnectTimeout) * (maxAutoRetries + 1) * (maxAutoRetriesNextServer + 1);
        }

        return ribbonTimeout;
    }

因为默认的时长太短,我们配置如下:

hystrix:
   command:
      default:
        execution:
          isolation:
             thread:
                 timeoutInMilliseconds: 6000
ribbon:
    ReadTimeout: 2000
    ConnectTimeout: 500

我们看到代码中还把重试次数算ribbon和hystrix的时长比较,这是因为怕,ribbon还未重试hystrix就已经超时熔断了。

四:高可用:

因为zuul已经注册进Eureka中了,如果想让它高可用,我们只要给它做集群就可以了,那么这个时候我们就需要在zuul外面使用nginx来代理了。具体的后面做项目的时候用。

暂时告一段落微服务的内容更新了。后面学习其它内容,但是微服务还没有学习完,

还有:

spring-cloud-config:统一资源配置中心,自动去git拉取最新的配置,缓存。使用Git的Webhook钩子,去通知配置,该配置发生了变化,配置中心会通过消息总线去通知所有的微服务,更新配置。

spring-cloud-bus:消息总线

spring-cloud-stream:消息通信

spring-cloud-hystrix-dashboard:容错统计,形成图形化界面

spring-cloud-Sleuth:链路追踪,结合Zipkin

以上都是配置的内容,方便运维微服务系统,后续有时间再更新。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
在 Spring 微服务中,可以使用 Zuul 网关实现基于过滤器的限流。Zuul 是 Netflix 开源的一个基于 JVM 的路由和服务端负载均衡器,可以用来构建微服务架构中的网关。 以下是使用 Zuul 实现基于过滤器的限流的步骤: 1. 添加 Zuul 依赖。可以在 Spring Boot 项目中添加以下依赖: ``` <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-zuul</artifactId> </dependency> ``` 2. 创建一个 Zuul 过滤器。可以实现 com.netflix.zuul.ZuulFilter 接口,并重写其抽象方法。在该过滤器中,可以实现限流逻辑。 3. 将过滤器注册到 Zuul 中。可以在 Spring Boot 应用的配置文件中添加以下配置: ``` zuul: routes: my-service: path: /my-service/** serviceId: my-service filters: rate-limit: type: pre url: http://localhost:8080/limit ``` 其中,my-service 是需要进行限流的服务名,/my-service/** 是需要进行限流的路径,my-service 是该服务的注册名,rate-limit 是自定义的限流过滤器名。 4. 配置限流参数。可以在应用的配置文件中添加以下配置: ``` rate-limiter: enabled: true limit: 1000 time-interval: 1 ``` 其中,enabled 表示是否启用限流,limit 表示每个时间间隔内允许的请求数,time-interval 表示时间间隔。 5. 编写限流逻辑。在自定义的限流过滤器中,可以使用 Redis、Guava、Bucket4j 等工具实现限流逻辑。以下是一个使用 Redis 实现限流的示例: ```java @Component public class RateLimitFilter extends ZuulFilter { private RedisTemplate<String, String> redisTemplate; @Autowired public RateLimitFilter(RedisTemplate<String, String> redisTemplate) { this.redisTemplate = redisTemplate; } @Override public String filterType() { return "pre"; } @Override public int filterOrder() { return 1; } @Override public boolean shouldFilter() { return true; } @Override public Object run() throws ZuulException { String ipAddress = RequestContext.getCurrentContext().getRequest().getRemoteAddr(); String key = "rate-limit:" + ipAddress; ValueOperations<String, String> ops = redisTemplate.opsForValue(); Long count = ops.increment(key, 1); if (count == 1) { redisTemplate.expire(key, 1, TimeUnit.SECONDS); } Long limit = Long.valueOf(redisTemplate.opsForValue().get("rate-limiter:limit")); Long timeInterval = Long.valueOf(redisTemplate.opsForValue().get("rate-limiter:time-interval")); if (count > limit) { throw new RuntimeException("Rate limit exceeded"); } return null; } } ``` 在上面的示例中,我们使用 Redis 存储每个 IP 地址的请求数,并在达到限流阈值时抛出异常。同时,我们从 Redis 中获取限流参数,即每个时间间隔内允许的请求数和时间间隔。 以上就是使用 Zuul 实现基于过滤器的限流的步骤。通过配置和编写逻辑,我们可以在微服务架构中对单个服务或多个服务进行限流。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

姑苏冷

您的打赏是对原创文章最大的鼓励

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值