Ribbon load balancing
1.1. Load balancing principle
The bottom layer of Spring Cloud actually uses a component called Ribbon to implement the load balancing function.
So the request we sent was obviously http://userservice/user/1, why did it become http://localhost:8081?
1.2. Source code tracking
Why can we access it just by entering the service name? You also need to obtain the IP and port before.
Apparently someone helped us get the IP and port of the service instance based on the service name. That is LoadBalancerInterceptor
, this class will intercept the RestTemplate request, then obtain the service list from Eureka based on the service id, and then use the load balancing algorithm to obtain the real service address information and replace the service id.
We conduct source code tracking:
1)LoadBalancerIntercepor
You can see that the intercept method here intercepts the user's HttpRequest request and then does several things:
request.getURI()
: Get the request uri, in this case http://user-service/user/8originalUri.getHost()
: Get the host name of the uri path, which is actually the service id.user-service
this.loadBalancer.execute()
: Process service id and user requests.
Here this.loadBalancer
is LoadBalancerClient
the type, let's continue to follow.
2)LoadBalancerClient
Continue to follow the execute method:
The code is like this:
- getLoadBalancer(serviceId): Get the ILoadBalancer based on the service id, and the ILoadBalancer will take the service id to get the service list from eureka and save it.
- getServer(loadBalancer): Use the built-in load balancing algorithm to select one from the service list. In this example, you can see that the service of port 8082 has been obtained
After being released, I visited and tracked it again and found that I got 8081:
Sure enough, load balancing was achieved.
3) Load balancing strategy IRule
In the code just now, you can see that obtaining services uses a getServer
method to perform load balancing:
Let’s continue to follow up:
Continuing to trace the source code chooseServer method, I found this piece of code:
Let’s see who this rule is:
The default value of the rule here is one RoundRobinRule
, see the introduction of the class:
Isn't this what polling means?
At this point, we have a clear understanding of the entire load balancing process.
4) Summary
The bottom layer of SpringCloudRibbon uses an interceptor to intercept the request sent by RestTemplate and modify the address. Let’s sum it up with a picture:
The basic process is as follows:
- Intercept our RestTemplate request http://userservice/user/1
- RibbonLoadBalancerClient will get the service name from the request url, which is user-service
- DynamicServerListLoadBalancer pulls the service list from eureka based on user-service
- eureka returns the list, localhost:8081, localhost:8082
- IRule utilizes built-in load balancing rules and selects one from the list, such as localhost:8081
- RibbonLoadBalancerClient modifies the request address, replaces userservice with localhost:8081, gets http://localhost:8081/user/1, and initiates a real request
1.3. Load balancing strategy
1.3.1. Load balancing strategy
Load balancing rules are defined in the IRule interface, and IRule has many different implementation classes:
The meanings of the different rules are as follows:
Built-in load balancing rule class | Rule description |
---|---|
RoundRobinRule | Simply poll the service list to select a server. It is Ribbon's default load balancing rule. |
AvailabilityFilteringRule | Ignore the following two types of servers: (1) By default, if this server fails to connect three times, this server will be set to a "short circuit" state. The short circuit state will last for 30 seconds. If the connection fails again, the duration of the short circuit will increase geometrically. (2) Servers with too high concurrency. If the number of concurrent connections to a server is too high, clients configured with AvailabilityFilteringRule rules will also ignore it. The upper limit of the number of concurrent connections can be configured by the client's ..ActiveConnectionsLimit property. |
WeightedResponseTimeRule | Give each server a weight value. The longer the server response time, the smaller the weight of the server. This rule will randomly select servers, and this weight value will affect server selection. |
ZoneAvoidanceRule | Server selection is based on servers available in the region. Use Zone to classify servers. This Zone can be understood as a computer room, a rack, etc. Then poll multiple services in the Zone. |
BestAvailableRule | Ignore those servers that are short-circuited and choose servers with lower concurrency numbers. |
RandomRule | Randomly select an available server. |
RetryRule | Selection logic of retry mechanism |
The default implementation is ZoneAvoidanceRule, which is a polling scheme
1.3.2. Customized load balancing strategy
Load balancing rules can be modified by defining IRule implementations in two ways:
- Code method: In the OrderApplication class in order-service, define a new IRule:
@Bean
public IRule randomRule(){
return new RandomRule();
}
- Configuration file method: In the application.yml file of order-service, adding new configuration can also modify the rules:
userservice: # 给某个微服务配置负载均衡规则,这里是userservice服务
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 负载均衡规则
Note that the default load balancing rules are generally used without modification.
1.4.Hungry loading
Ribbon uses lazy loading by default, that is, the LoadBalanceClient will not be created until the first access, and the request time will be very long.
Hungry loading will be created when the project starts, reducing the time of the first visit. Enable hungry loading through the following configuration:
ribbon:
eager-load:
enabled: true
clients: userservice
Study notes, compiled from Dark Horse Programmer