简介
Spring Cloud Ribbon是一个基于HTTP和TCP的客户端负载均衡工具,它基于Netflix Ribbon实现。通过Spring Cloud的封装,可以让我们轻松地将面向服务的REST模版请求自动转换成客户端负载均衡的服务调用。
在SpringCloud中一般配合Eureka使用,从Eureka中获取服务列表,根据负载均衡算法(轮询,随机)来选择使用的哪个服务提供者的服务
负载均衡(loadblance): 将用户请求平摊到分配到多个服务器,类似于用3个100宽带提供一个300m宽带的效果
分为:
集中式LB
在服务的消费方和提供方之间使用独立的负载均衡设施(可以是硬件,如F5,也可以是软件,如nginx),由该设施负责吧访问请求通过某中策略转发至服务的提供方
进程式LB 将负载均衡逻辑集成到消费方,消费方从服务注册中心获知那些地址可用,然后自己再从这些地址中选择一个合适的服务器,Ribbon就属于进程式LB,ribbon只是一个类库,集成在消费方进程,消费方通过它来获取到服务提供方的地址
即:ribbon是一个类库,在消费者方面进行对服务列表的选择(轮询,随机)
使用
- 导入依赖
<!--因与Eureka配合所以需要导入Eureka的依赖包-->
<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-ribbon</artifactId>
<version>1.4.7.RELEASE</version>
</dependency>
<dependency>
<groupId>com.netflix.ribbon</groupId>
<artifactId>ribbon-eureka</artifactId>
<version>2.2.5</version>
</dependency>
- 编写配置文件
eureka:
client:
register-with-eureka: false #客户端只要拿,不需要向注册中心注册
service-url:
#从多个注册中心获取
defaultZone: http://eureka1:7001/eureka,http://eureka1:7002/eureka,http://eureka1:7003/eureka
- 开启LoadBalanced 由于Client访问是通过RestTemplate来访问的 因此我们只需在RestTemplate上添加注解让其拥有负载均衡的功能即可
@Configuration
public class ConfigBean {
@Bean
@LoadBalanced
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}
- 修改Controller
之前
private static final String url="http://localhost:";被我们写死了
现在修改为private static final String url="http://PROVIDER-NAME";根据服务的id来获取
由于我们之前的三个服务提供者都叫PROVIDER-NAME,因此client有三个选择,会根据LB算法来抉择
@RestController
public class ConsumerController {
@Autowired
private RestTemplate template;
private static final String url="http://PROVIDER-NAME";
@RequestMapping("/consumer/get/{id}")
public Dept getByID(@PathVariable long id){
//请求的路径,返回的对象
Dept getEntity = template.getForObject(url + "/dev/" + id, Dept.class);
return getEntity;
}
@RequestMapping("/consumer/add")
public boolean add(String dname){
Dept dept = new Dept();
dept.setDname(dname);
System.out.println(dept);
//请求的路径,传递的参数,返回的对象
return template.postForObject(url+ "/dev/add",dept,Boolean.class);
}
@RequestMapping("/consumer/list")
public List<Dept> list(){
//请求的路径,返回的对象
return template.postForObject(url+"/dev/list",void.class,List.class);
}
}
- 由于使用了Eureka,因此需在启动类上添加注解
@SpringBootApplication
@EnableEurekaClient
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class,args);
}
}
运行后访问 http://localhost/consumer/list 由于Ribbon默认是轮询的策略,因此每次访问都是不同的服务提供者 我们也可以自定义自己的LB策略
如何自定义LB策略
IRule接口是Riboon中负责负载均衡策略的组件有多个实现类
- 继承IRule,照猫画虎将RandomRule中的代码抄过来,在"//-----"之间编写我们的代码
public class MyRandomRule extends AbstractLoadBalancerRule {
/**
* Randomly choose from all living servers
*/
private static int currentindex=0;//谁在调用
private static int total=0;//调用了几次
// @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE")
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;
}
// int index = chooseRandomInt(serverCount); //源代码,在活着的服务数之间中生成随机数
// server = upList.get(index);//源代码;根据随机数获取服务
//------------------------------------
//每个服务调用五次后,调用下一个服务
if (total<5){
server=upList.get(currentindex);
total++;
}else {
total=1;
currentindex++;
if (currentindex>=upList.size())
currentindex=0;
server=upList.get(currentindex);
}
System.out.println("--------"+server);
//------------------------------------
if (server == null) {
Thread.yield();
continue;
}
if (server.isAlive()) {
return (server);
}
server = null;
Thread.yield();
}
return server;
}
protected int chooseRandomInt(int serverCount) {
return ThreadLocalRandom.current().nextInt(serverCount);
}
@Override
public Server choose(Object key) {
return choose(getLoadBalancer(), key);
}
@Override
public void initWithNiwsConfig(IClientConfig clientConfig) {
// TODO Auto-generated method stub
}
}
- 注册到spring中
@Configuration
public class MyRuleConfig {
@Bean
public IRule myRule(){
return new MyRandomRule();
}
}
- 修改启动类
@SpringBootApplication
@EnableEurekaClient
//在微服务启动时自动去加载我们自定义的配置
@RibbonClient(name="xxx",configuration = MyRuleConfig.class)//
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class,args);
}
}
注意:我们自定义的Ribbon相关配置不应该与启动类在同一个包下
debug
No instances available for provider
旧的pom.xml中对于ribbon的依赖是
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
后面新增了一个依赖
<dependency>
<groupId>com.netflix.ribbon</groupId>
<artifactId>ribbon-eureka</artifactId>
<version>2.2.5</version>
</dependency>