一、什么是Spring Cloud Ribbon?
- Spring Cloud Ribbon 是Spring Cloud Netflix 子项目的核心组件之一,主要给服务间调用及API网关转发提供负载均衡的功能。
- 在微服务架构中,很多服务都会部署多个,其他服务去调用该服务的时候,如何保证负载均衡是个不得不去考虑的问题。负载均衡可以增加系统的可用性和扩展性,当我们使用RestTemplate来调用其他服务时,Ribbon可以很方便的实现负载均衡功能。
- Ribbon 的客户端组件提供一系列完整的配置项如:连接超时、重试等等。简单的说,就是在配置文件中列出LoadBalancer后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接等等)去连接这些机器,我们也很容易使用Ribbon实现自定义的负载均衡算。
- 负载均衡简单分类:
集中式LB
:即在服务的消费方和提供方之间使用独立的LB设施,如反向代理服务器,由该设施负责把访问请求通过某种策略转发至服务的提供方。进程式LB
:将LB逻辑集成到消费方,消费方从服务注册中心获知有哪些地址可用,然后自己再从这些地址中选出一个合适的服务器。
- Ribbon就属于进程内LB,它只是一个类库,集成于消费方进程,消费方通过它来获取到服务提供方的地址。
二、案例演示
-
添加依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> <version>2.2.0.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId> <version>2.2.0.RELEASE</version> </dependency>
-
添加配置
启动类
@SpringBootApplication @EnableEurekaClient public class RibbonClientApplication { public static void main(String[] args) { SpringApplication.run(RibbonClientApplication.class, args); } }
自定义配置类
@Configuration public class MyConfig { @Bean @LoadBalanced public RestTemplate restTemplate(){ return new RestTemplate(); } }
application.yml文件
server: port: 8080 servlet: context-path: / spring: application: name: ribbon-client eureka: client: register-with-eureka: false fetch-registry: true service-url: defaultZone: http://localhost:8010/eureka # 服务访问地址 user-service-url: http://ribbon-service/
-
测试使用
-
编写控制器类
@RestController public class UserController { @Autowired private RestTemplate restTemplate; @Value("${user-service-url}") private static String SERVICE_URL; @GetMapping("/get/{id}") public Map<String, Object> getUser(@PathVariable Long id){ Map result = restTemplate.getForObject(SERVICE_URL + "get/" + id, Map.class); return result; } @GetMapping("/add") public Map<String, Object> addUser(User user){ Map result = restTemplate.postForObject(SERVICE_URL + "add", user, Map.class); return result; } }
-
访问
访问:http://localhost:8010/
访问:http://localhost:8080/get/1
发现Ribbon默认采用轮询算法依次在每一个服务方进行访问
-
三、负载均衡策略
-
已定义的策略
Ribbon默认使用的是轮询算法
-
com.netflix.loadbalancer.RandomRule
:从提供服务的实例中以随机的方式;
-
com.netflix.loadbalancer.RoundRobinRule
:以线性轮询的方式,就是维护一个计数器,从提供服务的实例中按顺序选取,第一次选第一个,第二次选第二个,以此类推,到最后一个以后再从头来过;
-
com.netflix.loadbalancer.RetryRule
:在RoundRobinRule的基础上添加重试机制,即在指定的重试时间内,反复使用线性轮询策略来选择可用实例;
-
com.netflix.loadbalancer.WeightedResponseTimeRule
:对RoundRobinRule的扩展,响应速度越快的实例选择权重越大,越容易被选择;
-
com.netflix.loadbalancer.BestAvailableRule
:选择并发较小的实例;
-
com.netflix.loadbalancer.AvailabilityFilteringRule
:先过滤掉故障实例,再选择并发较小的实例;
-
com.netflix.loadbalancer.ZoneAwareLoadBalancer
:采用双重过滤,同时过滤不是同一区域的实例和故障实例,选择并发较小的实例。
-
-
自定义均衡策略
-
启动类添加注解
@SpringBootApplication @EnableEurekaClient @RibbonClient(name = "ribbon-service", configuration = RuleConfig.class) public class RibbonClientApplication { public static void main(String[] args) { SpringApplication.run(RibbonClientApplication.class, args); } }
-
自定义配置类
public class MyRule extends AbstractLoadBalancerRule { public MyRule() { } private int total = 1; private int current = 0; @SuppressWarnings({"RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE"}) 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 <= 3){ server = upList.get(current); total++; }else{ total = 1; current += 1; if(current > upList.size()-1){ current = 0; } server = upList.get(current); } //-****************************** if (server == null) { Thread.yield(); } else { if (server.isAlive()) { return server; } server = null; Thread.yield(); } } return server; } } protected int chooseRandomInt(int serverCount) { return ThreadLocalRandom.current().nextInt(serverCount); } public Server choose(Object key) { return this.choose(this.getLoadBalancer(), key); } public void initWithNiwsConfig(IClientConfig clientConfig) { } }
@Configuration public class RuleConfig { @Bean public IRule myRule(){ return new MyRule(); } }
-
五、常用配置
-
全局配置
ribbon: ConnectTimeout: 1000 #服务请求连接超时时间(毫秒) ReadTimeout: 3000 #服务请求处理超时时间(毫秒) OkToRetryOnAllOperations: true #对超时请求启用重试机制 MaxAutoRetriesNextServer: 1 #切换重试实例的最大个数 MaxAutoRetries: 1 # 切换实例后重试最大次数 NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #修改负载均衡算法
-
局部配置
user-service: ribbon: ConnectTimeout: 1000 #服务请求连接超时时间(毫秒) ReadTimeout: 3000 #服务请求处理超时时间(毫秒) OkToRetryOnAllOperations: true #对超时请求启用重试机制 MaxAutoRetriesNextServer: 1 #切换重试实例的最大个数 MaxAutoRetries: 1 # 切换实例后重试最大次数 NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #修改负载均衡算法
【源码地址】:GitHub