负载均衡策略

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

然后连续访问两遍,打印 端口信息

不同负载均衡策略使用场景 负载均衡的策略_分布式

两次的端口不一样(因为默认采用节点轮询的效果)。

不同负载均衡策略使用场景 负载均衡的策略_不同负载均衡策略使用场景_02

说明负载均衡 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,同时代码更加友好