Why Is the First Feign Call So Slow? Understanding Ribbon’s Lazy Loading and Eager‑Load Fix
The article explains that the initial Feign request is slow because Ribbon lazily creates its client and fetches the service list at first use, and shows how enabling Ribbon’s eager‑load mode pre‑warms the client to eliminate the delay.
Introduction
Feign relies on Ribbon for client‑side load balancing. When a microservice registers with Eureka or Nacos, Ribbon obtains the service list, caches it locally, and the Feign client uses this cache for remote calls.
How Ribbon Performs Load Balancing
Ribbon’s RibbonClientConfiguration injects a LoadBalancer implementation. The core interface is ILoadBalancer, which provides methods to add services, choose a server, mark a server down, and retrieve server lists (all, alive, or total).
ZoneAwareLoadBalancer Details
The default load balancer is ZoneAwareLoadBalancer, which extends DynamicServerListLoadBalancer. Its restOfInit method initializes two important functions: enableAndInitLearnNewServersFeature and updateListOfServers. The former starts a ServerListUpdater thread that continuously fetches the latest service list.
LOGGER.info("Using serverListUpdater {}", serverListUpdater.getClass().getSimpleName());
serverListUpdater.start(updateAction);Ribbon Load‑Balancing Strategies
RoundRobinRule – cycles through servers sequentially.
WeightedResponseTimeRule – prefers servers with shorter response times.
RandomRule – selects a server at random.
BestAvailableRule – chooses the server with the fewest active connections.
RetryRule – retries failed servers within a timeout.
AvailabilityFilteringRule – filters out unhealthy instances.
ZoneAvoidanceRule – applies zone‑aware filtering.
Eager‑Load Mode ("Hungry Loading")
Ribbon creates its client only when the first HTTP request occurs. This first call includes both the network latency and the time to instantiate the client and load the server list, making it noticeably slower.
@GetMapping("/requestSystem2Api")
public String requestSystem2Api(){
long startTime = System.currentTimeMillis();
R<String> stringR = iTestServiceClient.testRequestMethod();
if(stringR != null){
log.info("Response: " + stringR.getMsg());
}
long needTime = System.currentTimeMillis() - startTime;
log.info("Call duration: " + needTime);
return "";
}Log output shows the first invocation takes longer because DynamicServerListLoadBalancer loads the Feign client and performs the server‑list update. Subsequent calls are fast.
Enabling Ribbon Eager‑Load
ribbon:
nacos:
enabled: true # enable Nacos discovery
eager-load:
enabled: true # turn on eager‑load to avoid first‑call timeout
clients: Lxlxxx-system2 # specify services to pre‑load
ReadTimeout: 10000
ConnectTimeout: 10000
MaxAutoRetries: 0
MaxAutoRetriesNextServer: 1
OkToRetryOnAllOperations: falseWhen the application starts, logs confirm that the specified service ( Lxlxxx-system2) is loaded, preventing the initial timeout.
Conclusion
Enabling Ribbon’s eager‑load mode acts like a client‑side warm‑up, loading service metadata at startup. This is useful when inter‑service calls involve heavy business logic or large data, helping to avoid first‑request latency.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
