springcloud zuul 动态路由

zuul简介

        Zuul 是Spring Cloud 子项目Spring Cloud Netflix的一个组件,它是Netflix对ApiGateway实现的一份答卷,应用非常广泛。常见的功能如下

  • 身份验证
  • 压力测试
  • Canary Testing
  • 动态路由
  • 安全控制 
  • ...............

zuul实例 

      OK,既然标题提到zuul动态路由,此文章主要介绍下zuul动态路由,那么我们写个小demo看看zuul

  • 1、首先创建对应的pom文件
  • <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-zuul</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-eureka</artifactId>
    </dependency>
  • 2、其次对应的主应用@EnableZuulProxy注解开启Zuul
  • @EnableZuulProxy
    @EnableEurekaClient
    @SpringCloudApplication
    public class Application {
        public static void main(String[] args) {
            SpringApplication.run(Application.class,args);
        }
    
        @Bean
        public PreFilter preFilter() {
            return new PreFilter();
        }
    
        @Bean
        public RoutingFilter routingFilter() {
            return new RoutingFilter();
        }
    
        @Bean
        public PostFilter postFilter() {
            return new PostFilter();
        }
    
        @Bean
        public ErrorFilter errorFilter() {
            return new ErrorFilter();
        }
    
    
    }
  • 3、application.properties中配置Zuul应用的基础信息,如:应用名、服务端口等。
  • spring.application.name=api-gateway
    server.port=9091
  • 到此简单的zuul就可以跑了,但是若需要用到微服务中那么还需如下配置

路由服务

#反响代理配置  
#这里的配置类似nginx的反响代理  
#当stripPrefix=true的时候 (http://127.0.0.1:8181/api/user/list -> http://192.168.1.100:8080/user/list)  
#当stripPrefix=false的时候(http://127.0.0.1:8181/api/user/list -> http://192.168.1.100:8080/api/user/list)  
zuul.routes.api.path=/api/**  
#代理前缀默认会从请求路径去除
zuul.routes.api.stripPrefix=false

zuul的其他配置

#提高超时配置(有的同学碰到第一次代理时都是timeout,需要配置如下配置)

hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds:60000

ribbon.ConnectTimeout: 3000

ribbon.ReadTimeout: 60000

服务过滤

在服务网关中定义过滤器只需要继承zuulfltier抽象类实现其定义的四个抽象函数就可对请求进行拦截与过滤。

比如下面的例子,定义了一个Zuul过滤器,实现了在请求被路由之前检查请求中是否有accessToken参数,若有就进行路由,若没有就拒绝访问,返回401 Unauthorized错误。

public class AccessFilter extends ZuulFilter  {
    private static Logger log = LoggerFactory.getLogger(AccessFilter.class);
    @Override
    public String filterType() {
        return "pre";
    }
    @Override
    public int filterOrder() {
        return 0;
    }
    @Override
    public boolean shouldFilter() {
        return true;
    }
    @Override
    public Object run() {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        log.info(String.format("%s request to %s", request.getMethod(), request.getRequestURL().toString()));
        Object accessToken = request.getParameter("accessToken");
        if(accessToken == null) {
            log.warn("access token is empty");
            ctx.setSendZuulResponse(false);
            ctx.setResponseStatusCode(401);
            return null;
        }
        log.info("access token ok");
        return null;
    }
}

自定义过滤器的实现,需要继承ZuulFilter,需要重写实现下面四个方法:

  • filterType:返回一个字符串代表过滤器的类型,在zuul中定义了四种不同生命周期的过滤器类型,具体如下:
    • pre:可以在请求被路由之前调用
    • routing:在路由请求时候被调用
    • post:在routing和error过滤器之后被调用
    • error:处理请求时发生错误时被调用
  • filterOrder:通过int值来定义过滤器的执行顺序
  • shouldFilter:返回一个boolean类型来判断该过滤器是否要执行,所以通过此函数可实现过滤器的开关。在上例中,我们直接返回true,所以该过滤器总是生效。
  • run:过滤器的具体逻辑。需要注意,这里我们通过ctx.setSendZuulResponse(false)令zuul过滤该请求,不对其进行路由,然后通过ctx.setResponseStatusCode(401)设置了其返回的错误码,当然我们也可以进一步优化我们的返回,比如,通过ctx.setResponseBody(body)对返回body内容进行编辑等。

        在实现了自定义过滤器之后,还需要实例化该过滤器才能生效,还需要在应用主类中增加四个过滤器的实例化。

  为什么服务网关是微服务架构的重要部分?

  • 不仅仅实现了路由功能来屏蔽诸多服务细节,更实现了服务级别、均衡负载的路由。
  • 实现了接口权限校验与微服务业务逻辑的解耦。通过服务网关中的过滤器,在各生命周期中去校验请求的内容,将原本在对外服务层做的校验前移,保证了微服务的无状态性,同时降低了微服务的测试难度,让服务本身更集中关注业务逻辑的处理。
  • 实现了断路器,不会因为具体微服务的故障而导致服务网关的阻塞,依然可以对外服务。

    问题总结

        1、第一次代理请求是连接超时(timeout) 需要配置 进行如下配置

hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds:60000

ribbon.ConnectTimeout: 3000

ribbon.ReadTimeout: 60000

        2、com.netflix.discovery.TimedSupervisorTask(线程池拒绝策略异常),相信很多人都碰到了这个问题,度娘了有的说不影响,确实是不影响,但是程序员都有强迫症。

java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@427829d8 rejected from java.util.concurrent.ThreadPoolExecutor@5f0345ff[Terminated, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 0]  
    at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2048) ~[na:1.7.0_79]  
    at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:821) [na:1.7.0_79]  
    at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1372) [na:1.7.0_79]  
    at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:110) ~[na:1.7.0_79]  
    at com.netflix.discovery.TimedSupervisorTask.run(TimedSupervisorTask.java:62) ~[eureka-client-1.4.11.jar:1.4.11]  
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471) [na:1.7.0_79]  
    at java.util.concurrent.FutureTask.run(FutureTask.java:262) [na:1.7.0_79]  
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:178) [na:1.7.0_79]  
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:292) [na:1.7.0_79]  
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) [na:1.7.0_79]  
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) [na:1.7.0_79]  
    at java.lang.Thread.run(Thread.java:745) [na:1.7.0_79]  

    ok废话不多说,直接上解决方案,将对应的eurake版本升级,此问题应该是eurake自带的bug

  <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Dalston.RELEASE</version> // 注意关键点在这
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

此问题的参考文档  https://github.com/Netflix/eureka/issues/907

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值