负载均衡是一个算法,可以通过该算法实现从地址列表中获取一个地址进行服务调用。
在RestTemplate的配置方法上添加 @LoadBalanced 注解,RestTemplate+@LoadBalanced,即服务消费方调用服务提供方的时候是用负载均衡的方式直接通过服务名调用(后面用Feign)
在刚才的案例中,我们启动了一个 user-service(此时可以不需要负载均衡) ,然后通过DiscoveryClient来获取服务实例信息,然后获取ip和端口来访问。但是实际环境中,往往会开启很多个 user-service(服务提供方)的集群。此时获取的服务列表中就会有多个,到底该访问哪一个呢?以前是根据serviceId(user-service)获取实例的集合,而如果总是获取第一个就不合理,我们希望通过负载均衡算法从多个实例中选择一个进行服务的调用。一般这种情况下就需要编写负载均衡算法,在多个实例列表中进行选择。不过Eureka中已经集成了负载均衡组件:Ribbon,简单修改代码即可使用。
什么是Ribbon:
Ribbon默认的负载均衡策略是轮询(这样比较合理)。SpringBoot也帮提供了修改负载均衡规则的配置入口在consumer-demo的配置文件中添加如下,就变成随机(Random)的了:
配置启动两个user-service服务,在consumer-demo中使用服务名进行服务调用。以前使用discoveryClient工具类,根据名称获取user-service服务的实例的集合,再获取集合中第一个实例,再根据实例信息拼接一个user-service服务的url,利用RestTemplate访问这个地址,获取数据。
而现在不需要使用discoveryClient,直接用RestTemplate访问一个以服务名称作为服务路径的地址,并获取到数据。
1、首先我们配置启动两个 user-service 实例,一个9091,一个9191。
配置多个服务提供方只需要在VMoptions中配置端口就可以了。
首先改变端口为:${port:9091},即如果VMoptions中提供了port,则使用该port,如果没有则使用9091这个默认值,以避免端口冲突,再在VM options中配置端口,如-Dport=9191
2、开启负载均衡
因为Eureka-client中已经集成了Ribbon,所以我们无需引入新的依赖。
直接修改服务消费方启动类ConsumerApplication,在RestTemplate的配置方法上添加 @LoadBalanced 注解:
3、修改ConsumerController,调用方式,不再手动获取ip和端口来调用,而是直接通过服务名调用;
可以使用Ribbon负载均衡:在执行RestTemplate发送服务地址请求的时候,使用负载均衡拦截器拦截,根据服务名获取服务地址列表,使用Ribbon负载均衡算法从服务地址列表中选择一个地址,访问该地址获取服务数据。
为什么只输入了service名称就可以访问了呢?之前还要获取ip和端口。
源码跟踪:
显然是有组件根据service名称,获取到了服务实例的ip和端口。因为 consumer-demo 使用的是RestTemplate,spring的负载均衡自动配置类(spring-cloud-commons包下的spring,factories) LoadBalancerAutoConfiguration.
打开LoadBalancerAutoConfiguration,
@ConditionalOnMissingClass({"org.springframework.retry.support.RetryTemplate"})表示如果没有使用RetryTemplate则实例化Load Balancer Interceptor Config。而我们用的是Rest Template
LoadBalancerInterceptorConfig 会自动配置负载均衡拦截器(在spring-cloud-commons-**.jar包中的spring.factories中定义的自动配置类), 它就是LoadBalancerInterceptor ,
这个类会在对RestTemplate的请求进行拦截,然后从Eureka根据服务id获取服务列表,随后利用负载均衡算法得到真实的服务地址信息,替换服务id,再访问该地址获取数据。