Spring Cloud loadbalancer
LoadBalancer:替代Ribbon的负载均衡组件
概述
在最新版SpringCloud
中,作为负载均衡组件的Ribbon
被弃用了,现在推荐使用的是Loadbalancer
。
LoadBalancer简介
LoadBalancer
是Spring Cloud
官方提供的负载均衡组件,可用于替代Ribbon
。其使用方式与Ribbon
基本兼容,可以从Ribbon
进行平滑过渡。
使用
依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
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());
}
}
服务提供者接口
@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);
}
}
服务实例缓存
LoadBalancer
为了提高性能,不会在每次请求时去获取实例列表,而是将服务实例列表进行了本地缓存。- 默认的缓存时间为
35s
,为了减少服务不可用还会被选择的可能性,我们可以进行如下配置。
spring:
cloud:
loadbalancer:
cache: # 负载均衡缓存配置
enabled: true # 开启缓存
ttl: 5s # 设置缓存时间
capacity: 256 # 设置缓存大小
HTTP请求转换
如果你想在每次远程调用中传入自定义的请求头的话,可以试试LoadBalancerRequestTransformer
,通过它可以对原始请求进行一定的转换。
- 首先我们需要配置好
LoadBalancerRequestTransformer
的Bean
实例,这里我们将ServiceInstance
的instanceId
放入到请求头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;
}
};
}
};
}
}
在服务提供接口中打印请求头
@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);
}
}