SpringCloud study notes (four, SpringCloud Netflix Ribbon)

table of Contents:

  • Ribbon Introduction
  • Ribbon application
  • RestTemplate Profile
  • Ribbon load balancing source code analysis

Ribbon Description:

1. What is load balancing

Load balancing, according to its literal meaning, it is to allow the cluster service has the ability to work together to complete , you can load-balancing capabilities of external services programs automatically distributed between multiple application instances ; thus eliminating single points of failure by the machine, lifting applications fault tolerance , make applications more efficient, stable and secure .

2. What is SpringCloud Ribbon

SpringCloud Ribbon is based on Http and TCP A load tool , Netflix Ribbon Based ; it can rest on the service request is automatically converted to the client load balancing service call .

Ribbon application:

1, Ribbon Configuration

) Add dependencies

1 <dependency>
2     <groupId>org.springframework.cloud</groupId>
3     <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
4 </dependency>

) RestTemplate reconfigured (such RestTemplate requested load balancing can be achieved)

1  @Bean
 2  @LoadBalanced
 3  public Residual Template rest template () {
 4      return  new Residual Template ( );
5 }

) Configuration properties

1 ## local configuration - individually developed client (eureka- Provider Client)
 2 Eureka-provider.ribbon.listOfServers = localhost: 8072, localhost: 8073

Configuration format:.. <ClientName> <nameSpace> <propertyName> = <value>

propertyName见com.netflix.client.config.CommonClientConfigKey

2, Ribbon retry mechanism

When it comes to retry mechanism Ribbon on the need to take a look at some of the basic configuration of the Ribbon:

We then look at the last two configurations, MaxAutoRetriesNextServer, MaxAutoRetries, these are examples of the number of retries and the retry switch case; for example we have three examples A, B, C, A request if the first fails, continuation request a (which is for instance retry), then the request fails or will retry to example B, and so on until the request is considered a failure after two failed C, i.e. above the weight of FIG. test configuration if requested 2 * 3 = 6, 6 times fail if they really failed.

Of course, if you configured crowbar timeout, i.e. the configuration of FIG first, then your overall retry time plus the time of the request can not be a normal one second timeout.

RestTemplate profile:

RestTemplate encapsulates plurality Http client, such as HttpClient, OKHttp3 like.

详见:org.springframework.web.client.RestTemplate#RestTemplate(org.springframework.http.client.ClientHttpRequestFactory)

1, construct your own RestTemplate

 1 @Bean
 2 @LoadBalanced
 3 public RestTemplate restTemplate(){
 4     return new RestTemplate(new OkHttp3ClientHttpRequestFactory(okHttpClient()));
 5 }
 6 
 7 @Bean
 8 public OkHttpClient okHttpClient() {
 9     OkHttpClient.Builder builder = new OkHttpClient.Builder();
10     builder.connectTimeout(30, TimeUnit.SECONDS)
11             .readTimeout(10, TimeUnit.SECONDS)
12             .writeTimeout(10,TimeUnit.SECONDS)
13             .retryOnConnectionFailure(true);
14     return builder.build();
15 }

Ribbon load balancing source code analysis:

We know that to be able to make the request of the client load balancing, then only need to re-construct RestTemplate, and its annotation can add @LoadBalanced, why add this comment on the line it?

1, first of all we need to know @LoanBalanced is RestTemplate enhanced, while RestTemplate is a package of Http request, so we used to guess should be enhanced interceptor

) We enter RestTemplate, and to find the parent org.springframework.http.client.support.InterceptingHttpAccessor found to have a property private List <ClientHttpRequestInterceptor> interceptors, this is the spring of the http request package, interceptors is requesting that needs to elapse interceptor collection;

 1 private List<ClientHttpRequestInterceptor> interceptors = new ArrayList<ClientHttpRequestInterceptor>();
 2 
 3 /**
 4  * Sets the request interceptors that this accessor should use.
 5  */
 6 public void setInterceptors(List<ClientHttpRequestInterceptor> interceptors) {
 7     this.interceptors = interceptors;
 8 }
 9 
10 /**
11  * Return the request interceptor that this accessor uses.
12  */
13 public List<ClientHttpRequestInterceptor> getInterceptors() {
14     return interceptors;
15 }

) Then we look at this set of interceptors in what set of >>>  public void setInterceptors (List <ClientHttpRequestInterceptor> interceptors)

According to the class name is not the picture above we guess the first two, is the first three, and then we were to see, that is the first two, we now look at the first two implementations:

 1 @Configuration
 2 @ConditionalOnMissingClass("org.springframework.retry.support.RetryTemplate")
 3 static class LoadBalancerInterceptorConfig {
 4     @Bean
 5     public LoadBalancerInterceptor ribbonInterceptor(
 6             LoadBalancerClient loadBalancerClient,
 7             LoadBalancerRequestFactory requestFactory) {
 8         return new LoadBalancerInterceptor(loadBalancerClient, requestFactory);
 9     }
10 
11     @Bean
12     @ConditionalOnMissingBean
13     publicRestTemplateCustomizer restTemplateCustomizer (
 14              final LoadBalancerInterceptor loadBalancerInterceptor) {
 15          return  new RestTemplateCustomizer () {
 16              @Override
 17              public  void customize (Template Residual residual template) {
 18                  List <ClientHttpRequestInterceptor> list = new ArrayList <> (
 19                          restTemplate.getInterceptors ());
20                  list.add (loadBalancerInterceptor);
21                  restTemplate.setInterceptors (list);
22              }
 23         };
24     }
25 }

From 18-21 lines of code, we can see it in the original http interceptor collection on added loadBalancerInterceptor this interceptor, the interceptor and this is precisely what the bean row 5.

According to the conclusions we can know: RestTemplate added @LoadBalanced comment after, in fact, is http enhance an interceptor , which is org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor

) So why add the interceptor will take effect then, we can debug request according to a RestTemplate (request a little dark)

如:String result = restTemplate.getForObject("http://eureka-provider/updateProduct/" + productName + "/" + num, String.class);

After debug we can find such a method >>>  org.springframework.http.client.InterceptingClientHttpRequest.InterceptingRequestExecution the Execute #

. 1  @Override
 2  public ClientHttpResponse Execute (the HttpRequest Request, Final  byte [] body) throws IOException {
 . 3      IF ( the this .iterator.hasNext ()) {
 . 4          // get current collector interceptor 
. 5          ClientHttpRequestInterceptor = nextInterceptor the this .iterator.next ();
 . 6          // intercept method for performing current interceptor, the interceptor is added such LoanBalancerInterceptor performed 
. 7          return nextInterceptor.intercept (Request, body, the this );
 . 8      } the else {
 . 9         ClientHttpRequest delegate = requestFactory.createRequest(request.getURI(), request.getMethod());
10         for (Map.Entry<String, List<String>> entry : request.getHeaders().entrySet()) {
11             List<String> values = entry.getValue();
12             for (String value : values) {
13                 delegate.getHeaders().add(entry.getKey(), value);
14             }
15         }
16         if (body.length > 0) {
17             if (delegate instanceof StreamingHttpOutputMessage) {
18                 StreamingHttpOutputMessage streamingOutputMessage = (StreamingHttpOutputMessage) delegate;
19                 streamingOutputMessage.setBody(new StreamingHttpOutputMessage.Body() {
20                     @Override
21                     public void writeTo(final OutputStream outputStream) throws IOException {
22                         StreamUtils.copy(body, outputStream);
23                     }
24                 });
25             } else {
26                 StreamUtils.copy(body, delegate.getBody());
27             }
28         }
29         return delegate.execute();
30     }
31 }

2, then we have to look at the implementation of LoanBalancerInterceptor

 1 public class LoadBalancerInterceptor implements ClientHttpRequestInterceptor {
 2 
 3     private LoadBalancerClient loadBalancer;
 4     private LoadBalancerRequestFactory requestFactory;
 5 
 6     public LoadBalancerInterceptor(LoadBalancerClient loadBalancer, LoadBalancerRequestFactory requestFactory) {
 7         this.loadBalancer = loadBalancer;
 8         this.requestFactory = requestFactory;
 9     }
10 
11     public LoadBalancerInterceptor(LoadBalancerClient loadBalancer) {
12         // for backwards compatibility
13         this(loadBalancer, new LoadBalancerRequestFactory(loadBalancer));
14     }
15 
16     @Override
17     public ClientHttpResponse intercept(final HttpRequest request, final byte[] body,
18             final ClientHttpRequestExecution execution) throws IOException {
19         final URI originalUri = request.getURI();
20         String serviceName = originalUri.getHost();
21         Assert.state(serviceName != null, "Request URI does not contain a valid hostname: " + originalUri);
22         return this.loadBalancer.execute(serviceName, requestFactory.createRequest(request, body, execution));
23     }
24 }

) From Intercepting intercept LoanBalancerInterceptor can be seen in execute is performed to execute loanBanlancer

) Which also verified annotations on the phrase @LoadBalanced the Annotation to Mark A RestTemplate bean Configured to use A to BE LoadBalancerClient (labeled using the RestTemplate bean LoadBalancerClient annotations)

) Then we take a look execute implementation >>> public <T> T execute (String serviceId, LoadBalancerRequest <T> request) throws IOException

. 1  @Override
 2  public <T> T Execute (String the serviceId, LoadBalancerRequest <T> Request) throws IOException {
 . 3      // get the list of available services 
. 4      ILoadBalancer LoadBalancer = getLoadBalancer (the serviceId);
 . 5      // The load balancing algorithm, from the service list may be selected from a service 
. 6      Server Server = the getServer (LoadBalancer);
 . 7      IF (Server == null ) {
 . 8          the throw  new new IllegalStateException ( "No Available for instances" + the serviceId);
 . 9      }
 10      RibbonLoadBalancerClient.RibbonServer ribbonServer =new new RibbonLoadBalancerClient.RibbonServer (the serviceId, Server, the isSecure (Server,
 . 11              the serviceId), serverIntrospector (the serviceId) .getMetadata (Server));
 12 is      // After obtaining the service, the final execution request 
13 is      return Execute (the serviceId, ribbonServer, Request);
 14 }

Get a list of available services, load balancing algorithm here is not explained, interested students can go and see (* ^ ▽ ^ *)

Guess you like

Origin www.cnblogs.com/bzfsdr/p/11623921.html