Spring-Cloud-loadbalancer

3/20/2023 微服务

# LoadBalancer:替代Ribbon的负载均衡组件

# 概述

在最新版SpringCloud中,作为负载均衡组件的Ribbon被弃用了,现在推荐使用的是Loadbalancer

# LoadBalancer简介

LoadBalancerSpring Cloud官方提供的负载均衡组件,可用于替代Ribbon。其使用方式与Ribbon基本兼容,可以从Ribbon进行平滑过渡。

# 使用

# 依赖

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

# RestTemplate配置

@Configuration
public class RestTemplateConfig {

    @Bean
    @ConfigurationProperties(prefix = "rest.template.config")
    public HttpComponentsClientHttpRequestFactory customHttpRequestFactory() {
        return new HttpComponentsClientHttpRequestFactory();
    }

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate(customHttpRequestFactory());
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 服务提供者接口

@RestController
@RequestMapping("/user")
public class UserLoadBalancerController {
    
    @Autowired
    private RestTemplate restTemplate;
    
    @Value("${service-url.nacos-user-service}")
    private String userServiceUrl;

    @GetMapping("/{id}")
    public CommonResult getUser(@PathVariable Long id) {
        return restTemplate.getForObject(userServiceUrl + "/user/{1}", CommonResult.class, id);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 服务实例缓存

  • LoadBalancer为了提高性能,不会在每次请求时去获取实例列表,而是将服务实例列表进行了本地缓存。
  • 默认的缓存时间为35s,为了减少服务不可用还会被选择的可能性,我们可以进行如下配置。
spring:
  cloud:
    loadbalancer:
      cache: # 负载均衡缓存配置
        enabled: true # 开启缓存
        ttl: 5s # 设置缓存时间
        capacity: 256 # 设置缓存大小
1
2
3
4
5
6
7

# HTTP请求转换

如果你想在每次远程调用中传入自定义的请求头的话,可以试试LoadBalancerRequestTransformer,通过它可以对原始请求进行一定的转换。

  • 首先我们需要配置好LoadBalancerRequestTransformerBean实例,这里我们将ServiceInstanceinstanceId放入到请求头X-InstanceId中;
@Configuration
public class LoadBalancerConfig {
    @Bean
    public LoadBalancerRequestTransformer transformer() {
        return new LoadBalancerRequestTransformer() {
            @Override
            public HttpRequest transformRequest(HttpRequest request, ServiceInstance instance) {
                return new HttpRequestWrapper(request) {
                    @Override
                    public HttpHeaders getHeaders() {
                        HttpHeaders headers = new HttpHeaders();
                        headers.putAll(super.getHeaders());
                        headers.add("X-InstanceId", instance.getInstanceId());
                        return headers;
                    }
                };
            }
        };
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 在服务提供接口中打印请求头

@RestController
@RequestMapping("/user")
public class UserController {
    
    @GetMapping("/{id}")
    public CommonResult<User> getUser(@PathVariable Long id) {
        User user = userService.getUser(id);
        LOGGER.info("根据id获取用户信息,用户名称为:{}", user.getUsername());
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = servletRequestAttributes.getRequest();
        String instanceId = request.getHeader("X-InstanceId");
        if (StrUtil.isNotEmpty(instanceId)) {
            LOGGER.info("获取到自定义请求头:X-InstanceId={}", instanceId);
        }
        return new CommonResult<>(user);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17