一、ribbon简介
Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法,将Netflix的中间层服务连接在一起。
Ribbon客户端组件提供一系列完善的配置项如连接超时,重试等。简单的说,就是在配置文件中列出Load Balancer(简称LB)里面的所有机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随即连接等)去连接这些机器。我们也很容易使用Ribbon实现自定义的负载均衡算法。
总结:Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡工具
二、LB简介
- LB即负载均衡,在微服务或分布式集群中经常用的一种应用
- 负载均衡简单的说就是将用户的请求平摊的分配到多个服务上,从而达到系统的HA
- 常见的负载均衡软件有Nginx、LVS、硬件F5等
- 相应的中间件有dubbo和SpringCloud均提供了负载均衡,SpringCloud的负载均衡算法可以自定义
三、负载均衡分类
- 集中式负载均衡(偏硬件):在服务的消费方和提供方之间使用独立的负载均衡设施,由该设施负责把访问请求(通过某种策略)转发至服务的提供方
- 进程内负载均衡(偏软件):将负载均衡逻辑集成到消费方,消费方从服务注册中心获知哪些地址可用,然后再从这些地址中选择出合适的服务器来运行,从而达到负载均衡的目的
ribbon就属于进程内负载均衡,它只是一个类库,集成于消费方进程,消费方通过它来获取到服务提供方的地址
四、Ribbon+RestTemplate方式调用服务实例
4.1、添加maven依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
4.2、修改yml配置文件
server:
port: 80
eureka:
client:
register-with-eureka: false
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
4.3、通过Ribbon+RestTemplate调用服务
@Configuration
public class ConfigBean {
@Bean
@LoadBalanced
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
4.4、主启动类添加@EnableEurekaClient注解
@SpringBootApplication
@EnableEurekaClient
public class DeptConsumer80_App {
public static void main(String[] args) {
SpringApplication.run(DeptConsumer80_App.class,args);
}
}
4.5、修改服务消费者Controller
@RestController
public class DeptControllerConsumer {
//private static final String REST_URL_PREFIX="http://localhost:8001";
private static final String REST_URL_PREFIX="http://MICROSERVICECLOUD-DEPT";
@Autowired
private RestTemplate restTemplate;
@RequestMapping(value = "/consumer/dept/add")
public boolean add(Dept dept){
return restTemplate.postForObject(REST_URL_PREFIX+"/dept/add",dept,Boolean.class);
}
@RequestMapping(value = "/consumer/dept/get/{id}")
public Dept get(@PathVariable("id")Long id){
return restTemplate.getForObject(REST_URL_PREFIX+"/dept/get/"+id,Dept.class);
}
@RequestMapping(value = "/consumer/dept/list")
public List<Dept> list(){
return restTemplate.getForObject(REST_URL_PREFIX+"/dept/list",List.class);
}
@RequestMapping(value = "/consumer/dept/discovery")
public Object discovery(){
return restTemplate.getForObject(REST_URL_PREFIX+"/dept/discovery",Object.class);
}
}
总结:Ribbon和Eureka整合后,服务消费者可以直接调用服务而不再关心访问地址和端口号,可以通过微服务名称直接调用,其中微服务名称为微服务提供者注册的服务名称
spring:
application:
name: microservicecloud-dept
五、ribbon负载均衡
ribbon在工作时分成两步
- 先选择Eureka Server,它优先选择在同一个区域内负载较少的server
- 再根据用户指定的策略,从Eureka Server取到的服务注册列表中选择一个地址
其中ribbon提供了多种策略,比如轮询、随机和根据响应时间加权
六、ribbon核心组件IRule
官方网址
IRule:根据特定算法中从服务列表中选取一个要访问的服务
- RoundRobinRule:轮询
- RandomRule:随机
- AvailabilityFilteringRule:会先过滤掉由于多次访问故障而处于断路跳闸状态的服务,还有并发的连接数量超过阀值的服务,然后对剩余的服务列表按照轮询策略进行访问
- WeightedResponseTimeRule:根据平均响应时间计算所有服务的权重,响应时间越快服务权重越大,被选中的概率越高,刚启动时,如果统计信息不足,则使用RoundRobinRule策略,等统计信息足够,会切换到WeightedResponseTimeRule
- RetryRule:先按照轮询的策略获取服务,如果获取服务失败则在指定时间内会进行重试,获取可用的服务
- BestAvailableRule:先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务
- ZoneAvoidanceRule:默认规则,复合判断server所在区域的性能和server的可用性选择服务器
@Configuration
public class ConfigBean {
@Bean
@LoadBalanced
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
//用新定义的负载均衡规则覆盖默认的负载均衡规则
@Bean
public IRule myRule(){
//return new RoundRobinRule();// todo 轮询
//return new RandomRule();//todo 随机
return new RetryRule();//todo 先按照轮询的策略获取服务,如果获取服务失败则在指定时间内会进行重试,获取可用的服务
}
}
七、自定义ribbon的负载均衡策略
-
启动类添加@RibbonClient
在启动该微服务的时候就能去加载我们的自定义Ribbon配置类,从而使配置生效 -
注意配置细节
官方文档明确给出了警告,自定义配置类不能放在@ComponentScan所描述的当前包下以及其子包下 否则这个配置类就会被所有的Ribbon客户端所共享,达不到特殊化定制的目的
需求:依旧轮询策略,但是加上新需求,每台服务器要求被调用5次
5.1、自定义算法:
public class RandomRule_ZY extends AbstractLoadBalancerRule {
private int total=0;//todo 总共调度的次数,目前要求每台被调用5次
private int currentIndex=0;//todo 当前提供服务的机器号
public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) {
return null;
} else {
Server server = null;
while(server == null) {
if (Thread.interrupted()) {
return null;
}
List<Server> upList = lb.getReachableServers();
List<Server> allList = lb.getAllServers();
int serverCount = allList.size();
if (serverCount == 0) {
return null;
}
if(total<5){
server=upList.get(currentIndex);
total++;
}else{
total=0;
currentIndex++;
if(currentIndex>=upList.size()){
currentIndex=0;
}
}
if (server == null) {
Thread.yield();
} else {
if (server.isAlive()) {
return server;
}
server = null;
Thread.yield();
}
}
return server;
}
}
@Override
public void initWithNiwsConfig(IClientConfig iClientConfig) {}
@Override
public Server choose(Object key) {
return this.choose(this.getLoadBalancer(), key);
}
}
5.2、调用:
@Configuration
public class MySelfRule {
@Bean
public IRule myRule(){
return new RandomRule_ZY();//todo 自定义负载均衡算法
}
}
5.3、主启动类添加注解:
@SpringBootApplication
@EnableEurekaClient
@RibbonClient(name = "MICROSERVICECLOUD-DEPT",configuration = MySelfRule.class)
public class DeptConsumer80_App {
public static void main(String[] args) {
SpringApplication.run(DeptConsumer80_App.class,args);
}
}