Ribbon
当一个服务需要提供多个的时候,负载均衡策略就成为了一个问题。我们可以使用随机、轮询、hash等方式实现负载均衡的策略。
Ribbon是一个为客户端提供负载均衡功能的服务,它内部提供了一个叫做ILoadBalance的接口代表负载均衡器的操作,比如有添加服务器操作、选择服务器操作、获取所有的服务器列表、获取可用的服务器列表等等。
使用Eureka时存在的问题
- 当部署多个相同微服务的时候,如何实现负载均衡?
- 微服务间互相通讯的时候,必须硬编码的形式获取服务的地址。
Ribbon简介
Ribbon是Netflix发布的云中间层服务开源项目,其主要功能是提供客户端实现负载均衡算法。Ribbon客户端组件提供一系列完善的配置项如连接超时,重试等。简单的说,Ribbon是一个客户端负载均衡器,我们可以在配置文件中Load Balancer后面的所有机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接等)去连接这些机器,我们也很容易使用Ribbon实现自定义的负载均衡算法。
下图展示了Eureka使用Ribbon时的大致架构:
Ribbon入门案例
在服务调用方consumer添加Ribbon依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
实现方式1:
修改web层的
/***
* 注入discoveryClient 注意是Spring的包
*/
@Autowired
private DiscoveryClient discoveryClient;
@GetMapping("/{id}")
public Employee getEmployeeById(@PathVariable Integer id) {
//获取实例列表
List<ServiceInstance> instancesList = discoveryClient.getInstances("emp-provider");
//获取实例
ServiceInstance instance = instancesList.get(0);
//获取主机地址
String hostName = instance.getHost();
//获取端口号
int port = instance.getPort();
//拼接url
String url = "http://" + hostName + ":" + port + "/employee/" + id;
//调用接口
Employee employee = restTemplate.getForObject(url, Employee.class);
//返回结果
return employee;
}
改为
@Autowired
private RibbonLoadBalancerClient client;
@GetMapping("/{id}")
public Employee getEmployeeById(@PathVariable Integer id) {
//轮询获取实例
ServiceInstance instance = client.choose("emp-provider");
//获取主机地址
String hostName = instance.getHost();
//获取端口号
int port = instance.getPort();
//拼接url
String url = "http://" + hostName + ":" + port + "/employee/" + id;
//调用接口
Employee employee = restTemplate.getForObject(url, Employee.class);
//返回结果
return employee;
}
方法2:修改配置类,在restTemplate方法上加入@LoadBalanced注解
package cn.rayfoo.config;
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;
/**
* @Author: rayfoo@qq.com
* @Date: 2020/7/2 2:29 下午
* @Description:
*/
@Configuration
public class RestTemplateConfiguration {
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
修改web层代码为
package cn.rayfoo.controller;
import cn.rayfoo.bean.Employee;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.List;
/**
* @Author: rayfoo@qq.com
* @Date: 2020/7/2 2:30 下午
* @Description:
*/
@RestController
@RequestMapping("/employee")
public class EmployeeController {
@Autowired
private RestTemplate restTemplate;
private static final String REST_URL_PREFIX = "http://emp-provider";
@GetMapping("/{id}")
public Employee getEmployeeById(@PathVariable Integer id) {
String url = REST_URL_PREFIX + "/employee/" + id;
//调用接口
Employee employee = restTemplate.getForObject(url, Employee.class);
//返回结果
return employee;
}
}
此时就通过服务名称自动通过轮询策略拿到项目的url,无需关心服务器的地址和端口号。
Ribbon负载均衡策略
Ribbon支持自定义的负载均衡策略和算法,但一般轮询就够我们使用,无需手动实现。
参考:参考博客
更详细的介绍:地址