在上篇文章中已经学到spring-cloud可以实现负载均衡,主要是通过在代码里注入一个带有@LoadBalance的RestTemplate的对象实现的,其原理是springcloud封装了netfllix的ribbon组件。
1 自定义负载均衡
1.1 自定义负载均衡策略
- 随机 (Random)
- 轮询 (RoundRobin)
- 一致性哈希 (ConsistentHash)
- 哈希 (Hash)
- 加权(Weighted)
1.2 替换默认的负载均衡策略
只需要在配置中添加一个负载均衡规则即可
@Configuration
public class BeansConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
@Bean
public IRule myRule() {
// 采用随机算法
return new RandomRule();
}
}
2 手写负载均衡
这里实现一个每个服务实例请求两次的复杂算法
2.1 负载均衡算法实现
public interface LoadBalancer {
ServiceInstance getServiceInstance(List<ServiceInstance> serviceInstances);
}
@Component
public class MyLoadBalancer implements LoadBalancer {
private AtomicInteger count = new AtomicInteger(0);
@Override
public ServiceInstance getServiceInstance(List<ServiceInstance> serviceInstances) {
int size = serviceInstances.size();
int num = 2;
int index = getAndIncrement() % (size * num) / num;
return serviceInstances.get(index);
}
private int getAndIncrement() {
int current;
int next;
do {
current = count.get();
next = current >= Integer.MAX_VALUE ? 0 : current + 1;
} while (!count.compareAndSet(current, next));
return next;
}
}
2.2 禁用@LoadBalance注解
这里直接注入一个RestTemplate即可
@Configuration
public class BeansConfig {
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
2.3 负载均衡使用
@Autowired
private RestTemplate restTemplate;
@Autowired
private DiscoveryClient discoveryClient;
@Autowired
private LoadBalancer loadBalancer;
@GetMapping("/payment/self-lb/{id}")
public Map selfLoadBalance(@PathVariable("id") Long id) {
List<ServiceInstance> serviceInstances = discoveryClient.getInstances("PAYMENT");
if (CollectionUtils.isEmpty(serviceInstances)) {
return null;
}
ServiceInstance serviceInstance = loadBalancer.getServiceInstance(serviceInstances);
URI uri = serviceInstance.getUri();
return restTemplate.getForObject(uri + "/payment/get?id=" + id, Map.class);
}
这样在访问/payment/get/接口的时候就会按照自己实现的负载均衡策略执行
3 超时时间设置
ribbon可以通过如下两个配置来控制服务调用方的超时时间
# 超时时间控制
ribbon:
ReadTimeout: 5000 # 建立连接时间
ConnectTimeout: 5000 # 建立连接后读取资源用的时间