zoukankan      html  css  js  c++  java
  • Ribbon负载均衡服务调用

    一、简介

    ​ 1、Ribbon 简介

    ​ Spring Cloud Ribbon 是基于Netflix Ribbon 实现的一套客户端负载均衡的工具。主要功能是提供客户端的软件负载均衡算法和服务调用。Ribbon 客户端组件提供一系列完善的配置项如连接超时、重试等。简单的说就是在配置文件中列出Load Balancer 后面所有的机器,Ribbon 会自动的帮助你基于某种规则(如简单轮询,随机连接等)去连接这些机器。我们很容易使用Ribbon实现自定义的负载均衡算法(负载均衡+服务调用)。

    ​ github 地址 https://github.com/Netflix/ribbon ,现在项目处于维护状态中。

    2、LB负载均衡(Load Balance)

    • 将用户的请求平摊到多个服务上,从而达到系统的高可用(HA)。常见的负载均衡软件有Nginx、LVS等。
    • Ribbon 本地负载均衡与Nginx 服务端负载均衡的区别
      • Nginx 是服务器负载均衡,客户端所有请求都会交给Nginx,然后由Nginx实现转发请求。即负载均衡由服务端实现。
      • Ribbon本地负载均衡在调用服务接口的时候,会在注册中心上获取注册信息服务列表之后缓存到JVM本地,从而在本地实现RPC远程服务调用技术。Ribbon属于进程内负载均衡(将LB逻辑集成到消费方,消费方从服务注册中心获知有那些地址可用,然后自己再从这些地址中选出一个合适的服务器)。

    3、工作步骤

    • 选择Eureka Server,优先选择同一个区域内负载较少的Server;

    • 根据用户指定的策略(轮询、随机、根据响应时间加权),在server取到的服务注册列表中选择一个地址。

    二、Ribbon负载均衡演示

    1、在和Eureka集成的时候,只需要引入最新的Eureka的版本即可,因为Eureka以及集成了Ribbon。

    <!-- eureka-client -->
    <dependency>
    	<groupId>org.springframework.cloud</groupId>
    	<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    

    ​ 然后结合RestTemplate使用即可。

    三、Ribbon核心组件IRule

    1、简介

    ​ 根据特定算法从服务列表中选取一个要访问的服务。接口类图如下:

    • com.netflix.loadbalacer.RoudRobinRule:轮询;
    • com.netflix.loadbalacer.RandomRule:随机;
    • com.netflix.loadbalacer.RetryRule:先按照RoudRobinRule的策略获取服务,如果获取服务失败则在指定时间内会进行重试,获取可用的服务。
    • WeightedResponseRule:对RoudRobinRule的扩展,响应速度越快的实例选择权重越大,越容易被选择;
    • BestAvailableRule:会优过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务。
    • AvailabilityFilteringRule:先过滤掉故障实例,再选择并发较小的实例;
    • ZoneAvoidanceRule:默认规则,复合判断server所在区域的性能和server的可用性选择服务器。

    2、负载规则配置

    • 自定义的规则配置不能放在 @ConponentScan 能扫描到的包及其子包,否则定义的配置类就会被所有的Ribbon客户端使用,起不到特殊化定制的效果。
    • 自定义配置类的编写
    @SpringBootConfiguration
    public class MySelfRule {
    
        @Bean
        public IRule myRule(){
            return new RandomRule(); //规则定义为随机
        }
    }
    
    • 在主启动类上加上注解 @RibbonClient(value = "CLOUD-PAYMENT-SERVICE",configuration = MySelfRule.class)。

    四、Ribbon负载均衡算法

    1、轮询原理

    ​ rest接口第几次请求数 % 服务器集群总数量 = 实际调用服务器位置下标,每次服务重启后rest从1开始重新计数。

    2、轮询源码

    public Server choose(ILoadBalancer lb, Object key) {
        if (lb == null) {
            log.warn("no load balancer");
            return null;
        } else {
            Server server = null;
            int count = 0;
    
            while (true) {
                if (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) {
                        int nextServerIndex = this.incrementAndGetModulo(serverCount);
                        server = (Server) allServers.get(nextServerIndex);
                        if (server == null) {
                            Thread.yield();
                        } else {
                            if (server.isAlive() && server.isReadyToServe()) {
                                return server;
                            }
    
                            server = null;
                        }
                        continue;
                    }
    
                    log.warn("No up servers available from load balancer: " + lb);
                    return null;
                }
    
                if (count >= 10) {
                    log.warn("No available alive servers after 10 tries from load balancer: " + lb);
                }
    
                return server;
            }
        }
    }
    

    3、实现一个负载均衡算法(JUC+自旋锁)

    • 定义一个接口;
    public interface LoadBalancer {
    
        /**
         *  获取执行当前请求的服务器
         * @param serviceInstances
         * @return
         */
        ServiceInstance instances(List<ServiceInstance> serviceInstances);
    }
    
    • 实现接口,需要添加一个 @Component;
    @Component //让容器能够扫描到
    public class MyLB implements LoadBalancer {
        //原子类,初始值0
        private AtomicInteger atomicInteger = new AtomicInteger(0);
    
        /**
         * 获得第几次访问的数
         * @return
         */
        public final int getAndIncrement(){
            int current;
            int next;
            //自旋锁
            do {
                current = this.atomicInteger.get();
                // 获取下一个请求次数,整型最大为2147483647
                next = current >= 2147483647 ? 0 : current + 1;
            }while (!this.atomicInteger.compareAndSet(current,next));
            return next;
        }
        public ServiceInstance instances(List<ServiceInstance> serviceInstances) {
            //访问到次数与集群服务器数量取模,获得该由哪个服务器执行该请求
            int index = getAndIncrement() % serviceInstances.size();
            return serviceInstances.get(index);
        }
    }
    
    • 服务调用
    @Resource
    private RestTemplate restTemplate;
    @Resource
    private LoadBalancer loadBalancer;//引入自定义的负载均衡算法
    @Resource
    private DiscoveryClient discoveryClient;
    @GetMapping("/consumer/payment/lb")
    public String getPaymentLB(){
        //获取服务集合
        List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
        if (instances == null || instances.size()<= 0){
            return null;
        }
        //获取执行当前请求的服务
        ServiceInstance serviceInstance = loadBalancer.instances(instances);
        URI uri = serviceInstance.getUri();
        return restTemplate.getForObject(uri+"/payment/lb",String.class);
    }
    

    案例代码地址:https://github.com/xhanglog/springcloud-learning

  • 相关阅读:
    手机游戏怎么独占世界手游鳌头
    游戏开发商是如何做到每日进帐410万美元的?
    [手游新项目历程]-48-svn分支开发与主干合并
    三国武将所带兵种
    Supercell:靠两款手游如何做到30亿美金市值?
    理财投资这需要知道的50个真相
    [手游新项目历程]-49-性能分析
    [手游新项目历程]-50-Mysql的大字段问题(数据库执行错误: Error=1118, Reason=Row size too large (> 8126))
    三国杀
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
  • 原文地址:https://www.cnblogs.com/Mhang/p/12555540.html
Copyright © 2011-2022 走看看