spring cloud zuul

2019-05-09  本文已影响0人  末日声箫

一 spring cloud Zuul底层架构

spring cloud zuul融合的是netflix 的zuul 1.x版本

1.1 netflix 的1.x的线程模型

zuul1.x线程模型.png
zuul1.x采用的是线程阻塞模型,也就是我们常说的BIO,每来一个请求就会从线程池中分配一个线程去处理。这里导致的问题就是如果每一次请求的耗时很长,i/o操作时间很长,就会导致大量线程被挂起,利用率不仅低,很容易耗尽容器线程池内的线程,造成容器无法接受新的请求。所以对于这种io密集型,大请求来说,是不合适的。他适合那种小请求,cpu密集型,如果每一次请求只需要0.0几秒,一个线程1s钟也可以处理上百次请求,再加上简单,所以对于流量不是特别大,请求时间很短的场景是很实用的。
应用场景

1.2 zuul 2.x 的线程模型

image.png

可以简单理解为有一个队列专门负责处理用户请求(如果连接量大,可以开个线程组来处理),后端有个队列专门负责处理后台服务调用(如果连接量大,可以开个线程组来处理),中间有个事件环线程(Event Loop Thread),它同时监听前后两个队列上的事件,有事件就触发回调函数处理事件。这种模式下需要的线程比较少,基本上每个CPU核上只需要一个事件环处理线程,前端的连接数可以很多,连接来了只需要进队列,不需要启动线程,事件环线程由事件触发,没有多线程阻塞问题。但是zuul2.x带来的问题就是开发成本大,对于小请求来说他的性能提升不明显。
应用场景

1.3 Zulu 1.x 的架构

image.png

每一次请求都会通过servlet,然后进入各种过滤器,最后再返回给客户端。而各个filters之间不会直接进行通信的。zuul 1.x使用RequestContext来实现各个filters之间共享数据,而RequestContext采用ConcurrentHashMap和ThreadLocal实现线程安全。

1.4 Zuul 1.x requestLifeCycle

image.png

一次请求的生命周期就如上图所示。可见最重要的一环就是各种过滤器。

过滤器类型

         * @author zhaokai008@ke.com
         * @date 2019-05-11 21:45
         */
        public class TokenFilters {
         private static Logger LOGGER = LoggerFactory.getLogger(TokenFilter.class);
        ​
         @Override
         public String filterType() {
         return PRE_TYPE;
         }
        ​
         @Override
         public int filterOrder() {
         return 0;
         }
        ​
         @Override
         public boolean shouldFilter() {
         //todo 什么时候需要验证token

         return true;
         }
        ​
         @Override
         public Object run() {
        ​
         RequestContext ctx = RequestContext.getCurrentContext();
         HttpServletRequest request = ctx.getRequest();
         String url = request.getRequestURI();
         String token = request.getHeader("token");
         checkToken(url,token);
         return null;
        ​
         }
        ​
         private boolean checkToken(String url, String token) {

         //todo dosomething
         return true;
         }
        ​
        }

二 配置详解

  zuul:
  SendErrorFilter:
    error:
      disable: true
  sensitive-headers:
  #ignored-services: '*'
  # 限流
  ratelimit:
    enabled: true
    fallback: true
    repository: in_memory
    # 全局限流
    default-policy-list:
      - limit: 10000 #optional - request number limit per refresh interval window
        quota: 300 #optional - request time limit per refresh interval window (in seconds)
        refresh-interval: 60 #default value (in seconds)
        type: #optional
          - url
    # 分route限流
    policy-list:
      test1:
        - limit: 1 #optional - request number limit per refresh interval window
          quota: 10 #optional - request time limit per refresh interval window (in seconds)
          refresh-interval: 1 #default value (in seconds)
          type: #optional
            - url
  routes:
    test1:
      path: /api/10/search/**
      serviceId: common
      stripPrefix: false
      token: 10
    test2:
      path: /api/10/search/**
      serviceId: on
      stripPrefix: false
      token: 10
    test3:
      path: /api/data/10/**
      serviceId: DAS
      stripPrefix: false
      token: d10
    test4:
      path: /api/data/**
      serviceId: no
      stripPrefix: false
      token: d10
    test5:
      path: /api/search/**
      serviceId: no
      stripPrefix: true
      token: d10
    test6:
      path: /api/search/**
      url: http://host/api/data/**
      stripPrefix: false
      token: d10
    test7:
      path: /*
      url: http://host/api/data/**
      stripPrefix: false
      token: d10

# hystrix
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 6000

  host:
    max-per-route-connections: 20 #默认20
    max-total-connections: 200  #默认200

ribbon:
  eager-load:
    enabled: true
  ConnectTimeout: 15 #默认1000
  ReadTimeout: 15 #默认2000

2.1 请求路由

zuul.ignored-services: 默认情况下所有Eureka上的服务都会被Zuul自动创建映射关系进行路由,一般情况下需要 将其 置为 * ,表示不需要为所有服务自动创建路规则。这个默认情况下是需要设置为 * ,因为很多时候我们不想让我们的服务都对外暴露

2.1.1 设置路由

有两种方式,URL和serviceId.都是通过匹配到网关的path然后映射到对应的服务(url或者serviceId)上去。其中test5是url式,其余的都是serviceId式。但是要注意的是url方式没有 Hystrix、Ribbon 特性。

2.1.2 存取路由顺序

2.1.3 读取路由规则

1,使用路由规则匹配请求路径的时候是通过线性遍历的方式,在请求路径获取到第一个匹配的路由规则之后就会返回并结束匹配过程。所以当存在多个匹配的路由规则时,匹配结果完全取决于路由规则的保存顺序。
2, 在yaml存入是按照顺序存入的,左边第一个图当我们访问/api/data/10的时候,因为第一个匹配到的是/api/data/10/**,所以会映射到test3的DAS,而不会映射到test4 的no服务

2.2 限流

2.3 超时,熔断

2.4 线程池大小

三 Zuul 使用的坑:

上一篇 下一篇

猜你喜欢

热点阅读