一、
Spring Cloud Ribbon是基于Netflix Ribbon网站建设定制开发实现的一套客户端 的工具。
简单的说,Ribbon是Netflix网站建设定制开发发布的开源项目,网站建设定制开发主要功能是提供客户端网站建设定制开发的软件负载均衡算法和服务调用。Ribbon网站建设定制开发客户端组件提供一系列网站建设定制开发完善的配置项如连接超时,重试等。简单的说,网站建设定制开发就是在配置文件中列出Load Balancer(简称LB)网站建设定制开发后面所有的机器,Ribbon网站建设定制开发会自动的帮助你基于某种规则(如简单轮询,随机连接等)去连接这些机器。我们很容易使用Ribbon实现自定义的负载均衡算法。
在前面的文章中,我们讲解到了eureka、zookeeper、consul作为注册中心,及采用 RestTemplate 作为客户端工具调用服务,后面我们也会讲到feign客户端工具。在使用中我们会发现,我们在声明 RestTemplate 时就加了一个@LoadBalanced 就实现了服务负载功能,其实是 ribbon 已经对RestTemplate 做了适配和优化,在RestTemplate 调用服务时会进入ribbon 的 负载规则器 ,选取出合适的请求服务ip 和 端口再交于 RestTemplate 进行http 请求。
上篇文章地址:https://blog.csdn.net/qq_43692950/article/details/121990497
在前面的演示中,我们也发现了,我们其实并没有针对的引入ribbon 的依赖,却也使用了ribbon的功能,ribbon已经附在了 eureka或其他一些cloud工具包中了,因此大多数情况下,我们无需主动配置ribbon的依赖:
二、Ribbon的基本使用
如果是采用 RestTemplate 作为客户端调用工具,只需在声明RestTemplate时加上 @LoadBalanced 即可自动使用 Ribbon的负载功能:
@Configurationpublic class RestTemplateConfig { @Bean @LoadBalanced public RestTemplate getRestTemplate() { return new RestTemplate(); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
如果是 feign 客户端工具,当然现在普遍用的是openFeign,在引入openFeign的依赖时,也会附带 ribbon,可以理解为 feign 是一个ribbon + httpclient 的结合封装产品,所以使用feign 时,如果是指定的注册中心的服务,则会自动开启了负载均衡。
三、Ribbon的负载均衡算法
Ribbon默认是采用轮训的算法,当然Ribbon肯定不只是这一种算法,但轮训也是我们项目中比较常用的一个选择,因为现在微服务,强调服务平等,大家都承受相同的压力,便于对服务的管理,但有时我们可能不想使用轮训算法。ribbon 所有的策略算法均实现与IRule 接口,下面我们看下Ribbon为我们提供的算法有哪些:
各个算法的说明:
-
RoundRobinRule:轮询
-
RandomRule:随机
-
AvailabilityFilteringRule:会先过滤掉由于多次访问故障而处于断路器状态的服务,还有并发的连接数量超过阈值的服务,然后对剩余的服务列表按照轮询策略进行访问
-
WeightedResponseTimeRule:根据平均响应时间计算所有服务的权重,响应时间越快的服务权重越大被选中的概率越大。刚启动时如果统计信息不足,则使用RoundRobinRule(轮询)策略,等统计信息足够,会切换到WeightedResponseTimeRule
-
RetryRule:先按照RoundRobinRule(轮询)策略获取服务,如果获取服务失败则在指定时间内进行重试,获取可用的服务
-
BestAvailableRule:会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务
-
ZoneAvoidanceRule:复合判断Server所在区域的性能和Server的可用性选择服务器
四、切换Ribbon的负载均衡算法
上面我们了解到了,各种ribbon提供的负载算法,下面就需要我们针对性的切换到合适的算法,下面均在服务消费者端修改:
我们将默认的轮训算法替换为随机算法
- 添加 RibbonLoadBalancedConfig.java
public class RibbonLoadBalancedConfig { @Bean public IRule myRule() { //定义为随机算法 return new RandomRule(); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
注意:官方文档明确给出了警告,这个自定义配置类不能放在@ComponentScan所扫描的当前包下以及子包下,否则我们自定义的这个配置类就会被所有的Ribbon客户端所共享,达不到特殊化定制的目的了。当然如果想要全局的吧ribbon的算法替换掉,就可以放到@ComponentScan扫描的范围,下面我们只对provider服务设置随机算法:
- 修改主启动类:
添加@RibbonClient注解
@SpringBootApplication@EnableDiscoveryClient@RibbonClient(name = "provider", configuration = RibbonLoadBalancedConfig.class)public class ConsulConsumerApplication { public static void main(String[] args) { SpringApplication.run(ConsulConsumerApplication.class, args); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
下面再次请求就可以看出,已经不是轮训算法了。
五、自定义Ribbon的负载均衡算法
如果Ribbon自带的算法不能满足我们的需求,我们也可以自定义负载算法,上面我们了解到了,所有的规则都实现于 IRule 接口和 继承AbstractLoadBalancerRule 抽象模板,既然我们要自定义也要符合它的规则,下面我们创建自定义类继承 AbstractLoadBalancerRule模板。
@Slf4jpublic class MyLoadBalanced extends AbstractLoadBalancerRule { private AtomicInteger atomicInteger = new AtomicInteger(0); @Override public void initWithNiwsConfig(IClientConfig iClientConfig) { } @Override public Server choose(Object key) { return this.choose(this.getLoadBalancer(), key); } private Server choose(ILoadBalancer lb, Object key) { if (lb == null) { log.warn("no load balancer"); return null; } else { List<Server> reachableServers = lb.getReachableServers(); int count = getAndIncrement(); int index = count % reachableServers.size(); Server server = reachableServers.get(index); log.info("访问次数:{} ,当前调用服务ip:{} , port: {} ", count, server.getHost(), server.getPort()); return server; } } public final int getAndIncrement() { int current; int next; do { current = this.atomicInteger.get(); next = current >= Integer.MAX_VALUE ? 0 : current + 1; } while (!this.atomicInteger.compareAndSet(current, next)); return next; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
上面的程序,我们也是简单实现了一个轮训的效果,以此来作为演示,大家可以根据需求编写自己的算法。
下面将我们的算法替换掉默认的轮训:
public class RibbonLoadBalancedConfig { @Bean public IRule myRule() { //定义为随机算法// return new RandomRule(); return new MyLoadBalanced(); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
最后在主启动类中声明:
@SpringBootApplication@EnableDiscoveryClient@RibbonClient(name = "provider", configuration = RibbonLoadBalancedConfig.class)public class ConsulConsumerApplication { public static void main(String[] args) { SpringApplication.run(ConsulConsumerApplication.class, args); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
再次请求,也是轮训的效果,不过看下打印的日志,走的已经是我们自定义的算法了:
喜欢的小伙伴可以关注我的个人微信公众号,获取更多学习资料!