当前位置: 代码网 > it编程>编程语言>Java > Feign 第一次调用为什么会很慢?

Feign 第一次调用为什么会很慢?

2025年12月16日 Java 我要评论
个人理解先说下我自己的理解因为Feign的调用是基于Ribbon做负载,在第一次调用的时候,需要对注册中心进行注册创建对应的Client,所以在第一次调用的时

个人理解

先说下我自己的理解
因为Feign的调用是基于Ribbon做负载,在第一次调用的时候,需要对注册中心进行注册创建对应的Client,所以在第一次调用的时候,等同于创建client的时间加上请求的时间,所以才会慢。
目前比较直接的解决方式就是开启Ribbon的饥饿模式

前言

首先要了解Feign是如何进行远程调用的,这里面包括,注册中心、负载均衡、FeignClient之间的关系,微服务通过不论是eureka、nacos也好注册到服务端,Feign是靠Ribbon做负载的,而Ribbon需要拿到注册中心的服务列表,将服务进行负载缓存到本地,然后FeignClient客户端在进行调用,大概就是这么一个过程。

Ribbon是如何进行负载的

首先我们要清楚Ribbon是如何进行负载的,也就是如何获取nacos、eureka的服务列表,这个很关键。
在这里插入图片描述

RibbonClientConfiguration

RibbonClientConfiguration类中通过LoadBalancer,我们知道ribbon是靠LoadBalancer做负载的

无非就是ILoadBalancer接口的方法,依次是添加新的服务、在负载均衡里选择一个服务、markServerDown服务下线、获取服务列表、获取存活的服务器、获取所有服务器(包括健康和不健康的)

在这里插入图片描述
addServers :
服务器的初始列表。这个APl还用于在以后添加额外的服务器相同的逻辑服务器可以添加多次 参数:newServers-要添加的新服务器

chooseServer:
从负载平衡器中选择一个服务器。Params:key-如果负载平衡器不使用此参数,则负载平衡器可以用来确定返回null的服务器的对象。返回:选择的服务器

markServerDown:
为了被负载平衡器的客户端调用以通知服务器已关闭,否则LB将认为它仍然活动,直到下一个Ping周期——可能(假设LB lmpl执行Ping)
参数:server-标记为关闭的服务器

getServerList: 该方法已弃用

getReachableServers:仅返回已启动且可访问的服务器

ZoneAwareLoadBalancer

loadBalancer默认的是ZoneAwareLoadBalancer负载均衡器,通过继承父类DynamicServerListLoadBalancer的restOfInit方法,里面比较重要的两个方法,enableAndInitLearnNewServersFeature和updateListOfServers方法
在这里插入图片描述
enableAndInitLearnNewServersFeature方法里面

LOGGER.info("Using serverListUpdater {}", serverListUpdater.getClass().getSimpleName());
serverListUpdater.start(updateAction);

ServerListUpdater.start方法的实现,通过自定义线程去拿,这就是获取服务列表:
在这里插入图片描述

Ribbon负载均衡策略

  • RoundRobinRule(轮询策略,按照服务顺序依次循环调用)

  • WeightedResponseTimeRule(权重比策略,优先选择权重比高的服务,也就是服务响应时间比较短的,响应时间越长权重比越低)

  • RandomRule(随机策略,服务提供者列表随机选择一个服务)

  • BestAvailableRule(最小连接数策略,获取服务列表中连接数最小的服务实例)

  • RetryRule(重试策略,重试获取已经失效的服务,指定时间没有获取到返回NULL)

  • AvailabilityFilteringRule(可用性敏感策略,过滤非健康服务实例,选择lianji)

  • ZoneAvoidanceRule(区域敏感策略)

关于自定义负载均衡策略,可以看: https://juejin.cn/post/7155754618486521869

Ribbon-eager-load(饥饿加载)模式

Ribbon对于负载Client是在服务启动后,发生调用的时候才会去创建Client,所以在第一次发生http请求调用的时候,不光要算上http的请求时间,还要算上Client的创建时间,所以第一次调用的时候才会很慢,写个方法调用下;

System 服务调用System2服务

@GetMapping("/requestSystem2Api")
public String requestSystem2Api(){
    long startTime = System.currentTimeMillis();
    R<String> stringR = iTestServiceClient.testRequestMethod();
    if (null !=stringR){
        log.info("接口返回:"+stringR.getMsg());
    }
    long needTime = System.currentTimeMillis() - startTime;
    log.info("接口调用需要的时间:"+needTime);
    return "";
}

从调用日志可以看出,第一次调用System2服务,Ribbon的DynamicServerListLoadBalancer会将feign客户端进行负载,然后进行调用,第一次调用的时间就是会长一些,第二次调用直接进行请求可以看到调用时间很快。

开启Ribbon饥饿加载

ribbon:
  nacos:
    enabled: true # 开启naocos轮询
  eager-load:
   enabled: true  # 开启Ribbon的饥饿加载模式(防止第一次请求超时的问题)
   clients: Lxlxxx-system2 # 指定需要开启的服务(需要开启Ribbon的饥饿加载模式)
   ReadTimeout: 10000
   ConnectTimeout: 10000
   MaxAutoRetries: 0
   MaxAutoRetriesNextServer: 1
   OkToRetryOnAllOperations: false

在项目启动的时候,可以从日志看到,已经把Lxlxxx-system2服务进行加载,从而避免了第一次请求超时的情况

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com