Ribbon负载均衡
1.概述:
Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端 负载均衡的工具。
简单的说,Ribbon是Netflix发布的开源项目, 主要功能是提供客户端的软件负载均衡算法,将Netflix的中间层服务连接在一起。
Ribbon客户端组件提供一系列完善的配置项如连接超时, 重试等。简单的说,就是在配置文件中列出Load Balancer (简称LB)后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接等)去连接这些机器。我们也很容易使用Ribbon实
现自定义的负载均衡算法。
LB,即负载均衡(Load Balance),在微服务或分布式集群中经常用的一种应用。
负载均衡简单的说就是将用户的请求平摊的分配到多个服务上,从而达到系统的HA。
常见的负载均衡有软件Nginx, LVS, 硬件F5等。
相应的在中间件,例如: dubbo和SpringCloud中均给我们提供了负载均衡,SpringCloud的负载均衡算法可以自定义。
2、Ribbon初步配置
修改consumer-80的配置
- pom文件,增加Ribbon的相关依赖
<!--Ribbon相关引用,与eureka有关-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
- 修改application.yml ,追加Eureka的注册服务地址
eureka:
client:
service-url:
defaultZone: eureka7001.com:7001/eureka,http://eureka7004.com:7004/eureka,http://eureka7003.com:7003/eureka
register-with-eureka: false
- 主启动类中增加注解@EnableEurekaClient
package com.blj.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient
public class DeptConsumer80_App {
public static void main(String[] args) {
SpringApplication.run(DeptConsumer80_App.class,args);
}
}
- ConfigBean配置中增加@LoadBalance注解,开启客户端负载均衡
package com.blj.springcloud.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class ConfigBean {
@Bean
@LoadBalanced//ribbon实现的一套 ==客户端、负载均衡的工具
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
- 修改客户端访问类80的controller,将地址改为微服务名称STUDY-SPRINGCLOUD-DEPT
package com.blj.springcloud.controller;
import com.blj.springcloud.entities.Dept;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import java.util.List;
@RestController
@RequestMapping(value = "consumer")
public class DeptController_Consumer {
//public static final String REST_URL_PREFFIX="http://localhost:8001";
public static final String REST_URL_PREFFIX="http://STUDY-SPRINGCLOUD-DEPT";
//使用restTemplate访问restful接口非常简单粗暴
//(url,requestMap,responseBean.class)这三个参数分别代表
//REST请求地址,请求参数,HTTP响应被转换的对象类型
@Autowired
private RestTemplate restTemplate;
@PostMapping(value = "/dept/add")
public boolean add(@RequestBody Dept dept){
return restTemplate.postForObject(REST_URL_PREFFIX+"/dept/add",dept,Boolean.class);
}
@GetMapping(value ="/dept/get/{deptno}")
public Dept get(@PathVariable("deptno") Long deptno){
return restTemplate.getForObject(REST_URL_PREFFIX+"/dept/get/"+deptno,Dept.class);
}
@GetMapping(value ="/dept/list")
public List<Dept> list(){
return restTemplate.getForObject(REST_URL_PREFFIX+"/dept/list",List.class);
}
@RequestMapping(value = "/dept/discovery",method = RequestMethod.GET)
public Object discovery(){
return restTemplate.getForObject(
REST_URL_PREFFIX+"/dept/discovery",
Object.class);
}
}
- 启动
先启动Eureka集群,然后启动8001服务注册进eureka,再启动80客户端
- 新建8004、8003服务提供者
复制8001的配置和类
yml配置中的实例名称application name不能改,下面以8083为例
#配置服务器信息
server:
port: 8003
#数据库信息配置
spring:
application:
name: study-springcloud-dept #微服务名称
datasource:
url: jdbc:mysql://localhost:3306/clouddb03?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: root1234
driver-class-name: com.mysql.jdbc.Driver #mysql驱动包
type: com.alibaba.druid.pool.DruidDataSource #当前数据源操作类型
#druid连接池配置
initialSize: 5 #初始化连接数
minIdle: 5 #数据库连接池最小连接维持数
maxActive: 20 #数据库最大活动连接数
maxWait: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
# 配置监控统计拦截的filters,去掉监控界面sql无法统计,‘wall’用于防火墙
filters: stat,wall,log4j
maxPoolPreparedStatementPerConnectionSize: 20
userGlobalDataSourceStat: true
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
#Mybatis配置
mybatis:
#type-aliases-package: com.blj.springcloud.entities #所有Entities实体类别名所在包
mapper-locations: classpath:mybatis/mapper/**/*.xml #mapper映射文件
configuration:
map-underscore-to-camel-case: true #开启驼峰命名
cache-enabled: true #开启二级缓存
type-aliases-package: com.blj.springcloud.entities #所有Entities实体类别名所在包
#客户端注册进eureka服务列表
eureka:
client:
service-url:
#defaultZone: http://localhost:7001/eureka
defaultZone: http://localhost:7001/eureka,http://localhost:7004/eureka,http://localhost:7003/eureka
instance:
instance-id: cloud-dept8003 #自定义服务名称信息
prefer-ip-address: true #访问路径可以显示ip地址
info:
app.name: study-springcloud-micoservices
company.name: www.blj.com
build.artifactId: ${project.artifactId}
build.version: ${project.version}
- 总结
Ribbon其实就是一个软负载均衡的客户端组件,他和其他所有需要请求的客户端结合使用,和Eureka结合只是其中的一个实例。默认采用轮询算法。
Ribbon核心组件IRule
IRule:根据特定算法中从服务列表中选取一个要访问的服务
Ribbon采用的负载均衡算法:
-
com.netflix.loadbalancer.RoundRobinRule 轮询:默认
-
com.netflix.loadbalancer.RandomRule 随机
-
com.netflix.loadbalancer.AvailabilityFilteringRule 会先过滤掉由于多次访问故
障而处于断路器跳闸状态的服务、还有并发的连接数量超过阈值的服务,然后对剩余 的服务列表按照轮询策略进行访问 -
com.netflix.loadbalancer.WeightedResponseTimeRule 根据平均响应时间计算所有服务的权重,响应时间越快的服务权重越大,选中的概率越高。刚启动时如果统计信息不足,则上有RoundRobinRule策略,等统计信息足够,会切换到WeightedResponseTimeRule
-
com.netflix.loadbalancer.RetryRule 先按RoundRobinRule轮询算法获取服务,如果失败则在指定时间内进行重试
-
com.netflix.loadbalancer.BestAvailableRule 会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务
-
com.netflix.loadbalancer.ZoneAvoidanceRule 默认规则,复合判断Server所在区域的性能和Server的可用性选择服务
配置负载均衡算法
1、使用Ribbon内置的7种负载均衡的算法:在ConfigBean中显示声明算法,增加bean
@Bean
public IRule myRule(){
return new RandomRule(); //用我们选择的随机算法
}
2.使用自定义的负载均衡算法
- 1、主启动类上添加注解@RibbonClient
package com.blj.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
@SpringBootApplication
@EnableEurekaClient
//在启动该微服务式是能去加载我们定义的Ribbon配置类
@RibbonClient(name="STUDY-SPRINGCLOUD-DEPT",configuration = MySelfRule.class)
public class DeptConsumer80_App {
public static void main(String[] args) {
SpringApplication.run(DeptConsumer80_App.class,args);
}
}
- 2、编写自定义Ribbon配置类
注意:Ribbon官方文档明确指出:自定义配置类不能放在@ComponentScan所扫描的当前包以及子包下,否则我们自定义的这个配置类就会被所有的Ribbon客户端锁共享,达不到特殊定制化的目的。
所以,我们新建package com.blj.myrule,编写MySelfRule.java
package com.blj.myrule;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MySelfRule {
//这里面编写自定义的负载均衡算法,
// 这里就简单直接还是用Ribbon内置的算法作为演示
@Bean
public IRule getMySelfRule(){
return new RandomRule();//随机算法
}
}
- 3、自定义规则深度解析
package com.blj.myrule;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.Server;
public class MyRandomRule extends AbstractLoadBalancerRule {
//实现代码
@Override
public Server choose(Object o) {
//实现代码
return null;
}
@Override
public void initWithNiwsConfig(IClientConfig iClientConfig) {
}
}