负载均衡策略
1. 啥是负载均衡?
首先我们想象一个场景,在分布式系统中有许多个服务,在实际生产环境中,一个服务肯定不止一个实例;但是对于用户或者调用方而已,如果需要我自己去选择,那未免也太麻烦了;并没有达到微服务架构所提倡的效率高;但是如果我们只是访问一个,那么又如何保证不会单点被爆破呢? 我们设想一下,最好的情况就是每一个实例所承受的相差无几的访问压力。这就是负载均衡;可以整体提高数据吞吐量。
1.1 负载均衡的分类
1.1.1 软硬件的角度
硬件解决方案:可供选择的有 NetScaler、F5、Radware和Array等商用的负载均衡器。
软件解决方案:Nginx 等。
1.1.2 两端的角度
可分为服务端的负载均衡与客户端的负载均衡.
1.2 负载均衡的做法
大体上有 节点轮询(用的最多);设置权重(我们可以给配置高的机器权重增高,这个是很好理解的)
2. 具体的负载均衡器介绍与使用
2.1 Ribbon
Ribbon 是 客户端的负载均衡器,通过Spring Cloud 封装,所以不必要额外引入依赖,我们直接通过注解使用
@Bean
@LoadBalanced // 这几是Ribbon的注解
public RestTemplate restTemplate() {
return new RestTemplate();
}
我依然沿用微服务系列第一篇的 订单服务和 视频服务作为例子
// 在上述添加了 @LoadBalance 的注解之后
// 我们去调用 视频服务的 find_by_id 接口
Video video = restTemplate.getForObject("http://video-service/api/v1/video/find_by_id 接口?videoId="+videoId, Video.class);
其实这就可以了;那么如何看有没有生效呢? 下图用 Postman 测试一下
1. 首先我生成两个实例,分别设置端口 为9000 和 9001
然后连续访问两遍,打印 端口信息
两次的端口不一样(因为默认采用节点轮询的效果)。
说明负载均衡 Ribbon 生效了。
到这个地方,我们发现了一个问题,就是依旧没有结局可调整性的问题,我们还是以 URL (http://video-service/api/v1/video/find_by_id)的形式去调用服务,那么有没有更优的解决方案呢?
这就引出了 如下 的 feign
2.2 Feign
原先 Ribbon 存在的问题:不规范,风格不统一,维护性比较差;
Feign 封装了 Ribbon;同时保证了代码的维护性和规范性,下面我们看看Feign是如何使用的;看过流程之后能更好的理解它的优点。
2.2.1 导入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2.2.2 注解
在启动类上注明注解
@EnableFeignClients
2.2.3 增添接口
例如 我们作为订单 orderService,需要调用 videoService 的接口,我们在 orderService 服务中新建一个 videoService 的接口。
这个接口上不注 @Service;而注上@FeignClient(name=“video-service”),
name 与 nacos 中注册的保持一致 (nacos 支持Feign)
然后
我们在这个接口中写相应的方法,并注上注解
@FeignClient(name="video-service")
public interface videoService{
@GetMapping(value = "/api/v1/video/find_by_id")
Video findById(@RequestParam("videoId") int videoId);
}
我们可以再 controller层进行 service 的使用了,就好像在本地同一个服务中一样。
其实 Feign 是一个 SpringCloud 提供的一个伪http;相比较 Ribbon 来看,我们仿佛就是把原先的 URL 语句拆分成了一个个注解。 是的,Feign 在启动之后会将这些注解中我们写好的参数拼接成一个完整的 URL 语句。
注意:对于 Get 请求,我们使用 @GetMapping;如果我们在调用接口的过程中需要传递参数,那么 Post 请求如何做呢?
// 使用 PostMapping 注解
// 同时 对于参数我们要用 @RequestBody 注解
@PostMapping("save")
public Object save(@RequestBody Video video){
System.out.println(video.getTitle());
return video;
}
综上,我们完全可以使用 Feign,因为 Feign 默认就是集成了 Ribbon,同时代码更加友好