Netflix Zuul host 属性配置

Netflix Zuul 的 host 属性用于控制默认连接池的主机属性,包括超时时间、连接最长等待时间、最大连接数等等信息,一个配置示例如下:

zuul:
  #...
  # 控制默认连接池属性的主机属性
  host:
    # Zuul在尝试连接后端服务时的超时时间,单位是毫秒
    connect-timeout-millis: 10000
    # 从连接请求发出到获取到连接的最长等待时间,单位是毫秒
    connection-request-timeout-millis: 20000
    # 限制Zuul到每个后端服务路径(路由)所能建立的最大连接数
    max-per-route-connections: 20
    # 限制Zuul与所有后端服务总共能够建立的最大连接数
    max-total-connections: 200
    # 定义了Zuul在与后端服务建立连接后,等待读取数据的超时时间,单位是毫秒
    socket-timeout-millis: 60000
    # 指定连接池中的连接的生存时间
    time-to-live: 1
    # 指定连接池中的连接的生存时间的单位
    time-unit: DAYS

上述 host 属性的对应了 org.springframework.cloud.netflix.zuul.filters.ZuulProperties.Host 类,如下图:

64a5841062b35d4456a0f6139f0ee55e_1734054357988-ff6b66a7-a874-4422-b390-4f48d9c6cccb.png

上图中的 timeUnit 对应 java.util.concurrent.TimeUnit 类,默认值为 MILLISECONDS,如下图:

4b6ebb1f8275a468a08bf782f946bec7_1734054415699-38371b02-8ed2-4505-ba94-4e0db2472318.png

以下是对 Netflix Zuul host 属性配置的详细介绍:

connect-timeout-millis

该属性用于设置 Zuul 网关在尝试连接后端服务时的超时时间,单位是毫秒。它决定了从 Zuul 发起连接请求到成功建立与后端服务的连接之间的最长等待时间。

注意,在网络状况不稳定、后端服务响应缓慢或者暂时不可达的情况下,该属性非常重要。例如,当后端服务正在部署新的实例、进行系统维护,或者网络延迟较高时,设置合理的 connect-timeout-millis 可以防止 Zuul 长时间等待连接建立,避免客户端请求长时间处于等待状态。

如果将 connect-timeout-millis 设置为 3000(即 3 秒),如果 Zuul 在 3 秒内未能成功建立连接,它将抛出连接超时异常,这有助于提高系统整体的响应性和稳定性,避免因长时间等待连接而占用过多资源。

connection-request-timeout-millis

该属性设置了从 Zuul 发出连接请求到获取连接资源的最大允许等待时间,以毫秒为单位。该属性侧重于从请求连接到获取可用连接资源的等待时长。

在高并发场景下,可能会出现连接资源竞争的情况,多个请求可能同时请求连接到后端服务,导致连接资源紧张。此时,设置 connection-request-timeout-millis 可以限制请求等待连接资源的时间,避免请求在等待连接时出现长时间阻塞。

例如,设置 connection-request-timeout-millis 为 5000(即 5 秒),当一个请求发出连接请求后,如果在 5 秒内无法获取到连接资源,将触发连接请求超时异常,从而避免请求因等待连接资源而导致系统性能下降。

max-per-route-connections

该属性限制了 Zuul 与每个后端服务路由可以建立的最大连接数。它针对的是 Zuul 与单个后端服务路径的连接数量。

在一个微服务架构中,不同的后端服务可能具有不同的负载处理能力和资源限制。通过设置 max-per-route-connections,可以防止 Zuul 向某个特定后端服务发送过多的连接请求,避免该后端服务因连接数过多而崩溃或性能下降。

例如,将 max-per-route-connections 设为 20,对于每个后端服务路由,Zuul 最多只能同时建立 20 个连接。这对于保护那些处理能力有限的后端服务,如数据库服务、计算密集型微服务等,具有重要意义,有助于确保服务的稳定运行。

max-total-connections

该属性定义了 Zuul 与所有后端服务总共能够建立的最大连接数。该属性从整体上对 Zuul 的连接能力进行了限制。

当 Zuul 作为网关处理来自多个客户端的大量请求并需要连接多个后端服务时,设置 max-total-connections 可以防止因连接数过多而耗尽系统资源,如网络端口、内存等。

假如设置 max-total-connections 为 100,这意味着 Zuul 最多可以同时建立 100 个连接到所有后端服务。这有助于在高负载情况下维持系统的稳定性,避免因连接数无限制增长而导致系统故障或性能瓶颈。

socket-timeout-millis

该属性指定了 Zuul 在与后端服务建立连接后,等待读取数据的超时时间,单位是毫秒。它涉及到连接建立成功后,等待接收数据的时长限制。

当后端服务响应缓慢,或者在数据传输过程中出现网络问题时,设置 socket-timeout-millis 可以确保 Zuul 不会无限期等待数据的读取。

例如,设置 socket-timeout-millis 为 60000(即 60 秒),如果 Zuul 在连接成功后 60 秒内没有读取到所需的数据,将触发读取超时异常,这有助于及时处理网络异常,保证系统的响应效率和可靠性。

time-to-live 和 time-unit

time-to-live 与 time-unit 通常一起使用。time-to-live 表示连接的生存时间长度,而 time-unit 则是时间的单位(如 SECONDS、MINUTES、HOURS、DAYS 等),它们共同决定了连接池中的连接在多长时间内有效。

在长时间运行的系统中,后端服务的网络地址、端口或其他配置可能会发生变化,或者网络环境会有所调整。通过设置 time-to-live 和 time-unit,可以确保连接池中的连接在一段时间后被更新或回收,以保证连接的有效性和适应新的服务配置。

例如,设置 time-to-live 为 2 且 time-unit 为 HOURS,意味着连接池中的连接在创建 2 小时后将被重新评估,以确保使用的连接仍然符合后端服务的最新状态,避免因使用陈旧或失效的连接而导致请求失败。

🌈注意:通过合理配置这些主机属性,Netflix Zuul 可以更好地管理与后端服务的连接,提高系统的性能、稳定性和可靠性,适应不同的网络和服务场景,确保在处理大量请求时能够有效地进行请求路由和服务转发。

示例

修改 service-order 服务

修改根据 ID 获取订单接口,模拟等待 2 秒,如下:

// 根据ID获取订单信息
private CommonReturn<Order> getOrderById(Long id) {
    try {
        // 模拟等待2秒
        Thread.sleep(2000);
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }
    
    return ORDERS.stream()
        .filter(order -> order.getId().equals(id))
        .findFirst()
        .map(u -> {
            final List<Product> products = new ArrayList<>();
            u.setProducts(products);
            u.getProductIds().forEach(productId -> {
                products.add(getProductById(productId));
            });
            return CommonReturn.success(u).ext(appName, appPort);
        })
        .orElse(CommonReturn.fail("订单不存在"));
}

修改 zuul 应用

修改 zuul 配置,读取超时时间为 6s,应该能正常访问:

zuul:
  #...
  # 控制默认连接池属性的主机属性
  host:
    # Zuul在尝试连接后端服务时的超时时间,单位是毫秒
    connect-timeout-millis: 1000
    # 从连接请求发出到获取到连接的最长等待时间,单位是毫秒
    connection-request-timeout-millis: 20
    # 限制Zuul到每个后端服务路径(路由)所能建立的最大连接数
    max-per-route-connections: 20
    # 限制Zuul与所有后端服务总共能够建立的最大连接数
    max-total-connections: 100
    # 定义了Zuul在与后端服务建立连接后,等待读取数据的超时时间,单位是毫秒
    socket-timeout-millis: 60000
    # 指定连接池中的连接的生存时间
    time-to-live: 1
    # 指定连接池中的连接的生存时间的单位
    time-unit: HOURS

重启 Zuul 示例引用,访问地址,如下图:

a009327c24a1376fadcf7bea833b89e4_1734059157219-569510a2-3407-47bc-9948-13feae88b607.png

出现了读超时,我们配置的不是 6s,响应模拟了 2s,不应该啊!查看具体错误日志:

ba76e4c868057fa8aa3c524028af3002_1734059284718-0249f2fb-2ff5-4dc2-a0c5-8c78163711e5.png

从上面错误可知,“Read timed out”错误是 Ribbon 抛出的。

注意:Zuul 1.x 默认会使用 Ribbon 进行服务路由和负载均衡。Ribbon 是一个客户端负载均衡器,它帮助 Zuul 将请求路由到不同的后端服务实例,尤其是在微服务架构中,当 Zuul 作为网关时,Ribbon 可以根据不同的服务发现机制(如 Eureka)和负载均衡算法将请求分发到多个后端服务实例中的一个。点击学习 Ribbon……

因此,我们需要配置一下 Ribbon 的读超时时间,如下:

# zuul 过滤器
zuul:
  #...

# 看这里
ribbon:
 ReadTimeout: 5000  # 读取超时时间,单位为毫秒,此处设置为 5 秒
 ConnectTimeout: 2000  # 连接超时时间,单位为毫秒,此处设置为 2 秒

重启服务,再试,访问成功了,如下图:

086e80f1a420e2cdf3da5c54f632721c_1734059509068-a2764b7e-5552-4523-81b0-727c74f0e0df.png

为什么 zuul.host.socket-timeout-millis 对 ribbon 没有作用?

zuul.host.socket-timeout-millis 配置主要是针对 Zuul 作为一个 HTTP 客户端时,在连接后端服务主机时的 socket 超时时间设置。它影响的是 Zuul 自身作为客户端与后端服务建立连接并读取数据时的超时行为。例如,当 Zuul 直接将请求发送到后端服务,在连接建立后等待数据读取的过程中,如果超过 zuul.host.socket-timeout-millis 所设定的时间,就会触发超时异常。

它更侧重于 Zuul 本身的客户端行为,通常适用于那些没有使用 Ribbon 进行负载均衡和服务路由的场景,或者是 Zuul 对一些外部服务(非通过 Ribbon 管理的服务)的请求处理。

例如:

将路由的 service-id 注释掉,使用 url 属性指定服务具体地址,并且将 socket-timeout-millis 改为 1000,如下:

# zuul 过滤器
zuul:
  # 指定哪些是敏感头,设置为空,表示没有敏感头
  sensitive-headers:
  # 路由配置
  routes:
    service-order:
      path: /api/order/**
      #service-id: service-order
      url: http://localhost:8092/
  # 控制默认连接池属性的主机属性
  host:
    #...
    # 定义了Zuul在与后端服务建立连接后,等待读取数据的超时时间,单位是毫秒
    socket-timeout-millis: 1000
    # 指定连接池中的连接的生存时间
    time-to-live: 1
    # 指定连接池中的连接的生存时间的单位
    time-unit: HOURS

重启服务,尝试访问,读超时了,如下图:

7698d754b03cfd7844794f81fbb21743_1734059940481-7da50f48-22f0-444d-92a3-460bd3b92c69.png

查看具体错误堆栈信息,你会发现,此时使用的 HttpClient 发起 HTTP 请求,如下图:

ff782892830809dd85f87b664747200d_1734060040605-139bc1b2-9238-48d6-965e-ecc543c74512.png

点击下载/查看本教程相关资料或者源代码。
说说我的看法
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
公众号