一、ribbon简介
Ribbon 是一个客户端负载均衡的组件,Netflix 开源的,其主要功能就是实现客户端的负载均衡。
Ribbon 客户端组件提供了一系列完善的配置项,如连接超时、重试等配置。简单来说,Ribbon是一个客户端负载均衡器,我们可以在配置文件中列出负载均衡后面所有的机器,Ribbon会自动的帮助你基于某种规则(轮询,随机等)去连接这些机器,我们也可以使用自定义Ribbon实现自己的负载均衡算法。
为什么说Ribbon是客户端的负载均衡组件?
自己的理解:
客户端和服务器端这两个概念是相互的,客户端请求服务器端,服务器端处理数据返回客户端等。
在微服务中,涉及到负载均衡操作,往往需要一个服务A去负载均衡其他的服务B,此时的服务A则可以理解为客户端。
二、Ribbon 的各种负载均衡策略配置
2.1、依赖的引入
一般情况下,我们采取 Ribbon 做客户端的负载均衡操作时,都需要引入下列依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
[注:]但是,在我们客户端(子服务)引入依赖中,我们使用了 eureka-client 的依赖。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
在引入的 Eureka-clent 中,本身就引入了Ribbon的依赖包,所以实际上,我们根本就不用额外的引入 Ribbon 的依赖文件就可以使用他。
ribbon只是一种负载均衡的方式!!接下来我们讨论ribbon 负载均衡的几种类型设置!!
2.2、增加负载均衡操作(old)
我们采取RestTemplate实现负载均衡操作,只需要在RestTemplate中增加额外的注解配置即可:
@Bean
@LoadBalanced //开启负载均衡
public RestTemplate restTemplate(){
return new RestTemplate();
}
看到这里大家可能会问到,你这里的配置和之前博客讲的一样啊,我们都是采取RestTemplate按照别名请求获取服务信息,然后使用轮询机制实现负载均衡操作。
其实我们一般请求并轮询的操作就是Ribbon。然后负载均衡的机制是默认轮询!
[问:]那我们如何自定义负载均衡方式呢?
我们可以修改负载均衡的策略,和不同的服务之间构成绑定!
[问:]如何进行自定的配置呢?
由于我们需要实现的功能为 :
请求访问不同的微服务(根据别名),使用不同的负载均衡策略!
所以我们自定义配置的文件,万万不能被SpringBoot的自动扫描注入扫描加载到!
[注:]不然就会出现我们的配置成了全局配置!!
为了实现对比操作,我们将配置类定义在自动扫描的包路径之外!!
结构如下所示:
随机轮询的配置文件如下所示:
package cn.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
/**
* 此类为 Ribbon 的配置类;<br>
* 注意:该类不在SpringbootApplication启动类的默认扫描路径下(@ComponentScan)
* @author 7651
*
*/
@Configuration
public class RibbonRandomConfig{
@Bean
public IRule ribbonRule(){
// 将默认的 轮询 更改为 随机
return new RandomRule();
}
}
因为我们需要实现请求不同的服务,采取不同的负载均衡策略。就在自动加载路径之外对其进行了配置项,但此时本就没有加载至指定的容器中。(不在启动主类 @ComponentScan 自动扫描的路径规则下),所以我们还需要一步操作:
将我们自定义的配置 绑定 需要指定到某个负载均衡策略的服务上!!
在主类扫描的路径下,编写关联类:
package cn.linkpower.config;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
import org.springframework.context.annotation.Configuration;
import cn.config.RibbonRandomConfig;
/**
* 我想针对 app-bunana-product 服务进行随机负载均衡的策略
* @author 765199214
*
*/
@Configuration
// 将指定的哪些服务 使用什么样的负载均衡方式 关联
@RibbonClient(name="app-bunana-product",configuration = RibbonRandomConfig.class)
public class ProductRandomRibbonConfig {
}
2.3、编写控制类
编写一个控制类,前端接收请求的服务类的别名为:
app-bunana-consumer
针对各项负载均衡策略的服务类为:
app-bunana-product :自定义随机策略,端口信息:10011,10010;
app-bunana-user :默认负载均衡策略,端口信息:10055,10050。
所以我们的请求处理方式逻辑如下所示:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
public class TestController {
private static final Logger logger = LoggerFactory.getLogger(TestController.class);
@Autowired
private RestTemplate restTemplate;
@Autowired
private LoadBalancerClient loadBalancerClient;
/**
* 随机负载
* @param name
* @return
*/
@RequestMapping("/product/{name}")
public String getTest1(@PathVariable String name){
String memberUrl = "http://app-bunana-product/product/getProduct?name="+String.valueOf(name);
String result = restTemplate.getForObject(memberUrl, String.class);
return "this is consumer project ,get product result = "+String.valueOf(result);
}
@RequestMapping("/productUser/{name}")
public String productUser(@PathVariable String name){
String memberUrl = "http://app-bunana-user/productUser/getProduct?name="+String.valueOf(name);
String result = restTemplate.getForObject(memberUrl, String.class);
//ServiceInstance serviceInstance = this.loadBalancerClient.choose("app-bunana-user");
//logger.info("{}:{}:{}", serviceInstance.getServiceId(), serviceInstance.getHost(), serviceInstance.getPort());
return "this is consumer project ,get user result = "+String.valueOf(result);
}
}
2.4、测试
分别启动 eureka注册中心、consumer(消费者)、product(生产者10010和10011)、user(生产者 10050和10055)。
分别对 自定义随机负载均衡方式和默认的轮询负载均衡方式进行请求测试:
1、随机负载均衡方式:
http://localhost:10001/product/1
这里只贴出一条图示,随机的需要自己去感受。
2、默认的轮询负载均衡方式:
http://localhost:10001/productUser/1
2.5、代码案例
三、Ribbon 负载均衡新配置
我们上面分析了之前得配置方式:
1、自定义一个 配置类(这个类为了不影响全部,就必须在启动类的包之外)。
2、创建一个配置类,将对应服务(别名)和指定的负载均衡配置方式关联。
3.1、新的配置方式
但是以上的配置方式,太繁琐,同时也不利于代码的维护。之后的cloud中,有了新的方式进行配置:
直接在配置文件中配置!
[例:]我们之前是 app-bunana-product服务采取的随机负载策略操作;其他的采用默认的轮询操作。
我们可以这么写:
去掉额外的配置类,直接在配置文件中编写关联操作。
app-bunana-product: #指定的服务
ribbon:
# 负载均衡的策略:具体策略实现的子类全路径
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
app-bunana-product1122: #指定的服务
ribbon:
# 负载均衡的策略:具体策略实现的子类全路径
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
有不是默认的服务的负载均衡策略,就配几个。
3.2、测试
由于我们只是测试 app-bunana-product 子服务是随机还是轮询,所以我们分别启动:
consumer(消费者 10001)、
eurekaService(注册中心 10000)、
product(子服务 10010和10011)。
http://localhost:10001/product/2
发现回执回来的信息的端口号信息为无规则的显示。
3.3、新配置方式文件
四、配置的优先级
在之前我们主要分析了两种负载均衡方式(随机和轮询),也按照了旧的方式(java类配置)和新的方式(配置文件)进行了测试。
[问:]如果两个配置方式都有,负载均衡采取哪种配置方式?
我们将consumer中的配置方式打开,同时也在yml中配置默认的轮询方式,我们来查看运行效果。
4.1、修改yml中的负载方式
修改负载均衡方式为默认的轮询,但java类中保持为随机。
#java类的配置方式为随机,此处我们把他修改为默认的轮询
app-bunana-product:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule
4.2、测试
配置完成后,将之前的项目重启,然后请求测试:
http://localhost:10001/product/2
不断的重复请求,发现采取的是轮询方式,即:采取的是我们yml配置的方式。
[注:]得出结论:
yml(属性)配置 > java类配置 > 默认配置
4.3、配置案例
五、关于ribbon不使用eureka进行负载均衡请求(重点)
我们都知道,eureka做注册中心时,各个服务都注册至注册中心上,当进行负载均衡请求时,微服务会根据定时从微服务上拉取的各个服务信息,进行默认的轮询操作,执行相关的请求。
[问:]当我所有的服务不采取注册中心的方式,然道就不能进行负载均衡操作了?
应该可以进行负载均衡操作,那我们测试下!
5.1、创建2个项目
我们先创建两个Sprijgboot项目,给定别名,但不注册Eureka。
5.1.1、服务消费者
由于我们不再使用Eureka框架,所以我们此时就永不了内置的Ribbon了,我们再创建项目时,必须在pom中引入Ribbon的依赖文件。
5.1.1.1、消费者依赖的引入
<!-- 引入Ribbon -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
5.1.1.2、修改yml
由于不能根据别名从Eureka中拉去服务信息了,所以针对别名对应的 host和port 需要我们自己去配置。
app-bunana-product:
ribbon:
listOfServers: localhost:10010,localhost:10011
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
5.1.2、创建生产者
去除掉之前Eureka注册的配置,分别启动两个服务,端口为10010和10011。
5.2、请求测试
http://localhost:10001/product/2
重复请求操作,发现:
1、可以请求成功!
2、随机负载均衡操作!
5.3、测试代码
来源:CSDN
作者:专注写bug
链接:https://blog.csdn.net/qq_38322527/article/details/103891028