继续 SpringCloud 之旅,前面讲到了服务的注册于发现,每个微服务都各自注册到 Eureka 服务,看上去很不错,但实际情况我们的客户端会有多个以缓解各自的压力,或者说万一哪个微服务宕机了有辅助的微服务来替代。这个时候就需要负载均衡了。
Robbin介绍
是 Netflixfa 发布的一个负载均衡器,有助于控制 HTTP 和 TCP客户端行为。在 SpringCloud 中,Eureka一般配合Ribbon进行使用,Ribbon提供了客户端负载均衡的功能,Ribbon利用从Eureka中读取到的服务信息,在调用服务节点提供的服务时,会合理的进行负载。
集成 Robbin
首先我们给服务消费者也就是 movie 微服务,集成 Robbin,其实在 spring-cloud-starter-eureka 依赖中已经包含了 Ribbon 的依赖,所以我们不再增加新的依赖,可以查阅 pom 的依赖,如下图
其次在 RestTemplate 构造上面增加新的注解 @LoadBalanced,网站代码如下
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
@EnableEurekaClient
public class MsSimpleConsumerMovieApplication {
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(MsSimpleConsumerMovieApplication.class, args);
}
}
说明:在这里添加这个注解就可以整合 Ribbon 到该微服务了。
最后来到我们的 Controller 层的代码处,修改 MovieController 如下
package cn.ts.ms.movie.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import cn.ts.ms.movie.model.User;
@RestController
public class MovieController {
@Autowired
private RestTemplate restTemplate;
@Autowired
private LoadBalancerClient loadBalancerClient;
@GetMapping("/user/{id}")
public User findByUserId(@PathVariable Integer id){
return restTemplate.getForObject("http://MS-SIMPLE-PROVIDER-USER/user/find?id="+id, User.class);
}
@GetMapping("/log")
public void printLog(){
ServiceInstance instance = loadBalancerClient.choose("MS-SIMPLE-PROVIDER-USER");
System.out.println("Now:"+instance.getServiceId()+"---"+instance.getHost()+":"+instance.getPort());
}
}
说明:
修改restTemplate.getForObject 的第一个参数为 http://MS-SIMPLE-PROVIDER-USER/user/find?id="+id 这样我们就不必关心到底是哪个 ip 提供的服务,只需要指定这个虚拟主机名,接下来我们启动服务器看看效果
启动 eureka、2个或多个 user 微服务,启动 movie 微服务
在开发的时候,启动多个微服务,只需要改变端口即可
启动后查看下 eureka 服务器
可以清楚的看到2个 use 微服务
我们接下来调用 movie 的接口看看是否和我们想象的一样,不出意外,我们也能获得和之前一样的结果,为了验证 Robbin 的分配策略,我们调用 http://localhost:8010/log 这个接口,多刷几次,可以看到我们的请求能够向不同的 user 提供发送
自定义 Robbin 策略
以上是默认行为,在实际情况下,很有可能需要不同的分配轮询策略,接下来我们构造一个我们自己的 Robbin
代码实现方式
首先我们建立一个 Robbin 配置类,这个类不能在主应用程序的@ComponentScan中,我们单独建一个包就叫 robbin
package cn.ts.ms.robbin;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
@Configuration
public class RobbinConfig {
@Bean
public IRule robbinRule(){
return new RandomRule();
}
}
我们需要配置 user 的服务使用这个 robbin,需要在构建一个类,这个类是需要被扫描到的
package cn.ts.ms.movie;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
import org.springframework.context.annotation.Configuration;
import cn.ts.ms.robbin.RobbinConfig;
@Configuration
@RibbonClient(name="MS-SIMPLE-PROVIDER-USER",configuration=RobbinConfig.class)
public class RobbinNewConfig {
}
OK,代码开发完毕,走一遍测试下,多次请求 http://localhost:8010/log
得到的结果是
这次是随机请求的结果。
配置方式更简单
上面是使用 java 编码的方式,也可以使用 yml 配置的方式快速达到效果
我们将上面的RobbinNewConfig 注释掉,改用 yml 的方式
在 yml 里面增加
MS-SIMPLE-PROVIDER-USER:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
结果也是一样的。
到此,我们基本把 Ribbon 如何使用给说明清楚,下一步我们将使用 Feign实现声明式 Rest 调用。