一、简介
Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡的工具。简单的说,Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法,将Netflix的中间层服务连接在一起。Ribbon客户端组件提供一系列完善的配置项如连接超时,重试等。简单的说,就是在配置文件中列出Load Balancer(简称LB)后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接等)去连接这些机器。我们也很容易使用Ribbon实现自定义的负载均衡算法。
LB,即负载均衡(Load Balance),在微服务或分布式集群中经常用的一种应用。负载均衡简单的说就是将用户的请求平摊的分配到多个服务上,从而达到系统的HA。常见的负载均衡有软件Nginx,LVS,硬件 F5等。相应的在中间件,例如:dubbo和SpringCloud中均给我们提供了负载均衡,SpringCloud的负载均衡算法可以自定义。
二、代码实现
注意 Ribbon 是客户端的工具,所以在消费者端项目操作,Ribbon 需要 Eureka 配合
- maven 依赖
<!-- 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>
- yml 配置
server:
port: 80
spring:
application:
name: consumer80 #注册中心服务的名字
eureka:
client:
register-with-eureka: true
service-url:
defaultZone: http://127.0.0.1:7001/eureka #注册中心服务端地址
- 在启动类启动类添加注解 @EnableEurekaClient
@SpringBootApplication
@EnableEurekaClient
public class ConsumerApplication {
- Ribbon 负载均衡是在 Rest 的基础上做的,只需要在 bean 添加一个注解 @LoadBalanced
@Configuration
public class RestConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
访问的时候通过 Eureka 注册中心的应用名访问
@RestController
public class RoleController {
private static final String REST_URL_PREFIX = "http://CORK-PROVIDER/cork";
@Autowired
private RestTemplate restTemplate;
@GetMapping("/consumer")
public Result list(){
return restTemplate.getForObject(REST_URL_PREFIX + "/list", Result.class);
}
}
这里我写了三个服务提供者,每个服务使用不同的库,一个消费者。
我访问消费者时候
第一次是1号库,再刷新
第二次是2号库
第三次是3号库,第四次是1号库,Ribbon 默认采用的负载均衡算法是轮循算法,当然我们还可以自定义算法和Ribbon自带的算法。
- RoundRobinRule():默认轮循算法
- RandomRule():随机算法
- AvailabilityFilteringRule():
- WeightedResponseTimeRule()
- RetryRule()
- BestAvailableRule()
- ZoneAvoidanceRule()
@Bean
public IRule myRule(){
// return new RoundRobinRule();
// return new RandomRule();
// return new AvailabilityFilteringRule();
// return new WeightedResponseTimeRule();
// return new RetryRule();
// return new BestAvailableRule();
return new ZoneAvoidanceRule();
}
public class MySelfRule extends AbstractLoadBalancerRule {
private int total = 0;
private int index = 0;
@Override
public void initWithNiwsConfig(IClientConfig iClientConfig) {
}
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(index);
total++;
}else {
total = 0;
index++;
if (index >= upList.size()){
index = 0;
}
}
if (server == null) {
Thread.yield();
} else {
if (server.isAlive()) {
return server;
}
server = null;
Thread.yield();
}
}
return server;
}
}
public Server choose(Object key) {
return this.choose(this.getLoadBalancer(), key);
}
}