Introduce SpringCloud Ribbon in detail

  • 2020-12-21 18:04:41
  • OfStack

1: What is Ribbon?

Ribbon is an open source project released by Netflix. Its main function is to provide software load balancing algorithms on the client side, connecting Netflix's mid-tier services at one start. The Ribbon client component provides a complete set of configuration items such as connection timeouts, retries, etc. Simply put, list all the machines after Load Balancer (LB for short) in the configuration file, and Ribbon will automatically help you connect the machines based on certain rules (such as simple polling, then connect, etc.). It is also easy to implement a custom load balancing algorithm using Ribbon.

2. Classification of LB scheme

The current mainstream LB schemes can be divided into two categories: one is centralized LB, which uses independent LB facilities (either hardware, such as F5, or software, such as nginx) between the consumer and provider of the service. The facility is responsible for forwarding access requests to the provider of the service through a certain policy. The other is in-process LB, which integrates LB logic into the consumer, who learns from the service registry what addresses are available, and then selects an appropriate server from those addresses itself. Ribbon is one of the latter; it is just a class library, integrated into the consumer process, through which the consumer gets the address of the service provider.

3: Main components and workflow of Ribbon

The core components of Ribbon (all interface types) are as follows:

ServerList

Used to get a list of addresses. It can be either static (providing a fixed set of addresses) or dynamic (periodically querying the address list from the registry).

ServerListFilter

Used only when dynamic ServerList is used to override 1 part of the address in the original list of services using 1 determination policy.

IRule

Select 1 final service address as the LB result. Selection strategies include polling, response time weighting, circuit breakers (when Hystrix is available), and so on.

When Ribbon works, it first obtains the list of all available services through ServerList, then overrides 1 part of the addresses through ServerListFilter, and finally selects 1 server among the remaining addresses through IRule as the final result.

4: Introduction of main load balancing strategies provided by Ribbon

1: Simple polling load balancing (RoundRobin)

The requests are scheduled to different servers in turn by polling, that is, i = (i + 1) mod n for each scheduling, and the i server is selected.

2: Random Load balancing (Random)

Randomly select Server with state UP

3: Weighted response time Load balancing (WeightedResponseTime)

1 weight is allocated according to the corresponding time. The longer the corresponding time is, the smaller the weight is, the less likely it is to be selected.

4: Region-aware polling load balancing (ZoneAvoidanceRule)

Compound judgment of server area performance and server availability selection server

Ribbon comes with its own load balancing strategy comparison

策略名 策略声明 策略描述 实现说明
BestAvailableRule public class BestAvailableRule extends ClientConfigEnabledRoundRobinRule 选择1个最小的并发请求的server 逐个考察Server,如果Server被tripped了,则忽略,在选择其中ActiveRequestsCount最小的server
AvailabilityFilteringRule public class AvailabilityFilteringRule extends PredicateBasedRule 过滤掉那些因为1直连接失败的被标记为circuit tripped的后端server,并过滤掉那些高并发的的后端server(active connections 超过配置的阈值) 使用1个AvailabilityPredicate来包含过滤server的逻辑,其实就就是检查status里记录的各个server的运行状态
WeightedResponseTimeRule public class WeightedResponseTimeRule extends RoundRobinRule 根据相应时间分配1个weight,相应时间越长,weight越小,被选中的可能性越低。 1 个后台线程定期的从status里面读取评价响应时间,为每个server计算1个weight。Weight的计算也比较简单responsetime 减去每个server自己平均的responsetime是server的权重。当刚开始运行,没有形成statas时,使用roubine策略选择 server。
RetryRule public class RetryRule extends AbstractLoadBalancerRule 对选定的负载均衡策略机上重试机制。 在1个配置时间段内当选择server不成功,则1直尝试使用subRule的方式选择1个可用的server
RoundRobinRule public class RoundRobinRule extends AbstractLoadBalancerRule roundRobin方式轮询选择server 轮询index,选择index对应位置的server
RandomRule public class RandomRule extends AbstractLoadBalancerRule 随机选择1个server 在index上随机,选择index对应位置的server
ZoneAvoidanceRule public class ZoneAvoidanceRule extends PredicateBasedRule 复合判断server所在区域的性能和server的可用性选择server 使 用ZoneAvoidancePredicate和AvailabilityPredicate来判断是否选择某个server,前1个判断判定1个 zone的运行性能是否可用,剔除不可用的zone(的所有server),AvailabilityPredicate用于过滤掉连接数过多的 Server。

5: Ribbon alone

Create an maven project name ribbon_client

pom content


    <dependencies>
    <dependency>
      <groupId>com.netflix.ribbon</groupId>
      <artifactId>ribbon-core</artifactId>
      <version>2.2.0</version>
    </dependency>

    <dependency>
      <groupId>com.netflix.ribbon</groupId>
      <artifactId>ribbon-httpclient</artifactId>
      <version>2.2.0</version>
    </dependency>
  </dependencies>

sample- ES113en. properties configuration file


# Max number of retries  
sample-client.ribbon.MaxAutoRetries=1

# Max number of next servers to retry (excluding the first server) 
sample-client.ribbon.MaxAutoRetriesNextServer=1

# Whether all operations can be retried for this client 
sample-client.ribbon.OkToRetryOnAllOperations=true  

# Interval to refresh the server list from the source 
sample-client.ribbon.ServerListRefreshInterval=2000

# Connect timeout used by Apache HttpClient 
sample-client.ribbon.ConnectTimeout=3000

# Read timeout used by Apache HttpClient 
sample-client.ribbon.ReadTimeout=3000

# Initial list of servers, can be changed via Archaius dynamic property at runtime 
sample-client.ribbon.listOfServers=www.sohu.com:80,www.163.com:80,www.sina.com.cn:80

sample-client.ribbon.EnablePrimeConnections=true 

RibbonMain code


import java.net.URI;
import com.netflix.client.ClientFactory;
import com.netflix.client.http.HttpRequest;
import com.netflix.client.http.HttpResponse;
import com.netflix.config.ConfigurationManager;
import com.netflix.loadbalancer.ZoneAwareLoadBalancer;
import com.netflix.niws.client.http.RestClient;
public class RibbonMain {
  public static void main( String[] args ) throws Exception { 
    ConfigurationManager.loadPropertiesFromResources("sample-client.properties"); 
    System.out.println(ConfigurationManager.getConfigInstance().getProperty("sample-client.ribbon.listOfServers")); 
    RestClient client = (RestClient)ClientFactory.getNamedClient("sample-client"); 
    HttpRequest request = HttpRequest.newBuilder().uri(new URI("/")).build(); 
    for(int i = 0; i < 4; i ++) { 
      HttpResponse response = client.executeWithLoadBalancer(request); 
      System.out.println("Status for URI:" + response.getRequestedURI() + " is :" + response.getStatus()); 

    } 
    ZoneAwareLoadBalancer lb = (ZoneAwareLoadBalancer) client.getLoadBalancer(); 
    System.out.println(lb.getLoadBalancerStats()); 
    ConfigurationManager.getConfigInstance().setProperty("sample-client.ribbon.listOfServers", "ccblog.cn:80,www.linkedin.com:80"); 
    System.out.println("changing servers ..."); 
    Thread.sleep(3000); 
    for(int i = 0; i < 3; i ++) { 
      HttpResponse response = client.executeWithLoadBalancer(request); 
      System.out.println("Status for URI:" + response.getRequestedURI() + " is :" + response.getStatus()); 
    } 
    System.out.println(lb.getLoadBalancerStats()); 
  } 
} 

Code parsing

Load attributes using Archaius ConfigurationManager;

Create client and load balancer using ClientFactory;

Use builder to build http requests. Note that we only support the path of the "/" part of URI. 1 once the server is selected by the load balancer, the client will calculate the complete URI.

Call API client.executeWithLoadBalancer (), not exeucte() API;

Dynamically modify server pool in configuration;

Wait for the server list to refresh (the refresh interval defined in the configuration file is 3 seconds);

Prints out server statistics recorded by the load balancer.

6: Ribbon combined with eureka

Start the eureka_register_service project (registry) and biz-service-0 project (Service Producer)

Create maven Project eureka_ribbon_client The project startup and associated configuration depends on eureka_register_service and biz-service-0

pom join


<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>1.4.3.RELEASE</version>
  <relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>

  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-ribbon</artifactId>
  </dependency>

  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-eureka</artifactId>
  </dependency>

  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
  </dependency>

  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
  </dependency>
</dependencies>

<dependencyManagement>
  <dependencies>
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-dependencies</artifactId>
    <version>Brixton.RELEASE</version>
    <type>pom</type>
    <scope>import</scope>
  </dependency>
  </dependencies>
</dependencyManagement> 

In the application main class, add the discovery service capability via the @EnableDiscoveryClient annotation. Create an instance of RestTemplate and enable load balancing via the @ES179en annotation.


@SpringBootApplication
@EnableDiscoveryClient
public class RibbonApplication {
  @Bean
  @LoadBalanced
  RestTemplate restTemplate() {
    return new RestTemplate();

  }
  public static void main(String[] args) {
    SpringApplication.run(RibbonApplication.class, args);
  }
} 

Create ConsumerController to consume getuser services of biz-service-0. The service is invoked via direct RestTemplate


@RestController
public class ConsumerController {
  @Autowired
  RestTemplate restTemplate;

  @RequestMapping(value = "/getuserinfo", method = RequestMethod.GET)
  public String add() {
    return restTemplate.getForEntity("http://biz-service-0/getuser", String.class).getBody();
  }

} 

application.properties to configure the eureka service registry


spring.application.name=ribbon-consumer
server.port=8003
eureka.client.serviceUrl.defaultZone=http://localhost:8000/eureka/

After the completion of the can open http: / / localhost: 8003 / getuserinfo can see the results

Summary: Ribbon is a soft load balancing client component that can be used in conjunction with any other client requested, and eureka is just one example of this.

Code address: https: / / github com/zhp8341 / SpringCloudDemo


Related articles: