Spring Cloud Ribbon是基于Netflix Ribbon实现的一套==客户端==负载均衡工具。Ribbon会自动帮助你基于某种规则(简单轮询、随机连接等),也可以实现自定义的负载均衡算法
[Ribbon源码]: https://github.com/Netflix/Ribbon
### 负载均衡
- 英文名称:Load Balance,微服务或分布式集群中常用的一种应用
- 简单来说负载均衡就是将用户的请求ping平摊的分配到多个任务上,从而是系统达到HA(高可用)
- 两种负载均衡:
1. 集中式LB:偏硬件,服务的消费方和提供方之间使用独立的LB设施,由该设施负责把访问请求以某种策略转发至服务的提供方
2. 进程内LB:骗软件, 将LB逻辑集成到消费方,消费方从服务注册中心指导哪些地址可用,再自己选择一个合适的服务器
#### Ribbon初步配置
- ==Ribbon是客户端负载均衡工具!!!Ribbon是客户端负载均衡工具!!!Ribbon是客户端负载均衡工具!!!==所以应该配置在客户端
修改 microservicecloud-consumer-dept-80
1. 加入依赖,因为Riboon需要依赖Eureka运行,所以要同时加入Eureka依赖
<!-- Ribbon相关 -->
<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>
2.在application.yml文件中配置向注册中心注册,如果是作为消费者模块不提供服务,不应该注册自己
// 修改application.yml,追加eureka的服务注册地址
eureka:
client:
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
register-with-eureka: false #作为消费者不提供服务,不应该注册自己
// ConfigBean 添加新注解 @LoadBalanced, 用于加入 Ribbon 配置
@Configuration
public class ConfigBean {
@Bean
@LoadBalanced
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}
主启动类中加入@EnableEurekaClient注解:
@SpringBootApplication
@EnableEurekaClient
public class DeptConsumer80_App {
public static void main(String[] args) {
SpringApplication.run(DeptConsumer80_App.class, args);
}
}
以上步骤完成后即可在controller中直接通过服务名访问系统中的微服务,服务名作为URI
// 修改 DeptController_Consumer 客户端访问类
private static final String REST_URL_PREFIX = "http://MICROSERVICECLOUD-DEPT";
// 测试访问:
// http://localhost:8082/consumer/dept/get/1
// http://localhost:8082/consumer/dept/list
// http://localhsot:8082/consumer/dept/add?dname=广告部
总结一下:用Eureka和Ribbon整合后,可以直接通过服务名调用服务不需要关心地址和端口
Ribbon负载均衡实现
架构示意图:
##### 实现方法
目标:构建provider集群后consumer通过负载均衡轮询调用在Eureka中注册的服务
1. 构建集群,新开两个provider模块,将原provider的==代码部分和pom.xml中依赖照搬==到新的provider中
2. 将原provider中application.yml文件照搬到新provider,并修改端口号,若新的provider使用自己的数据库,则修改数据库信息(其他配置也一样,如修改别名)
3. 集群中服务名称必须一致!!!
// 新建microservicecloud-provider-dept-8002
// 新建microservicecloud-provider-dept-8003
// 新建8002/8003数据库
// 修改8002/8003各自YML
spring:
application:
name: microservicecloud-dept #同一集群下必须使用同一服务名!!!!!
启动服务,进行测试
##### 总结
Ribbon其实就是一个软负载均衡的客户端组件,可以和其他需要请求的客户端结合使用
Ribbon核心组件IRule
IRule:根据特定算法从服务列表中选取一个需要访问的服务
根据特定算法,从服务列表中选取一个要访问的服务;
==IRule是一个接口,七大方法是其自带的落地实现类==
- RoundRobinRule:轮询
- RandomRule:随机
- AvailabilityFilteringRule: 会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,以及并发的连接数量
超过阈值的服务,然后对剩余的服务列表按照轮询策略进行访问; - WeightedResponseTimeRule: 根据平均响应时间计算所有服务的权重,响应时间越快,服务权重越大,被选中的机率越高;
刚启动时,如果统计信息不足,则使用RoundRobinRule策略,等统计信息足够时,会切换到WeightedResponseTimeRule - RetryRule: 先按照RoundRobinRule的策略获取服务,如果获取服务失败,则在指定时间内会进行重试,获取可用的服务;
- BestAvailableRule: 会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务;
- ZoneAvoidanceRule: 默认规则,复合判断server所在区域的性能和server的可用性选择服务器;
只需在==配置类==中配置一个返回具体方法的bean即可
// 修改 microservicecloud-consumer-dept-80,// ConfigBean
@Configuration
public class ConfigBean {
@Bean
@LoadBalanced
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
@Bean
public IRule myRule() {
return new RoundRobinRule(); // 显式的指定使用轮询算法
}
}
自定义Ribbon负载均衡算法
#### 配置及包位置
1. 自定义的Ribbon算法类不能放在主启动类所在的包及子报下(确切来说是不能放在 @ComponentScan注解的包及子包下),否则会被全局应用到Ribbon服务中。应该把自定义算法类放在另外新建的包下,且这个类应该是为==配置类==。(其实与普通切换负载均衡规则类似,只不过是位置不同而已,普通的可以放在主启动类所在的包,自定义的要放在外面的包下)
2. 主启动类添加 @RibbonClient(name = "微服务名",configuration = XXX.class)注解指定需要用到负载均衡的微服务名及自定义算法的class对象
// 修改主启动类
@SpringBootApplication
@EnableEurekaClient
@RibbonClient(name="MICROSERVICECLOUD-DEPT", configuration=MySelfRule.class) // 自定义Ribbon配置类
public class DeptConsumer80_App {
public static void main(String[] args) {
SpringApplication.run(DeptConsumer80_App.class, args);
}
}
// com.zhou.myrule
// 自定义Robbin规则类
@Configuration
public class MySelfRule{
@Bean
public IRule myRule(){
return new RandomRule(); //自定义均衡策略
}
}
####通过修改源代码获得自定义算法
目标:每个服务调用5次后再进行轮询(调用次数不是很对,懒得改了)
官网源码解析: https://github.com/Netflix/ribbon/blob/304e38cf765a1d09ec950502ac62437a05c7eab4/ribbon-loadbalancer/src/main/java/com/netflix/loadbalancer/RandomRule.java
Feign负载均衡
服务调用方式:
1.使用微服务名字获取调用地址进行调用
2.使用接口+注解来获取我们需要调用的服务--面向接口编程-Feign
Feign是一个声明式WebService客户端,使用方法时定义一个接口并在上面添加注解即可。Feign支持可拔插式的编码器和解码器。Spring Cloud对Feign进行了封装,使其支持SpringMVC和HttpMessageConverters。Feign可以与Eureka和Ribbon组合使用以支持负载均衡。
Feign 是一个声明式WebService客户端:
- 使用方法:定义一个接口,然后在上面添加注解;
[Feign源码]: https://github.com/OpenFeign/Feign
官网文档:https://projects.spring.io/spring-cloud/spring-cloud.html#spring-cloud-feign
### 使用案例
创建microservicecloud-consumer-dept-feign工程
新建Feign模块,加入依赖(其实跟80消费者差不多,主要是多了Feign依赖)
<!-- Feign相关 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
// 修改 microservicecloud-api 工程,// pom.xml
因为Feign开发其实是面向接口编程,所以Feign接口可以放在api模块中供各模块使用,所以要在api模块中添加Feign依赖
<!-- Feign相关 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
// 修改 microservicecloud-api 工程,// 新建DeptClientService接口,并新增注解@FeignClient
在api中编写接口,接口上添加@FeignClient注解,并通过value指定作用的微服务名
@FeignClient(value="MICROSERVICECLOUD-DEPT")
public interface DeptClientService {
@RequestMapping(value="/dept/get/{id}", method= RequestMethod.GET)
public Dept get(@PathVariable("id") long id);
@RequestMapping(value="/dept/list", method= RequestMethod.GET)
public List<Dept> list();
@RequestMapping(value="/dept/add", method= RequestMethod.POST)
public boolean add(Dept dept);
}
// mvn clean,// mvn install
// microservice-consumer-dept-feign 工程修改Controller
在Feign模块中编写Controller,并注入FeignClient接口,直接调用service接口中的方法即可(因为声明Feign接口时已经指定过微服务,所以访问时会正确地找到微服务)
@RestController
public class DeptController_Consumer {
@Autowired
private DeptClientService service;
@RequestMapping(value="/consumer/dept/get/{id}")
public Dept get(@PathVariable("id") Long id) {
return this.service.get(id);
}
@RequestMapping(value="/consumer/dept/list")
public List<Dept> list(){
return this.service.list();
}
@RequestMapping(value="/consumer/dept/add")
public Object add(Dept dept) {
return this.service.add(dept);
}
}
// 修改主启动类
修改Feign模块的主启动类,加入@EnableFeignClients注解和@ComponentScan注解(主要是扫描api中声明的接口
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients(basePackages = {"com.zhou.springcloud"})
@ComponentScan("com.zhou.springcloud")
public class DeptConsumer80_Feign_App {
public static void main(String[] args) {
SpringApplication.run(DeptConsumer80_Feign_App.class, args);
}
}
启动后访问,即会按照轮询的方式调用provider集群
### 总结
- Feign通过接口方法调用REST服务,在Eureka中查找对应的服务
- Feign集成了Ribbon技术,所以也支持负载均衡(轮询)