Ribbon is a client load balancer, given the application of some of the power to dominate HTTP and TCP behavior, which can be learned, here's client load balancing load balancing is an internal process. Ribbon in SpringCloud ecological indispensable component, without the Ribbon, services can not scale. Feign, Zuul have been integrated Ribbon.
1. Ribbon load balancing strategy
The Ribbon provides seven load balancing strategy
Strategy | name | description |
---|---|---|
RandomRule | Random Strategy | Server randomly selected |
RoundRobinRule | Polling Policy | Server in order to cycle |
RetryRule | Retry strategy | In a configurable time period, when the selected Server is unsuccessful, it has been trying to select one of the available Server |
BestAvailableRule | Minimum concurrency strategy | One by one investigation Server, Server is opened if the circuit breaker is ignored, select the lowest concurrent connections Server not be ignored in Server |
AvailabilityFilteringRule | Available filter test | Connection failure has been filtered off, and was not labeled circuit tripped (i.e., not available) the Server, the Server to filter out high concurrency |
ResponseTimeWeightedRule | Response time weighting strategy | The response time of the assigned weight Server weight, the longer the response time, the lower the weight, the lower the probability of being selected to |
ZoneAvoidanceRule | Regional Balance Policy | Integrated Area Analyzing polling availability and performance of Server Server Server selection, and determines a running performance of the AWS Zone is available, unavailable Zone remove all Server |
Ribbon default load balancing strategy is polling policy .
2. Ribbon Configuration
2.1 load balancing policy configuration
You can configure each service load balancing policy in the configuration file
{instance-id}: # instance-id 即被调用服务名称
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
# NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #配置规则 随机
# NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule #配置规则 轮询
# NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RetryRule #配置规则 重试
# NFLoadBalancerRuleClassName: com.netflix.loadbalancer.WeightedResponseTimeRule #配置规则 响应时间权重
# NFLoadBalancerRuleClassName: com.netflix.loadbalancer.BestAvailableRule #配置规则 最空闲连接策略
Timeout and retry configuration 2.2
{instance-id}: # instance-id 指的是被调用者的服务名称
ribbon:
ConnectTimeout: 30000 # 链接超时时间
ReadTimeout: 30000 # 读超时时间
MaxAutoRetries: 1 # 对第一次请求的服务的重试次数
MaxAutoRetriesNextServer: 1 # 要重试的下一个服务的最大数量(不包括第一个服务)
OkToRetryOnAllOperations: true # 是否对 连接超时、读超时、写超时 都进行重试
2.3 hunger load
Ribbon when performing load balancing is not started when the load on the line on paper, but in practice the request, only to request context information acquisition callee ip, port, when this mode is inferior in a network environment, They tend to make a cause timeouts, resulting in failure of the first call. At this point you need to specify Ribbon client, a hunger load , namely: load at startup good context.
ribbon:
eager-load:
enabled: true
clients: spring-cloid-ribbon-provider
At this point start consumer, you will see the print control information is as follows:
Client: spring-cloid-ribbon-provider instantiated a LoadBalancer: DynamicServerListLoadBalancer:{NFLoadBalancer:name=spring-cloid-ribbon-provider,current list of Servers=[],Load balancer stats=Zone stats: {},Server stats: []}ServerList:null
Using serverListUpdater PollingServerListUpdater
DynamicServerListLoadBalancer for client spring-cloid-ribbon-provider initialized: DynamicServerListLoadBalancer:{NFLoadBalancer:name=spring-cloid-ribbon-provider,current list of Servers=[],Load balancer stats=Zone stats: {},Server stats: []}ServerList:org.springframework.cloud.netflix.ribbon.eureka.DomainExtractingServerList@79e7188e
You can see when you start to load up spring-cloud-ribbon-provider
, and boundLoadBalancer。
2.4 common arrangement
Configuration Item | Explanation |
---|---|
{instance-id}:ribbon.NFLoadBalancerClassName | Load balancing refers classpath |
{instance-id}:ribbon:NFLoadBalancerRuleClassName | Specifies the load balancing algorithm classpath |
{instance-id}:ribbom:NFLoadBalancerPingClassName | Specifies the survival of the class path testing services |
{instance-id}:ribbon:NIWSServerListClassName | Specify a class path to get the list of services |
{instance-id}:ribbon:NIWSServerListFilterClassName | Filter the specified service implementation class path |
3. Works
3.1 Ribbon core interface
interface | description | The default implementation class |
---|---|---|
IClientConfig | Ribbon is defined in the configuration management interface | DefaultClientConfigImpl |
IRule | The definition of the Ribbon interface load balancing strategy | RoundRobinRule |
IPing | Ping service definitions regularly check the availability of an interface | DummyPing |
ServerList<Server> | Get a list of methods defined service interfaces | ConfigurationBasedServerList |
ServerListFilter<Server> | Define a specific list of methods expectations for service interface | ZonePreferenceServerListFilter |
ILoadBalanacer | Interface core of the method defined load balancing service selection | BaseLoadBalancer |
ServerListUpdater | Define the interface dynamically updated list of services for DynamicServerListLoadBalancer | PollingServerListUpdater |
The operating principle 3.2 Ribbon
Ribbon load balancing, basic usage is to inject a RestTemplate, and use @LoadBalanced on RestTemplate, in order to make RestTemplate with load balancing.
3.2.1 @LoadBalanced
This annotation label, a RestTemplate use LoadBalancerClient.
/**
* Annotation to mark a RestTemplate bean to be configured to use a LoadBalancerClient
* @author Spencer Gibb
*/
@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Qualifier
public @interface LoadBalanced {
}
LoadBalancerClient:
/**
* Represents a client side load balancer
* @author Spencer Gibb
*/
public interface LoadBalancerClient extends ServiceInstanceChooser {
<T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException;
<T> T execute(String serviceId, ServiceInstance serviceInstance, LoadBalancerRequest<T> request) throws IOException;
URI reconstructURI(ServiceInstance instance, URI original);
}
LoadBalancerClient has expanded ServiceInstanceChooser Interface
public interface ServiceInstanceChooser {
ServiceInstance choose(String serviceId);
}
Description:
ServiceInstance choose(String serviceId)
: According to the serviceId, in conjunction with the load balancer, to select a service instance<T> T execute(String serviceId, LoadBalancerRequest<T> request)
: Use LoadBalancer for the top of serviceInstance service execution request<T> T execute(String serviceId, ServiceInstance serviceInstance, LoadBalancerRequest<T> request)
: Use ServiceInstance LoadBalancer for execution request from the service specified, a method is overloaded, the details of implementation of the method on aURI reconstructURI(ServiceInstance instance, URI original)
: Using the host ip, port to build a specific URI, RIbbon for internal use. Ribbon using the service URI names as host. Such as: HTTP: // instance-the above mentioned id / path / to / Service
3.2.2 LoadBalancer initialization
LoadBalancerAutoConfiguration
Is the key to the core code Ribbon load balancing load the class initialization, start as follows:
@Configuration
@ConditionalOnClass(RestTemplate.class)
@ConditionalOnBean(LoadBalancerClient.class)
@EnableConfigurationProperties(LoadBalancerRetryProperties.class)
public class LoadBalancerAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public LoadBalancerRequestFactory loadBalancerRequestFactory(
LoadBalancerClient loadBalancerClient) {
return new LoadBalancerRequestFactory(loadBalancerClient, transformers);
}
@Configuration
@ConditionalOnMissingClass("org.springframework.retry.support.RetryTemplate")
static class LoadBalancerInterceptorConfig {
@Bean
public LoadBalancerInterceptor ribbonInterceptor(
LoadBalancerClient loadBalancerClient,
LoadBalancerRequestFactory requestFactory) {
return new LoadBalancerInterceptor(loadBalancerClient, requestFactory);
}
@Bean
@ConditionalOnMissingBean
public RestTemplateCustomizer restTemplateCustomizer(
final LoadBalancerInterceptor loadBalancerInterceptor) {
return restTemplate -> {
List<ClientHttpRequestInterceptor> list = new ArrayList<>(
restTemplate.getInterceptors());
list.add(loadBalancerInterceptor);
restTemplate.setInterceptors(list);
};
}
}
}
It can be seen on the class annotations @ConditionalOnClass(RestTemplate.class)
, and @ConditionalOnBean(LoadBalancerClient.class)
must have a project in the current RestTemplate
instance, must have been initialized LoadBalancerClient
implementation class, will be loaded LoadBalancer automatic assembly.
Which LoadBalancerRequestFactory
is used to create LoadBalancerRequest
, for LoadBalancerInterceptor
use (not in low version), LoadBalancerInterceptorConfig
maintained a LoadBalancerInterceptor
, RestTemplateCustomizer
examples.
- LoadBalancerInterceptor: intercept every HTTP request, the request is load balancing to bind into the Ribbon of Life Cycle
- RestTemplateCustomizer: Binding LoadBalancerInterceptor interceptors for each RestTemplate
3.2.3 LoadBalancerInterceptor
public class LoadBalancerInterceptor implements ClientHttpRequestInterceptor {
private LoadBalancerClient loadBalancer;
private LoadBalancerRequestFactory requestFactory;
public LoadBalancerInterceptor(LoadBalancerClient loadBalancer, LoadBalancerRequestFactory requestFactory) {
this.loadBalancer = loadBalancer;
this.requestFactory = requestFactory;
}
public LoadBalancerInterceptor(LoadBalancerClient loadBalancer) {
// for backwards compatibility
this(loadBalancer, new LoadBalancerRequestFactory(loadBalancer));
}
@Override
public ClientHttpResponse intercept(final HttpRequest request, final byte[] body,
final ClientHttpRequestExecution execution) throws IOException {
final URI originalUri = request.getURI();
String serviceName = originalUri.getHost();
Assert.state(serviceName != null, "Request URI does not contain a valid hostname: " + originalUri);
return this.loadBalancer.execute(serviceName, requestFactory.createRequest(request, body, execution));
}
}
LoadBalancerInterceptor use ClientHttpRequestInterceptor
for each HTTP request to intercept this class is maintained Spring request interceptor. Can be seen, the use of intercepted requests LoadBalancerClient
the execute method of processing request (service name due RestTemplate used as host, so in this case getHosts () acquired service name), LoadBalancerClient only one implementation class: RibbonLoadBalancerClient
, particularly the execute method is as follows:
@Override
public <T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException {
ILoadBalancer loadBalancer = getLoadBalancer(serviceId);
Server server = getServer(loadBalancer);
if (server == null) {
throw new IllegalStateException("No instances available for " + serviceId);
}
RibbonServer ribbonServer = new RibbonServer(serviceId, server, isSecure(server,
serviceId), serverIntrospector(serviceId).getMetadata(server));
return execute(serviceId, ribbonServer, request);
}
It can be seen in the source code first gets a LoadBalancer, go get a Server, then this is the specific service instance Server encapsulates. Since Server is a specific service instance, then, getServer (loadBalancer) is the local load balancing occurs.
protected Server getServer(ILoadBalancer loadBalancer) {
if (loadBalancer == null) {
return null;
}
return loadBalancer.chooseServer("default"); // TODO: better handling of key
}
View chooseServer specific implementation method (BaseLoadBalancer):
public Server chooseServer(Object key) {
if (counter == null) {
counter = createCounter();
}
counter.increment();
if (rule == null) {
return null;
} else {
try {
return rule.choose(key);
} catch (Exception e) {
logger.warn("LoadBalancer [{}]: Error choosing server for key {}", name, key, e);
return null;
}
}
}
rule.choose (key) of the rule, is IRule, and IRule is Ribbon load balancing strategy. It can be proved, HTTP request load balancing policy domain associated up.
3.2.4 IRule
public interface IRule{
/*
* choose one alive server from lb.allServers or
* lb.upServers according to key
*
* @return choosen Server object. NULL is returned if none
* server is available
*/
public Server choose(Object key);
public void setLoadBalancer(ILoadBalancer lb);
public ILoadBalancer getLoadBalancer();
}
In IRule we have defined three methods, choose a method to realize implementation class will be added to a particular load balancing policy logic, associated with the other two methods ILoadBalancer.
During the call, Ribbon by ILoadBalancer association IRule, ILoadBalancer of chooseServer method will be converted to invoke choose method IRRule abstract class AbstractLoadBalancerRule
implements these two methods, which will be associated with IRule ILoadBalancer up.