Spring Cloud Ribbon: load balancing service calls

SpringBoot actual electricity supplier item mall (20k + star) Address: github.com/macrozheng/...

Summary

Spring Cloud Ribbon Spring Cloud Netflix is ​​one of the core components of subprojects, mainly to the API gateway between service calls and forwarding to provide load balancing functionality, this article will detail its usage.

Ribbon Introduction

In the micro-services architecture, the service will deploy many more other services to invoke the service when, how to ensure that the load balancing is the question had to be considered. Load balancing can increase the availability and scalability of the system, when we use RestTemplate to call other services, Ribbon can easily achieve load balancing.

RestTemplate use

RestTemplate is an HTTP client, we can easily use it to call the HTTP interface, support for GET, POST, PUT, DELETE and other methods.

GET request method

<T> T getForObject(String url, Class<T> responseType, Object... uriVariables);

<T> T getForObject(String url, Class<T> responseType, Map<String, ?> uriVariables);

<T> T getForObject(URI url, Class<T> responseType);

<T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object... uriVariables);

<T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Map<String, ?> uriVariables);

<T> ResponseEntity<T> getForEntity(URI var1, Class<T> responseType);
复制代码

getForObject way

Returns the data object transformed into an object in response, for example as follows:

@GetMapping("/{id}")
public CommonResult getUser(@PathVariable Long id) {
    return restTemplate.getForObject(userServiceUrl + "/user/{1}", CommonResult.class, id);
}
复制代码

getForEntity way

Returns the object ResponseEntity object containing important information in the response, such as in response headers, response status code in response the like, for example as follows:

@GetMapping("/getEntityByUsername")
public CommonResult getEntityByUsername(@RequestParam String username) {
    ResponseEntity<CommonResult> entity = restTemplate.getForEntity(userServiceUrl + "/user/getByUsername?username={1}", CommonResult.class, username);
    if (entity.getStatusCode().is2xxSuccessful()) {
        return entity.getBody();
    } else {
        return new CommonResult("操作失败", 500);
    }
}
复制代码

POST request method

<T> T postForObject(String url, @Nullable Object request, Class<T> responseType, Object... uriVariables);

<T> T postForObject(String url, @Nullable Object request, Class<T> responseType, Map<String, ?> uriVariables);

<T> T postForObject(URI url, @Nullable Object request, Class<T> responseType);

<T> ResponseEntity<T> postForEntity(String url, @Nullable Object request, Class<T> responseType, Object... uriVariables);

<T> ResponseEntity<T> postForEntity(String url, @Nullable Object request, Class<T> responseType, Map<String, ?> uriVariables);

<T> ResponseEntity<T> postForEntity(URI url, @Nullable Object request, Class<T> responseType);
复制代码

postForObject example

@PostMapping("/create")
public CommonResult create(@RequestBody User user) {
    return restTemplate.postForObject(userServiceUrl + "/user/create", user, CommonResult.class);
}
复制代码

postForEntity example

@PostMapping("/create")
public CommonResult create(@RequestBody User user) {
    return restTemplate.postForEntity(userServiceUrl + "/user/create", user, CommonResult.class).getBody();
}
复制代码

PUT request method

void put(String url, @Nullable Object request, Object... uriVariables);

void put(String url, @Nullable Object request, Map<String, ?> uriVariables);

void put(URI url, @Nullable Object request);
复制代码

Example PUT request

@PutMapping("/update")
public CommonResult update(@RequestBody User user) {
    restTemplate.put(userServiceUrl + "/user/update", user);
    return new CommonResult("操作成功",200);
}
复制代码

DELETE request method

void delete(String url, Object... uriVariables);

void delete(String url, Map<String, ?> uriVariables);

void delete(URI url);

复制代码

Example DELETE request

@DeleteMapping("/delete/{id}")
public CommonResult delete(@PathVariable Long id) {
   restTemplate.delete(userServiceUrl + "/user/delete/{1}", null, id);
   return new CommonResult("操作成功",200);
}
复制代码

Creating a user-service module

First, we create a user-service, call for service to the Ribbon.

Add its dependencies in pom.xml

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
复制代码

Configured in application.yml

The main port is configured and registries address.

server:
  port: 8201
spring:
  application:
    name: user-service
eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://localhost:8001/eureka/
复制代码

Add UserController used to provide call interface

UserController of the User object class defines the common CRUD interface.

/**
 * Created by macro on 2019/8/29.
 */
@RestController
@RequestMapping("/user")
public class UserController {

    private Logger LOGGER = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private UserService userService;

    @PostMapping("/create")
    public CommonResult create(@RequestBody User user) {
        userService.create(user);
        return new CommonResult("操作成功", 200);
    }

    @GetMapping("/{id}")
    public CommonResult<User> getUser(@PathVariable Long id) {
        User user = userService.getUser(id);
        LOGGER.info("根据id获取用户信息,用户名称为:{}",user.getUsername());
        return new CommonResult<>(user);
    }

    @GetMapping("/getUserByIds")
    public CommonResult<List<User>> getUserByIds(@RequestParam List<Long> ids) {
        List<User> userList= userService.getUserByIds(ids);
        LOGGER.info("根据ids获取用户信息,用户列表为:{}",userList);
        return new CommonResult<>(userList);
    }

    @GetMapping("/getByUsername")
    public CommonResult<User> getByUsername(@RequestParam String username) {
        User user = userService.getByUsername(username);
        return new CommonResult<>(user);
    }

    @PostMapping("/update")
    public CommonResult update(@RequestBody User user) {
        userService.update(user);
        return new CommonResult("操作成功", 200);
    }

    @PostMapping("/delete/{id}")
    public CommonResult delete(@PathVariable Long id) {
        userService.delete(id);
        return new CommonResult("操作成功", 200);
    }
}

复制代码

Create a ribbon-service module

Here we create a ribbon-service module to call the user-service module shows the load balancing service calls.

Add its dependencies in pom.xml

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
复制代码

Configured in application.yml

The main port is the call path, registry address and user-service configured.

server:
  port: 8301
spring:
  application:
    name: ribbon-service
eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://localhost:8001/eureka/
service-url:
  user-service: http://user-service
复制代码

The ability to use @LoadBalanced notes given RestTemplate load balancing

Ribbon can be seen using the load balancing function is very simple and straightforward to use RestTemplate no different, just to add a @LoadBalanced RestTemplate can.

/**
 * Created by macro on 2019/8/29.
 */
@Configuration
public class RibbonConfig {

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}

复制代码

Add UserRibbonController class

Injection RestTemplate, using its call to the relevant interface provides user-service, where GET and POST calls for a demonstration, other methods can be invoked by reference.

/**
 * Created by macro on 2019/8/29.
 */
@RestController
@RequestMapping("/user")
public class UserRibbonController {
    @Autowired
    private RestTemplate restTemplate;
    @Value("${service-url.user-service}")
    private String userServiceUrl;

    @GetMapping("/{id}")
    public CommonResult getUser(@PathVariable Long id) {
        return restTemplate.getForObject(userServiceUrl + "/user/{1}", CommonResult.class, id);
    }

    @GetMapping("/getByUsername")
    public CommonResult getByUsername(@RequestParam String username) {
        return restTemplate.getForObject(userServiceUrl + "/user/getByUsername?username={1}", CommonResult.class, username);
    }

    @GetMapping("/getEntityByUsername")
    public CommonResult getEntityByUsername(@RequestParam String username) {
        ResponseEntity<CommonResult> entity = restTemplate.getForEntity(userServiceUrl + "/user/getByUsername?username={1}", CommonResult.class, username);
        if (entity.getStatusCode().is2xxSuccessful()) {
            return entity.getBody();
        } else {
            return new CommonResult("操作失败", 500);
        }
    }

    @PostMapping("/create")
    public CommonResult create(@RequestBody User user) {
        return restTemplate.postForObject(userServiceUrl + "/user/create", user, CommonResult.class);
    }

    @PostMapping("/update")
    public CommonResult update(@RequestBody User user) {
        return restTemplate.postForObject(userServiceUrl + "/user/update", user, CommonResult.class);
    }

    @PostMapping("/delete/{id}")
    public CommonResult delete(@PathVariable Long id) {
        return restTemplate.postForObject(userServiceUrl + "/user/delete/{1}", null, CommonResult.class, id);
    }
}

复制代码

Load balancing feature presentation

  • Start eureka-server port in 8001;
  • Start user-service ports in 8201;
  • To start another user-service port 8202 can be configured by modifying the starting SpringBoot IDEA of:

  • At this point the operation of the service as follows:

  • Alternately print run can be found in the following information 8201 and 8202 of user-service console:

Ribbon of common configuration

Global Configuration

ribbon:
  ConnectTimeout: 1000 #服务请求连接超时时间(毫秒)
  ReadTimeout: 3000 #服务请求处理超时时间(毫秒)
  OkToRetryOnAllOperations: true #对超时请求启用重试机制
  MaxAutoRetriesNextServer: 1 #切换重试实例的最大个数
  MaxAutoRetries: 1 # 切换实例后重试最大次数
  NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #修改负载均衡算法
复制代码

Designated service configuration

Difference ribbon is configured with a global name service nodes hanging below when configured as a separate user-service call to the ribbon-service.

user-service:
  ribbon:
    ConnectTimeout: 1000 #服务请求连接超时时间(毫秒)
    ReadTimeout: 3000 #服务请求处理超时时间(毫秒)
    OkToRetryOnAllOperations: true #对超时请求启用重试机制
    MaxAutoRetriesNextServer: 1 #切换重试实例的最大个数
    MaxAutoRetries: 1 # 切换实例后重试最大次数
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #修改负载均衡算法
复制代码

Ribbon load balancing strategy

The so-called load balancing strategy is that when service A service call B, then B services have more than one instance, then A to select the manner in which the service calls an instance of B, ribbon can choose from several load balancing strategy.

  • com.netflix.loadbalancer.RandomRule: providing services from an instance in a random manner;
  • com.netflix.loadbalancer.RoundRobinRule: polling a linear manner, a counter is maintained, the service is selected from the example provided in this order, first select the first, second select the second, and so on, to last a later start over;
  • com.netflix.loadbalancer.RetryRule: adding retry mechanism on the basis of RoundRobinRule, i.e., within a specified retry time, repeated use linear polling policy to select the available instances;
  • com.netflix.loadbalancer.WeightedResponseTimeRule: extension of RoundRobinRule, the faster the response speed of the examples weights are chosen, the more likely to be selected;
  • com.netflix.loadbalancer.BestAvailableRule: selecting a smaller concurrent instances;
  • com.netflix.loadbalancer.AvailabilityFilteringRule: failure to filter the instances, and then select a smaller concurrent instances;
  • com.netflix.loadbalancer.ZoneAwareLoadBalancer: double filter, while filtering and fault examples are not examples of the same area, select a smaller concurrent instances.

To use the module

springcloud-learning
├── eureka-server -- eureka注册中心
├── user-service -- 提供User对象CRUD接口的服务
└── ribbon-service -- ribbon服务调用测试服务
复制代码

Project Source Address

github.com/macrozheng/…

No public

mall project a full tutorial serialized in public concern number the first time to obtain.

No public picture

Guess you like

Origin juejin.im/post/5d7f9006f265da03951a260c