客户端负载均衡与服务端负载均衡的最大不同点在于服务清单存储的位置。在客户端负载均衡中,所有客户端节点维护着自己要访问的服务端清单,而这些清单来自于服务注册中心。
通过spring cloud ribbon的封装,在微服务架构中使用客户端负载均衡十分简单,只需要如下两步:
服务提供者启动多个服务实例注册到一个或者多个相关联的服务注册中心
服务消费者直接调用被@LoadBalanced注解修饰过的RestTemplate来实现面向服务的接口调用。
添加依赖,spring-cloud-starter-netflix-eureka-client中包含了ribbon依赖,之前用的是spring-cloud-netflix-eureka-client和spring-cloud-starter-netflix-ribbon这两个依赖,但是调用服务时报错No instances available for hello-service,使用spring-cloud-starter-netflix-eureka-client这个依赖之后程序能正常访问。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
服务消费者启动类
@SpringBootApplication
@EnableEurekaClient
public class ConsumerApplication {
@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
}
调用其他服务方式
@RestController
public class ConsumerController {
@Autowired
private RestTemplate restTemplate;
@RequestMapping("/consumer")
public String consumer() {
return restTemplate.getForEntity("http://hello-service/say-hello", String.class).getBody();
}
}
源码分析
从@LoadBalanced注解源码可以知道,该注解用来给RestTemplate做标记,以使用负载均衡的客户端(LoadBalancerClient)来配置它。
通过搜索LoadBalancerClient可以发现,这是spring cloud中定义的一个接口:
public interface LoadBalancerClient extends ServiceInstanceChooser {
<T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException;
<T> T execute(String serviceId, ServiceInstance serviceInstance, LoadBalancerRequest<T> request) throws IOException;
URI reconstructURI(ServiceInstance instance, URI original);
}
从该接口中,我们可以通过定义的抽象方法来了解负载均衡器中应具备的几种能力:
ServiceInstance choose(String serviceId) :根据传入的serviceId,选择一个对应的服务器实例
<T> T execute(String serviceId, LoadBalancerRequest<T> request) :使用负载均衡器中的服务实例来执行请求内容
URI reconstructURI(ServiceInstance instance, URI original):为系统构建合适的host:port形式的uri
查看org.spring.cloud.loadBalancer包下的内容,可以找到LoadBalancerAutoConfiguration这个类,从类的命名可初步判断LoadBalancerAutoConfiguration为实现客户端负载均衡的自动化配置类。
@Configuration
@ConditionalOnClass(RestTemplate.class)
@ConditionalOnBean(LoadBalancerClient.class)
@EnableConfigurationProperties(LoadBalancerRetryProperties.class)
public class LoadBalancerAutoConfiguration {
}
从LoadBalancerAutoConfiguration头上的注解可以知道,ribbon实现自动配置需满足以下条件
@ConditionalOnClass(RestTemplate.class):RestTemplate类必须存在于当前的工程环境中
@ConditionalOnBean(LoadBalancerClient.class):在spring的bean工程中必须有LoadBalancerClient的实现
在该自动化配置类中,主要做了三件事情:
创建了一个LoadBalancerInteceptor的bean,用于实现对客户端发起请求时进行拦截,实现负载均衡
创建一个RestTemplateCustomizer的bean,用于给RestTemplate添加LoadBalancerInteceptor拦截器
维护了一个被@LoadBalanced注解修饰的RestTemplate对象列表,并在这里进行初始化,通过调用RestTemplateCustomizer来给需要负载均衡的RestTemplate添加拦截器
网友评论