微服务 springcloud Ribbon客户端负载均衡 青旅半醒 2023-01-11 13:07 102阅读 0赞 ### 微服务 springcloud Ribbon客户端负载均衡 ### * 微服务 springcloud Ribbon客户端负载均衡 * * 一、概述 * * 1、Ribbon是什么 * 2、Ribbon作用 * 3、Ribbon与nginx负载均衡原理 * 4、Ribbon工作模式 * 5、引入依赖坐标 * 二、Ribbon核心组件IRule * * 1、IRule:根据特定算法从服务列表中选取一个要访问的服务 * 三、Ribbon修改访问策略 * * 1、Ribbon配置注意事项 * 2、新建配置类 * 3、指定配置 * 三、Ribbon负载均衡算法 * * 1、原理 * 2、RoundRobinRule源码 * 3、重写负载均衡算法 # 微服务 springcloud Ribbon客户端负载均衡 # ## 一、概述 ## ### 1、Ribbon是什么 ### SpringCloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡组件。 简单的说,Ribbon是Netflix发布的开源项目,主要功能是提供客户端负载均衡算法和服务调用的组件。 Ribbon客户端组件提供一系列完善的配置如连接超时,重试等简单地说就是在配置文件中列出LoadBalancer后面所以的机器,Ribbon会自动的帮助你基于某种规则(如简单轮训,随机连接等)去连接这些机器。而且我们很容易使用Ribbon实现自定义的负载均衡算法。 在实际使用中,Ribbon实质就是在客户端实现负载均衡,通过RestTemplate实现远程调用。 官网地址:[https://github.com/Netflix/ribbon/wiki/Getting-Started][https_github.com_Netflix_ribbon_wiki_Getting-Started] 目前进入维护模式,未来SpringCloud LoadBalancer替代。 ### 2、Ribbon作用 ### ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzM3NTgzNjU1_size_16_color_FFFFFF_t_70]Ribbon=负载均衡+RestTemplate调用 ### 3、Ribbon与nginx负载均衡原理 ### nginx负载原理 ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzM3NTgzNjU1_size_16_color_FFFFFF_t_70 1]Ribbon负载原理 ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzM3NTgzNjU1_size_16_color_FFFFFF_t_70 2] ### 4、Ribbon工作模式 ### ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzM3NTgzNjU1_size_16_color_FFFFFF_t_70 3] ### 5、引入依赖坐标 ### ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzM3NTgzNjU1_size_16_color_FFFFFF_t_70 4] **新版的Eureka已经整合了Ribbon** ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzM3NTgzNjU1_size_16_color_FFFFFF_t_70 5] ## 二、Ribbon核心组件IRule ## ### 1、IRule:根据特定算法从服务列表中选取一个要访问的服务 ### ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzM3NTgzNjU1_size_16_color_FFFFFF_t_70 6] ## 三、Ribbon修改访问策略 ## Ribbon默认轮训机制,那么如何修改默认访问机制?由于Ribbon是客户端负载所以需要配置客户端。 ### 1、Ribbon配置注意事项 ### 官方文档明确给出警告: 这个自定义配置类不能放在@ComponentScan所扫描的当前包下及其子包下。 否则我们自定义的这个配置类就会被所以的Ribbon客户端所共享,达不到特殊化定制的目的。 注意:在springboot中@ComponentScan可以扫描到的包默认是主程序Application.java类所在包及其子包。 ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzM3NTgzNjU1_size_16_color_FFFFFF_t_70 7] ### 2、新建配置类 ### git地址:[https://github.com/zrj-coder/cloudboot3][https_github.com_zrj-coder_cloudboot3] ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzM3NTgzNjU1_size_16_color_FFFFFF_t_70 8] /** * 配置ribbon策略 * 注意:不要放在主程序所在宝及其子包等能被ComponentScan扫描到的包下面 * * @author zrj * @date 2021/1/23 * @since V1.0 **/ @Configuration public class MySelfRule { /** * 定义为随机 */ @Bean public IRule myRule() { return new RandomRule(); } } ### 3、指定配置 ### /** * 订单主程序 * 指定Ribbon配置类 * * @author zrj * @date 2021/1/23 * @since V1.0 **/ @EnableEurekaClient @SpringBootApplication @RibbonClient(name = "CLOUD-PAYMENT-SERVICE", configuration = MySelfRule.class) public class OrderApplication { public static void main(String[] args) { SpringApplication.run( OrderApplication.class, args ); } } ## 三、Ribbon负载均衡算法 ## ### 1、原理 ### 负载均衡算法:rest接口第几次请求数 % 服务器集群总数量 =实际调用服务器位置小标。 每次服务器重启后rest接口技术从1开始。 ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzM3NTgzNjU1_size_16_color_FFFFFF_t_70 9] ### 2、RoundRobinRule源码 ### idea生成的IRule的UML类图,具体方式参考:[idea Diagrams生成UML类图][idea Diagrams_UML] ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzM3NTgzNjU1_size_16_color_FFFFFF_t_70 10]负载均衡算法源码分析 /** * 负载均衡调用算法 * The most well known and basic load balancing strategy, i.e. Round Robin Rule. * * @author stonse * @author Nikos Michalakis <nikos@netflix.com> * */ public class RoundRobinRule extends AbstractLoadBalancerRule { private AtomicInteger nextServerCyclicCounter; // 服务器调用次数,默认是0 private static final boolean AVAILABLE_ONLY_SERVERS = true; private static final boolean ALL_SERVERS = false; private static Logger log = LoggerFactory.getLogger(RoundRobinRule.class); public RoundRobinRule() { // 服务器调用次数,默认是0 nextServerCyclicCounter = new AtomicInteger(0); } public RoundRobinRule(ILoadBalancer lb) { this(); setLoadBalancer(lb); } public Server choose(ILoadBalancer lb, Object key) { if (lb == null) { log.warn("no load balancer"); return null; } Server server = null; int count = 0; while (server == null && count++ < 10) { List<Server> reachableServers = lb.getReachableServers(); // 所有服务集合 List<Server> allServers = lb.getAllServers(); // 缓存本地服务器数量 int upCount = reachableServers.size(); // 获取当前服务器数量 int serverCount = allServers.size(); if ((upCount == 0) || (serverCount == 0)) { log.warn("No up servers available from load balancer: " + lb); return null; } // 负载均衡具体调用算法 int nextServerIndex = incrementAndGetModulo(serverCount); server = allServers.get(nextServerIndex); if (server == null) { /* Transient. */ Thread.yield(); continue; } if (server.isAlive() && (server.isReadyToServe())) { return (server); } // Next. server = null; } if (count >= 10) { log.warn("No available alive servers after 10 tries from load balancer: " + lb); } return server; } /** * 负载均衡具体调用算法 * Inspired by the implementation of {@link AtomicInteger#incrementAndGet()}. * * @param modulo The modulo to bound the value of the counter. * 调用次数 * * @return The next value. * 下一次调用服务器下标 */ private int incrementAndGetModulo(int modulo) { for (;;) { // 获得当前调用算法 int current = nextServerCyclicCounter.get(); // 当前调用次数加1 取余 服务器数量 int next = (current + 1) % modulo; // CAS 自旋 返回 if (nextServerCyclicCounter.compareAndSet(current, next)) return next; } } @Override public Server choose(Object key) { return choose(getLoadBalancer(), key); } @Override public void initWithNiwsConfig(IClientConfig clientConfig) { } } ### 3、重写负载均衡算法 ### /** * 自定义负载均衡算法 * * @author zrj * @date 2021/1/31 * @since V1.0 **/ public interface LoadBalancer { /** * 服务实例 * * @param serviceInstances * @return */ ServiceInstance instances(List<ServiceInstance> serviceInstances); } /** * 自定义负载均衡算法 * * @author zrj * @date 2021/1/31 * @since V1.0 **/ @Component public class NewLoadBalancer implements LoadBalancer { private AtomicInteger atomicInteger = new AtomicInteger( 0 ); /** * 自定义负载均衡算法 * * @return */ 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 )); System.out.println( "*****第几次访问,次数next: " + next ); return next; } /** * 负载均衡算法:rest接口第几次请求数 % 服务器集群总数量 = 实际调用服务器位置下标 * 每次服务重启动后rest接口计数从1开始。 * * @param serviceInstances * @return */ @Override public ServiceInstance instances(List<ServiceInstance> serviceInstances) { int index = getAndIncrement() % serviceInstances.size(); return serviceInstances.get( index ); } } [https_github.com_Netflix_ribbon_wiki_Getting-Started]: https://github.com/Netflix/ribbon/wiki/Getting-Started [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzM3NTgzNjU1_size_16_color_FFFFFF_t_70]: /images/20221119/e9fcbdd77c554da7b54d7999592c291d.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzM3NTgzNjU1_size_16_color_FFFFFF_t_70 1]: /images/20221119/8722cc98811e46bda62c0cbff1791a7c.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzM3NTgzNjU1_size_16_color_FFFFFF_t_70 2]: /images/20221119/57aae0b8f67849c1aac28f5ea18f0da5.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzM3NTgzNjU1_size_16_color_FFFFFF_t_70 3]: /images/20221119/af48ca7423ea40fdac7c95c0c6a3857c.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzM3NTgzNjU1_size_16_color_FFFFFF_t_70 4]: /images/20221119/ab56fc5470954e22b7fb8019fe329145.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzM3NTgzNjU1_size_16_color_FFFFFF_t_70 5]: /images/20221119/73def524926346bc8dfeead2ab126c3b.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzM3NTgzNjU1_size_16_color_FFFFFF_t_70 6]: /images/20221119/f432aed7eb944be1bf9d40c30bd51414.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzM3NTgzNjU1_size_16_color_FFFFFF_t_70 7]: /images/20221119/2324c09bbf2a497b8daa1b97ec62cd35.png [https_github.com_zrj-coder_cloudboot3]: https://github.com/zrj-coder/cloudboot3 [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzM3NTgzNjU1_size_16_color_FFFFFF_t_70 8]: /images/20221119/d89edc6752e04af4b214f71eb50213c2.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzM3NTgzNjU1_size_16_color_FFFFFF_t_70 9]: /images/20221119/466e32d2cd0e413ca824d7143b9d16f0.png [idea Diagrams_UML]: https://blog.csdn.net/m0_37583655/article/details/113406668 [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzM3NTgzNjU1_size_16_color_FFFFFF_t_70 10]: /images/20221119/ed77b2cf8240463fac22b22d67a2117c.png
还没有评论,来说两句吧...