Home

Service Invocation

Li

Li Wei

December 27, 20258 min read

Service Invocation

Overview

In the introductory section, we briefly described how the RestTemplate API enables remote calls between services by sending HTTP requests. However, this approach differs greatly from local method calls, leading to an inconsistent programming experience—sometimes it feels like a remote call, other times like a local call. Therefore, we need to change the development model for remote calls so that remote calls are as simple as local method calls. This is where a component comes into play: we need a remote‑call component.

Ribbon (Overview)

Basic Introduction

Spring Cloud Ribbon is a load‑balancing tool built on Netflix Ribbon. It provides client‑side load‑balancing algorithms and service invocation capabilities. The Ribbon client component offers a range of configurable options such as connection timeout, retries, etc.

Official site: (now in maintenance mode, will be replaced by Load Balancer in the future)

Load balancing (LB) distributes user requests across multiple services, achieving high availability (HA). Common load‑balancing algorithms:

  • Round‑robin: selects the first healthy backend server in the pool, then proceeds sequentially.
  • Least connections: prefers the server with the fewest active connections (i.e., the least load), useful for long‑lived sessions.
  • Hashing: uses a hash of the request source IP to pick a target server, helping ensure a particular user consistently reaches the same server—useful when the application maintains state per user.

Ribbon vs. Nginx Load Balancing

  • Nginx performs server‑side load balancing: all client requests go to Nginx, which then forwards them according to its policies.
  • Ribbon performs client‑side load balancing: when invoking a microservice, it retrieves the service list from the registry, caches it locally in the JVM, and then makes RPC calls directly.

Centralized LB vs. In‑process LB

  • Centralized LB: an independent load‑balancer (e.g., Nginx) sits between consumers and providers, forwarding requests based on a strategy.
  • In‑process LB: the LB logic is embedded in the consumer. The consumer queries the service registry for available instances and selects one locally. Ribbon belongs to this category.

Workflow

Spring Cloud Ribbon uses an interceptor that captures RestTemplate requests and rewrites the address. The diagram below summarizes the process:

  1. Intercept our RestTemplate request http://userservice/user/1.
  2. RibbonLoadBalancerClient extracts the service name from the URL, i.e., user-service.
  3. DynamicServerListLoadBalancer queries eureka for the list of instances of user-service.
  4. eureka returns the list, e.g., localhost:8081, localhost:8082.
  5. IRule applies the built‑in load‑balancing rule to pick one, say localhost:8081.
  6. RibbonLoadBalancerClient rewrites the request URL to http://localhost:8081/user/1 and sends the real request.
Source Code Walkthrough

LoadBalancerInterceptor

The intercept method captures the user's HttpRequest and performs several actions:

  • request.getURI() obtains the request URI, e.g., http://user-service/user/8.
  • originalUri.getHost() extracts the host part of the URI, which is the service ID, user-service.
  • this.loadBalancer.execute() processes the service ID and the user request.

Here, this.loadBalancer is of type LoadBalancerClient; we continue tracing.

LoadBalancerClient

Continuing into the execute method:

  • getLoadBalancer(serviceId) retrieves an ILoadBalancer for the service ID; the ILoadBalancer fetches the instance list from Eureka and caches it.
  • getServer(loadBalancer) uses the built‑in load‑balancing algorithm to select an instance. In this example, it picks the service on port 8082.

After the request passes through, a subsequent trace shows the selection of port 8081—confirming that load balancing works.

Ribbon uses lazy initialization by default, creating LoadBalanceClient only on the first request, which can cause a long initial latency. Eager initialization creates it at application startup, reducing the first‑call delay. Enable eager loading with the following configuration:

## (configuration snippet)

Load‑Balancing Strategies

The core Ribbon component is the IRule interface. Main implementations include:

  • RoundRobinRule: Round‑robin
  • RandomRule: Random
  • RetryRule: Retry on failure after attempting with RoundRobinRule
  • WeightedResponseTimeRule: Weighted response time (faster instances get higher weight)
  • BestAvailableRule: Filters out instances in a circuit‑breaker state and selects the one with the fewest concurrent connections
  • AvailabilityFilteringRule: Ignores two kinds of servers:
    • By default, a server that fails three consecutive connections is marked “tripped.” The tripped state lasts 30 seconds and grows exponentially with repeated failures.
    • Servers with excessively high concurrent connections. The limit can be configured via the client’s . .ActiveConnectionsLimit property.
  • ZoneAvoidanceRule: Default rule—considers both the server’s zone performance and its availability.

Note: The official docs warn that custom load‑balancing configuration classes must not reside in the package scanned by @ComponentScan (or its sub‑packages). Generally, stick with the default rule and avoid modifications.

OpenFeign

Basic Introduction

Feign is a declarative web‑service client that simplifies writing HTTP clients: you just define an interface and add the @Feign annotation. It can be combined with Eureka and Ribbon for load balancing, so it’s typically used on the consumer side.

OpenFeign extends Feign with Spring MVC annotations, and the @FeignClient annotation can parse interfaces annotated with @RequestMapping, generating implementations via dynamic proxies that handle load balancing and service calls.

Advantages: By wrapping RestTemplate’s HTTP handling, Feign provides a templated way to invoke services. Since a service may be called from many places, annotating a microservice interface once with an EE annotation (presumably @FeignClient) suffices for all callers.

Basic Usage

Steps to use Feign:

  1. Add the required dependencies.
  2. Annotate the main class with @EnableFeignClients.
  3. Define a FeignClient interface.
  4. Replace RestTemplate calls with methods defined in the FeignClient.
@FeignClient("provider name") Annotation Rules
  • The declared method signatures must match those of the provider microservice’s controller methods.
  • If parameters are needed, @RequestParam, @RequestBody, and @PathVariable must also be added.
Refactor Consumer Service
  • Add the Maven dependency.
  • In application.yml, configure the service not to register itself with Eureka.
  • Enable Feign in the main application class.
  • Create a Service interface: annotate with PaymentFeignService and @FeignClient to wrap Feign calls.
  • In ServiceImpl, replace code with direct calls to the Feign client.

Timeout Issues

Feign relies on Ribbon for load balancing and timeout control. Configure Feign client timeout values accordingly.

Connection Pool

Feign’s underlying HTTP calls depend on other frameworks. Supported HTTP client implementations include:

  • HttpURLConnection (default, no connection pool)
  • Apache HttpClient (supports pooling)
  • OKHttp (supports pooling)

Therefore, it’s common to replace the default HttpURLConnection with a pooled client such as OKHttp.

<!-- Add dependency in cart-service pom.xml -->

Enable the pool in application.yml:

## Feign connection pool settings

Restart the service and the pool becomes active.

Best Practices

To avoid duplicating client interfaces, consider two extraction strategies:

  • Strategy 1: Extract common interfaces into a separate module outside the microservices. Simpler and clearer project structure, but increases overall coupling.
  • Strategy 2: Each microservice creates its own module. More work and a more complex structure, but reduces inter‑service coupling.

Logging Levels

Feign provides logging capabilities. Configure the log level to see request details:

  • NONE – default, no logs.
  • BASIC – logs request method, URL, response status, and execution time.
  • HEADERS – adds request and response headers.
  • FULL – adds request/response bodies and metadata.

By default, Feign uses NONE, so no request logs appear.

Defining a Log Level
  1. Create a configuration class that sets Feign’s log level.
  2. Register the class:
    • Local: apply to a specific FeignClient.
    • Global: configure in @EnableFeignClients to affect all FeignClients.

Propagating User Information

Frontend requests pass through the gateway to microservices. Because we have filters and interceptors, a microservice can easily obtain the logged‑in user’s info. However, some business flows are more complex and require calls to multiple downstream services. For example, an order service creates an order, then calls the product service to decrement inventory and the cart service to clear the user’s cart. The cart service needs to know which user is making the request, but the order service does not forward user information when calling the cart service, leaving the cart service unaware of the current user.

Since microservices obtain user info from request headers via interceptors, we must inject the user information into the request headers whenever a microservice initiates a call.

Calls between microservices are made with OpenFeign, not with manually crafted HTTP requests. To automatically attach the logged‑in user’s data to every OpenFeign request, we use Feign’s interceptor interface: feign.RequestInterceptor.

Implement this interface, override the apply method, and use the RequestTemplate class to add the user info to the request headers. Consequently, each OpenFeign request will carry the user data.

Create the interceptor bean in a configuration class, and the user information will be propagated automatically during inter‑service OpenFeign calls.


Originally written by Li Wei (李唯_) and published in Chinese on 后端技术栈全书 (Full-Stack Backend Engineering). Translated and adapted for DriftSeas with permission.

Keep reading

More related articles from DriftSeas.