Spring Cloud Part IV | Client load balancing Ribbon

This article is Spring Cloud column Title IV article for the first three articles of content contribute to a better understanding of this article:

  1. Spring Cloud first post | Spring Cloud Foreword and common components Glance

  2. The second Spring Cloud | use and understanding of Eureka registry

  3. Spring Cloud Part III | Eureka registration center set up high availability

First, what is the Ribbon

    Ribbon is based on HTTP and TCP client load balancer, when using Ribbon access to the service, he will expand the service discovery Eureka client to achieve access to the server from the list of Eureka registry, and come through Eureka client determining whether the services have been started. Ribbon on the basis of Eureka client service discovery on the realization of selection policy for service instances for load balancing the consumption of services. Load balancing is a very important element in the system architecture, load balancing is because high availability of the system, an important means of pressure buffering and processing capabilities of network expansion, we are usually talking about load balancing refers to the service end load balancing, which is divided into hardware and software load balancing load balancing.

  • Hardware load balancing: the main server node passes between mounting apparatus designed for load balancing, such as the F5, SINFOR, Array like.

  • Load balancing software: it is to install some software functions or having a load module to complete the work by the request distribution server, such as Nginx, LVS, HAProxy like.

    Hardware load balancing device or software load balancing software module will maintain a list of available services linked to a lower end, to eliminate the server node failure through the heartbeat to ensure that the server node list can all be normal access. When the client sends a request to the load balancing apparatus when the apparatus according to an algorithm (such as a linear polling, according to the weight load, according to traffic load, etc.) taken from a list of available server address of the server maintenance, and then forwarding.

    Ribbon is Netflix released open source project, the main function is to provide the client software load balancing algorithm is based on HTTP and TCP client load balancing tool. Spring Cloud on the Ribbon to do a second package, allows us to use the service request RestTemplate automatically converted to service calls the client load balancing. Ribbon support a variety of load balancing algorithms, also supports load balancing algorithm to customize. Ribbon tools just a framework, relatively small, Spring Cloud after packaging it is also very easy to use, it is not a service registry, distribution center, the gateway that the AP needs to deploy independent, Ribbon only need to use it directly into the code.

Ribbon and Nginx difference:

  • They are soft load

  • Ribbon client load balancing

  • Nginx server load balancing segment

The difference is that:

    Different service list stored position, the client load balancing, server list in all client nodes, so you need to obtain from the service registry, such as Eureka service registry. With the server load is similar to a balanced architecture, the client load balancing is also required heartbeat to maintain the health of the server list, but this step is needed with the completion of the service registry, service governance framework SpringCloud implementation, created by default Ribbon automation for each service governance framework to integrate configuration, such as Eureka in org.springframework.cloud.netflix.ribbon.eureka.RibbonEurekaAutoConfiguration , in actual use, we can see the implementation of this class to find their configuration details to help us make better use of it.

    By Spring Cloud Ribbon package, we use client load balancing service called micro-architecture is very simple, just two steps as follows:

  1. Service providers just need to start multiple service instances and registered with the service registry or a registry more associated

  2. Service consumers directly @LoadBalanced comment by calling the RestTemplate be modified to implement a service-oriented interface call.

So that we can be a service provider of high availability and load balancing service consumers use to achieve together.

  • Server load balancing is configured in advance: Nginx

  • Client load balancing is to find from the registry: Ribbon

    In the SpringCloud, Ribbon primarily used in conjunction with RestTemplate objects, Ribbon will be automated configuration RestTemplate objects, open load balancing when RestTemplate object calls by @LoadBalance, the role of which is shown Ribbon:

Two, Ribbon implement client load balancing

    1. As mentioned earlier, by Spring Cloud Ribbon package, we use client load balancing service called micro-architecture is very simple, just two steps as follows:

  1. Service providers just need to start multiple service instances and registered with the service registry or a registry more associated

  2. Service consumers directly @LoadBalanced comment by calling the RestTemplate be modified to implement a service-oriented interface call.

    2, we replication service provider (springcloud-service-provider) and was named springcloud-service-provider-02, modify the content controlle response result, the difference between content providers (springcloud-service-provider) is. Modify the service provider (springcloud-service-provider-02 ) port 8081, the specific details of the case to see the code source. We use the registry after 8700 single node, for convenience only.

    3, add the following code in the consumer RestTemplate:

    // Use Ribbon load balancing call, the default is polling 
    @LoadBalanced // adding support ribbon, then when you call, you can instead use the service name to access 
    @Bean
     public RestTemplate RestTemplate () {
         return  new new RestTemplate (); 
    }

    4, see the Eureka web page displays two examples provider

    5, start consumer access as shown:

provider-01 and provider-02 alternately, you can see default polling policies.

Three, Ribbon load balancing strategy

    Ribbon load balancing strategy is defined by IRule interface, which is achieved by the following:

 

Load meaning IRule strategy implementation class

RandomRule

random

RoundRobinRule

polling

AvailabilityFilteringRule

To filter the access failure due to multiple services, as well as the number of concurrent connections exceeds the threshold of the service, and then the rest of the service is accessed according to polling policy

WeightedResponseTimeRule

All computing services based on the average response time weighting, the faster service response time greater weight on the probability of being selected that is higher, if the service has just started time statistics insufficient information ,, use RoundRobinRule strategy to be enough statistical information, will switch to the strategy WeightedResponseTimeRule

RetryRule

According to RoundRobinRule first policy distribution, if distributed to the service can not access, within a specified period of time to try again, if not, then distributed to other available services

BestAvailableRule

To filter the service due to the failure of many visits, and then select a minimum amount of concurrent service

ZoneAvoidanceRule

综合判断服务节点所在区域的性能和服务节点的可用性,来决定选择哪个服务

TIP:结合Ribbon负载均衡,默认的是轮询,重新注入IRule可以实现负载均衡的其他策略

四、Rest请求模板类解读

    当我们从服务消费端去调用服务提供者的服务的时候,使用了一个极其方便的对象叫RestTemplate,当时我们只使用了 RestTemplate中最简单的一个功能getForEntity发起了一个get请求去调用服务端的数据,同时,我们还通过配置@Loadbalanced注解开启客户端负载均衡, RestTemplate的功能非常强大, 那么接下来就来详细的看一下RestTemplate中几种常见请求方法的使用。在日常操作中,基于Rest的方式通常是四种情况,它们分表是

  • GET请求-查询数据

  • POST请求-添加数据

  • PUT请求-修改数据

  • DELETE-删除数据

1、RestTemplate的GET请求

Get请求可以有两种方式

第一种:getForEntity(..)

    该方法返回一个ResponseEntity<T>对象,ResponseEntity<T>是Spring对HTTP请求响应的封装,包括了几个重要的元素,比如响应码,contentType,contentLength,响应消息体等

        ResponseEntity<String> forEntity = restTemplate.getForEntity("http://SPRINGCLOUD-SERVICE-PROVIDER/provider/hello", String.class);
        String body = forEntity.getBody();
        HttpStatus statusCode = forEntity.getStatusCode();
        int statusCodeValue = forEntity.getStatusCodeValue();
        HttpHeaders headers = forEntity.getHeaders();

        System.out.println(body);
        System.out.println(statusCode);
        System.out.println(statusCodeValue);
        System.out.println(headers);

    以上代码, getForEntity方法第—个参数为要调用的服务的地址,即服务提供者提供的http://SPRINGCLOUD-SERVICE-PROVIDER/provider/hello接口地址,注意这里是通过服务名调用而不是服务地址,如果改为服务地址就无法使用Ribbon实现客户端负载均衡了。getForEntity方法第二个参数String.class表示希望返回的body类型是 String 类型,如果希望返回一个对象,也是可以的,比如User对象

    /**
     * 调用get请求,返回一个User对象
     * @return
     */
    @RequestMapping("/user")
    public User user(){
        //逻辑判断省略
        ResponseEntity<User> forEntity = restTemplate.getForEntity("http://SPRINGCLOUD-SERVICE-PROVIDER/provider/user", User.class);
        System.out.println(forEntity.getBody().getId()+""+forEntity.getBody().getName()+""+forEntity.getBody().getPhone());
        return forEntity.getBody();
    }

另外两个重载方法:

  @Override
  public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object... uriVariables)
      throws RestClientException {

    RequestCallback requestCallback = acceptHeaderRequestCallback(responseType);
    ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
    return nonNull(execute(url, HttpMethod.GET, requestCallback, responseExtractor, uriVariables));
  }

  @Override
  public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Map<String, ?> uriVariables)
      throws RestClientException {

    RequestCallback requestCallback = acceptHeaderRequestCallback(responseType);
    ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
    return nonNull(execute(url, HttpMethod.GET, requestCallback, responseExtractor, uriVariables));
  }

比如:

   /**
     * 给服务传参数Get请求
     * @return
     */
    @RequestMapping("/getUser")
    public User getUser(){
        //逻辑判断省略
        String [] arr={"2","xxx","4545645456"};
        Map<String,Object> map=new HashMap<>();
        map.put("id",1);
        map.put("name","wwwwww");
        map.put("phone","1213213213123");

        //ResponseEntity<User> forEntity = restTemplate.getForEntity("http://SPRINGCLOUD-SERVICE-PROVIDER/provider/getUser?id={0}&name={1}&phone={2}", User.class,arr);
        //ResponseEntity<User> forEntity = restTemplate.getForEntity("http://SPRINGCLOUD-SERVICE-PROVIDER/provider/getUser?id={id}&name={name}&phone={phone}", User.class,map);
        /*
         * restTemplate.getForObject在getForObject在getForEntity在次封装,直接获取返回值类型,相当于ResponseEntity中的getBody
         */
            User user1 = restTemplate.getForObject("http://SPRINGCLOUD-SERVICE-PROVIDER/provider/getUser?id={id}&name={name}&phone={phone}", User.class, map);

        //System.out.println(forEntity.getBody().getId()+""+forEntity.getBody().getName()+""+forEntity.getBody().getPhone());
        System.out.println(user1.getId()+""+user1.getName()+""+user1.getPhone());
        return user1;
    }

    可以用一个数字做占位符,最后是一个可变长度的参数,来来替换前面的占位符也可以前面使用name={name}这种形式,最后一个参数是一个map,map的key即为前边占位符的名字,map的value为参数值

第二种:getForObject(..)

    与getForEntity使用类似,只不过getForobject是在getForEntity基础上进行了再次封装,可以将http的响应体body信息转化成指定的对象,方便我们的代码开发,当你不需要返回响应中的其他信息,只需要body体信息的时候,可以使用这个更方便,它也有两个重载的方法,和getForEntity相似

  @Override
  @Nullable
  public <T> T getForObject(String url, Class<T> responseType, Object... uriVariables) throws RestClientException {
    RequestCallback requestCallback = acceptHeaderRequestCallback(responseType);
    HttpMessageConverterExtractor<T> responseExtractor =
        new HttpMessageConverterExtractor<>(responseType, getMessageConverters(), logger);
    return execute(url, HttpMethod.GET, requestCallback, responseExtractor, uriVariables);
  }

  @Override
  @Nullable
  public <T> T getForObject(String url, Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException {
    RequestCallback requestCallback = acceptHeaderRequestCallback(responseType);
    HttpMessageConverterExtractor<T> responseExtractor =
        new HttpMessageConverterExtractor<>(responseType, getMessageConverters(), logger);
    return execute(url, HttpMethod.GET, requestCallback, responseExtractor, uriVariables);
  }

  @Override
  @Nullable
  public <T> T getForObject(URI url, Class<T> responseType) throws RestClientException {
    RequestCallback requestCallback = acceptHeaderRequestCallback(responseType);
    HttpMessageConverterExtractor<T> responseExtractor =
        new HttpMessageConverterExtractor<>(responseType, getMessageConverters(), logger);
    return execute(url, HttpMethod.GET, requestCallback, responseExtractor);
  }

上面例子已经涉及到了,此处不再啰嗦。

2、RestTemplate的POST请求

restTemplate.postForEntity();
restTemplate.postForObject();
restTemplate.postForLocation();

例如:

   /**
     * 调用POST请求
     * @return
     */
    @RequestMapping("/addUser")
    public User addUser(){
        //逻辑判断省略
        String [] arr={"2","xxx","4545645456"};
        //不能使用map传递参数
        Map<String,Object> map=new HashMap<>();
        map.put("id",1);
        map.put("name","wwwwww");
        map.put("phone","1213213213123");

        /**
         *要传的表单信息,参数数据(很坑人)
         */
        MultiValueMap<String,Object> multiValueMap=new LinkedMultiValueMap<>();
        multiValueMap.add("id",1);
        multiValueMap.add("name","xxxxx");
        multiValueMap.add("phone","000000000");

        //使用jdk中的map传参数,接收不到
        ResponseEntity<User> userResponseEntity = restTemplate.postForEntity(
                "http://SPRINGCLOUD-SERVICE-PROVIDER/provider/addUser", multiValueMap, User.class);

        System.out.println(userResponseEntity.getBody().getId()+""+userResponseEntity.getBody().getName()+""+userResponseEntity.getBody().getPhone());
        return userResponseEntity.getBody();
    }

3、RestTemplate的PUT请求

restTemplate.put();

例如:

   /**
     * 调用PUT请求
     * @return
     */
    @RequestMapping("/updateUser")
    public String updateUser(){
        //逻辑判断省略
        String [] arr={"2","xxx","4545645456"};
        //不能使用map传递参数
        Map<String,Object> map=new HashMap<>();
        map.put("id",1);
        map.put("name","wwwwww");
        map.put("phone","1213213213123");

        /**
         *要传的表单信息,参数数据(很坑人)
         */
        MultiValueMap<String,Object> multiValueMap=new LinkedMultiValueMap<>();
        multiValueMap.add("id",1);
        multiValueMap.add("name","xxxxx");
        multiValueMap.add("phone","000000000");

        //使用jdk中的map传参数,接收不到
        restTemplate.put("http://SPRINGCLOUD-SERVICE-PROVIDER/provider/updateUser", multiValueMap);

        return "SUCCESS";
    }

4、RestTemplate的DELETE请求

restTemplate.delete();

例如: 

   /**
     * 调用DELETE请求
     * @return
     */
    @RequestMapping("/deleteUser")
    public String deleteUser(){
        //逻辑判断省略
        String [] arr={"2","xxx","4545645456"};
        Map<String,Object> map=new HashMap<>();
        map.put("id",1);
        map.put("name","wwwwww");
        map.put("phone","1213213213123");

        /**
         *要传的表单信息,参数数据(很坑人),只有post,PUT请求采用这种map传参数
         */
     /*   MultiValueMap<String,Object> multiValueMap=new LinkedMultiValueMap<>();
        multiValueMap.add("id",1);
        multiValueMap.add("name","xxxxx");
        multiValueMap.add("phone","000000000"); */

        //使用jdk中的map传参数,接收不到,不能使用MultiValueMap,接收不到参数
        restTemplate.delete("http://SPRINGCLOUD-SERVICE-PROVIDER/provider/deleteUser?id={id}&name={name}&phone={phone}", map);

        return "SUCCESS";
    }

 

详细参考案例源码:https://gitee.com/coding-farmer/spirngcloud-learn

 

Guess you like

Origin www.cnblogs.com/coding-farmer/p/12003633.html