Ribbon实现负载均衡
Spring Cloud Ribbon是基于Netflix Ribbon实现的一套【客户端】负载均衡工具。
Ribbon会自动帮助你基于某种规则(简单轮询、随机连接等),也可以实现自定义的负载均衡算法。
负载均衡介绍:
简单来说负载均衡就是将用户的请求ping平摊的分配到多个任务上,从而是系统达到HA(高可用)。
目前主要分两种负载均衡:
- 集中式LB:偏硬件,服务的消费方和提供方之间使用独立的LB设施(可以是硬件,如F5。也可以是软件,如Nginx),由该设施负责把访问请求以某种策略转发至服务的提供方。
- 进程内LB:偏软件, 将LB逻辑集成到消费方,消费方从服务注册中心指导哪些地址可用,再自己选择一个合适的服务器(如Ribbon)。
总结:Ribbon其实就是一个软负载均衡的客户端组件,可以和其他需要请求的客户端结合使用。
Ribbon初步配置:
分析图如下:
实现前提:构建服务提供者集群,新开两个provider模块,注册入Eureka,提供服务,集群中服务名称必须一致。
Ribbon是客户端负载均衡工具!所以应该配置在客户端。此处使用consume工程为例,配置仅需要在客户端配置即可。配置步骤如下:
1.加入依赖,因为Riboon需要依赖Eureka运行,所以要同时加入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>
2.对实现类加入@LoadBalanced注解,即以之前实现的RestTemplate为例。
在consume工程中的SpringBoot配置类ConfigBean中增加如下注解:
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 注解相当于代表该类是 applicationContext.xml */
@Configuration
public class ConfigBean
{
@Bean
@LoadBalanced
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
3. 在application.yml文件中配置向注册中心注册,如果是作为消费者模块不提供服务,不应该注册自己;
server:
port: 9001
eureka:
client:
register-with-eureka: false #作为消费者不提供服务,不应该注册自己
service-url:
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
4. 主启动类中加入@EnableEurekaClient注解;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class})
@EnableEurekaClient
public class DeptConsumer_9001_App {
public static void main(String[] args) {
SpringApplication.run(DeptConsumer_9001_App.class, args);
}
}
5. 以上步骤1~4完成后即可在controller中直接通过服务名访问系统中的微服务,服务名作为URI
consumer应用中controller实现如下:
/* 原服务url */
//private static final String REST_URL_PREFIX = "http://localhost:8001";
/* 以服务名作为URI */
private static final String REST_URL_PREFIX = "http://SPRINGCLOUDDEMO-PROVIDER-DEPT";
@Autowired
private RestTemplate restTemplate;
@RequestMapping(value = "/dept/list")
public List<Dept> list() {
return restTemplate.getForObject(REST_URL_PREFIX + "/provider/dept/list", List.class);
}
完成以上5个步骤就已经实现客户端负载均衡功能(此处使用的是默认轮询的规则进行负载均衡),可以访问客户端进行测试(略过)。
Ribbon核心组件IRule:根据特定算法从服务列表中选取一个需要访问的服务;
其中IRule是一个接口,有七个自带的落地实现类,可以实现不同的负载均衡算法规则:
RoundRobinRule | 轮询规则(默认方法) |
RandomRule | 随机 |
AvailabilityFilteringRule | 先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,还有并发的连接数量超过阈值的服务,然后对剩余的服务进行轮询 |
WeightedResponseTimeRule | 根据平均响应时间计算服务的权重。统计信息不足时会按照轮询,统计信息足够会按照响应的时间选择服务 |
RetryRule | 正常时按照轮询选择服务,若过程中有服务出现故障,在轮询一定次数后依然故障,则会跳过故障的服务继续轮询。 |
BestAvailableRule | 先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务 |
ZoneAvoidanceRule | 默认规则,符合判断server所在的区域的性能和server的可用性选择服务 |
如何切换Ribbon中赋值均衡的规则,而不是使用默认的轮询方式?
只需在客户端(consume)工程中的SpringBoot配置类ConfigBean配置一个返回具体方法的bean即可,如下:
@Bean
public IRule MyRule(){
/* RandomRule为Ribbon中自带规则实现之一,随机规则 */
return new RandomRule();
}
自定义Ribbon负载均衡算法
**如果觉得Ribbon中自带的负载均衡规则无法满足你的需求,那也可以自定义****Ribbon负载均衡算法。**
需要注意的地方;
自定义的Ribbon算法类不能放在主启动类所在的包及子包下(确切来说是不能放在@ComponentScan注解的包及子包下),否则会被全局应用到Ribbon服务中。 应该把自定义算法类放在另外新建的包下,且这个类应该是为【配置类】即加上注解@Configuration。
实现自定义Ribbon负载均衡算法的步骤:
1。将原来consumer工程中的配置类ConfigBean中返回 IRule 的Bean删掉,然后新建一个包,定义配置类,返回自定义的负载均衡规则的实现类:
package com.wangcw.ribbon;
import com.netflix.loadbalancer.IRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MySelfRule
{
@Bean
public IRule myRule() {
/* 此处返回自定义的负载算法规则 */
return new RandomRule_Myself();
}
}
2.实现自定义规则实现类RandomRule_Myself(此处实现每台服务器调用5次后,再继续轮询下一台服务器)
package com.wangcw.ribbon;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;
import java.util.List;
public class RandomRule_Myself extends AbstractLoadBalancerRule {
/*
total = 0 // 当total==5以后,我们指针才能往下走,
index = 0 // 当前对外提供服务的服务器地址,
total需要重新置为零,但是已经达到过一个5次,我们的index = 1 */
/* 总共被调用的次数,目前要求每台被调用5次 */
private int total = 0;
/* 当前提供服务的机器号 */
private int currentIndex = 0;
public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) {
return null;
}
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();
continue;
}
if (server.isAlive()) {
return (server);
}
server = null;
Thread.yield();
}
return server;
}
@Override
public Server choose(Object key) {
return choose(getLoadBalancer(), key);
}
@Override
public void initWithNiwsConfig(IClientConfig clientConfig) {}
}
3.在启动类上加上注解 @RibbonClient(name = “微服务名”,configuration = XXX.class) 注解指定需要用到负载均衡的微服务名及自定义算法的class对象。
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class})
@EnableEurekaClient
@RibbonClient(name="SPRINGCLOUDDEMO-PROVIDER-DEPT",configuration=MySelfRule.class)
public class DeptConsumer_9001_App {
public static void main(String[] args) {
SpringApplication.run(DeptConsumer_9001_App.class, args);
}
}
4.启动测试就可以发现已经生效。
还没有评论,来说两句吧...