Ribbon 负载均衡服务调用

文章目录

      • 1 SpringCloud Load Balance
      • 2 总结:
      • 3 Ribbon工作流程:
      • 4 自定义Ribbon 负载均衡算法:
        • 4.1 iRule接口:
        • 4.2 Ribbon自带的负载均衡算法:
        • 4.3 负载均衡算法替代:
          • 4.3.1、在非启动类包及子包下创建配置类
          • 4.3.2、定义
          • 4.3.3、启动类增加RibbonClient注解
      • 5 Ribbon负载均衡算法
        • 5.1 轮询算法原理:
        • 5.2 轮询算法源码:
        • 5.3 手写负载均衡算法

想要学习完整SpringCloud架构可跳转: SpringCloud Alibaba微服务分布式架构

Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡的工具。

Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法和服务调用。

Ribbon客户端组件提供一系列完善的配置项如连接超时,重试等。

在配置文件中列出Load Balancer(简称LB)后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接等)去连接这些机器。

我们很容易使用Ribbon实现自定义的负载均衡算法。

1 SpringCloud Load Balance

LB负载均衡(Load Balance)是什么?

将用户的请求平摊的分配到多个服务上,从而达到系统的HA(高可用)。常见的负载均衡有软件Nginx,LVS,硬件F5等。

集中式LB Load Balance

即在服务的消费方和提供方之间使用独立的LB设施(可以是硬件,如F5,也可以是软件,1如nginx),由该设施负责把访问请求通过某种策略转发至服务的提供方;

Ribbon本地负载均衡客户端 VS Nginx服务端负载均衡区别

Nginx是服务器负载均衡,客户端所有请求都会交给Nginx,然后由Nginx实现转发请求。即负载均衡是由服务端实现的。

Ribbon本地负载均衡,在调用微服务接口时候,会在注册中心上获取注册信息服务列表之后缓存到JVM本地,从而在本地实现RPC远程服务调用技术。

2 总结:

Ribbon其实就是一个软负载均衡的客户端组件,

他可以和其他所需请求的客户端结合使用,和eureka结合只是其中的一个实例。

在这里插入图片描述

3 Ribbon工作流程:

Ribbon在工作时分成两步:

  • 第—步先选择EurekaServer ,它优先选择在同一个区域内负载较少的server.
  • 第二步再根据用户指定的策略,在从server取到的服务注册列表中选择一个地址。
  • 其中Ribbon提供了多种策略:比如轮询、随机和根据响应时间加权。

4 自定义Ribbon 负载均衡算法:

4.1 iRule接口:

在这里插入图片描述

4.2 Ribbon自带的负载均衡算法:

com.netflix.loadbalancer.RoundRobinRule:

轮询

com.netflix.loadbalancer.RandomRule:

随机
com.netflix.loadbalancer.RetryRule:

先按照RoundRobinRule的策骼获取服务,如果获取服务失败则在指定时间内会进行重试,获取可用的服务

weightedResponseTimeRule:

对RoundRobinRule的扩展,响应速度越快的实例选择权重越大,越容易被选择

BestAvailableRuleo:

会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发是最小的服务

vailabilityFilteringRule:

先过滤掉故障实例,再选择并发较小的实例:

zoneAvoidanceRule

默认规则,复合判断server所在区域的性能和server的可用性选择服务器

官方文档明确给出了警告:

这个自定义配置类不能放在@ComponentScan所扫描的当前包下以及子包下,
否则我们自定义的这个配置类就会被所有的Ribbon客户端所共享,达不到特殊化定制的目的了。

4.3 负载均衡算法替代:

4.3.1、在非启动类包及子包下创建配置类

在这里插入图片描述

4.3.2、定义
/**
 * Myrule : Ribbon 自定义负载均衡算法配置类
 *
 * @author zyw
 * @create 2023/6/18
 */
@Configuration
public class Myrule {

    @Bean
    public IRule getIRule(){
        //定义为随机
        return new RandomRule();
    }
}
4.3.3、启动类增加RibbonClient注解

自定义需要指定的服务

/**
 * OderMain80 :
 *
 * @author zyw
 * @create 2023/6/16
 */
@SpringBootApplication
@EnableEurekaClient
@RibbonClient(name = "CLOULD-PAYMENT-SERVICE",configuration = Myrule.class)
@MapperScan("com.zyw.springcloud.dao")
public class OderMain80 {
    public static void main(String[] args) {
        SpringApplication.run(OderMain80.class,args);
    }
}

5 Ribbon负载均衡算法

5.1 轮询算法原理:

在这里插入图片描述

5.2 轮询算法源码:

public class RoundRobinRule extends AbstractLoadBalancerRule {
    
private AtomicInteger nextServerCyclicCounter;
    
public RoundRobinRule() {
   nextServerCyclicCounter = new AtomicInteger(0);
}


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;
    }

    //自旋锁
    //rest接口第几次请求数 % 服务器集群总数量 = 实际调用服务器位置下标,每次服务器重启后rest接口计数从1开始。
        private int incrementAndGetModulo(int modulo) {
        for (;;) {
            //获取当前值
            int current = nextServerCyclicCounter.get();
            //计算下次值
            int next = (current + 1) % modulo;
            //比较并交换
            if (nextServerCyclicCounter.compareAndSet(current, next))
                //得到当前下标值
                return next;
        }
    }
    
}

5.3 手写负载均衡算法

/**
 * LoadBalancer : 自定义负载均衡算法
 *
 * @author zyw
 * @create 2023/6/20
 */
public interface LoadBalancer {

    //收集Eurek上所有活着的服务总数
    ServiceInstance instances(List<ServiceInstance> serviceInstances);

}
/**
 * MyLB : 自定义负载均衡算法实现类
 *
 * @author zyw
 * @create 2023/6/20
 */
@Component
public class MyLB implements LoadBalancer {

    private AtomicInteger atomicInteger = new AtomicInteger(0);

    public final int getAndIncrement() {
        int currrnt;
        int next;
        do {
            currrnt = this.atomicInteger.get();
            //Integer.MAX_VALUE = 2147483647
            next = currrnt >= 2147483647 ? 0 : currrnt + 1;
            //自选锁,直到得到期望值
        } while (!this.atomicInteger.compareAndSet(currrnt, next));
        System.out.println("第" + 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);
    }
}

/**
 * OrderController : 订单系统控制层
 *
 * @author zyw
 * @create 2023/6/16
 */
@Slf4j
@RestController
@RequestMapping("consumer/orderController")
@Api(tags={"订单系统控制层"})
public class OrderController {

    @Resource
    private RestTemplate restTemplate;

    @Resource
    private DiscoveryClient discoveryClient;

    @Resource
    private LoadBalancer loadBalancer;

    @GetMapping("/lb")
    @ApiOperation(value = "获取负载服务的端口号", response = String.class)
    public String getPaymentBl(){
        List<ServiceInstance> serviceInstances = discoveryClient.getInstances("CLOULD-PAYMENT-SERVICE");
        if (serviceInstances == null || serviceInstances.size() <= 0){
            return null;
        }

        ServiceInstance serviceInstance = loadBalancer.instances(serviceInstances);

        URI uri = serviceInstance.getUri();
        return restTemplate.getForObject(uri+"paymentController/lb",String.class);
    }


}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/38479.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

网络虚拟化相关的Linux接口介绍

Linux拥有丰富的网络虚拟化功能&#xff0c;能被虚拟机&#xff0c;容器还有云网络使用。在这篇文章中&#xff0c;我会给出所有通用网络虚拟化接口的简要介绍。没有代码分析&#xff0c;只有简短的接口介绍和在Linux上的使用操作。这系列接口都可以使用ip link命令实现。 这篇…

Spring核心和设计思想(1)

1.Spring是什么&#xff1f; 我们通常说的Spring指的是Spring FrameWork&#xff08;Spring 框架&#xff09;&#xff0c;它是一个开源框架&#xff0c;有着活跃而庞大的社区&#xff0c;这就是它长久不衰的原因。Spring支持广泛的应用场景&#xff0c;它让Java企业级的应用程…

用html+javascript打造公文一键排版系统5:二级标题排版

公文中二级标题的一般以&#xff08;X&#xff09;标注&#xff08;其中X为由"一二三四五六七八九十"中的字符组成的字符串&#xff09;&#xff0c;用楷体字加粗。 首先我们要判断一段文字是否包含二级标题&#xff0c;最简单的方法 就是判断文字中的头一个字符是否…

【Linux】Linux下的项目自动化构建工具——make和makefile

❤️前言 大家好&#xff0c;好久不见&#xff01;今天小狮子为大家带来的文章是一篇关于Linux下的项目自动化构建工具——make和makefile的博客&#xff0c;希望能帮助到大家。 正文 当我们进行涉及多文件的工程开发时&#xff0c;我们需要对很多不同类型、不同功能&#xff…

基于R语言Meta分析与【文献计量分析、贝叶斯、机器学习等】多技术融合方法与应用

Meta分析是针对某一科研问题&#xff0c;根据明确的搜索策略、选择筛选文献标准、采用严格的评价方法&#xff0c;对来源不同的研究成果进行收集、合并及定量统计分析的方法&#xff0c;最早出现于“循证医学”&#xff0c;现已广泛应用于农林生态&#xff0c;资源环境等方面。…

XUbuntu22.04之解决蓝牙鼠标不停掉线问题(追凶过程)(一百八十五)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

Linux网络基础 — 网络层

目录 IP协议 IP协议报头格式 网段划分 特殊的IP地址 IP地址的数量限制 私有IP地址和公网IP地址 路由 补充 网络层 在复杂的环境中确定一个合适的路径。 IP协议 ip具有将数据从 主机A 跨网络送到 主机B 的能力。 主机: 配有IP地址&#xff0c;但是不进行路由控制的设备…

【Redis】Transaction(事务)

&#x1f3af;前言 Redis事务是一个组有多个Redis命令的集合&#xff0c;这些命令可以作为一个原子操作来执行。 Redis事务通常用于以下两种情况&#xff1a; 保证操作的原子性&#xff1a;在多个命令的执行过程中&#xff0c;如果有一个命令执行失败&#xff0c;整个事务都需…

挖矿记录+解决方案:利用GitLab组件对服务器进行挖矿导致CPU占用200%

文章目录 什么是云服务器挖矿?事件记录事件分析产生影响解决方案后期预防什么是云服务器挖矿? 云服务器挖矿是指利用云服务器从事赚取比特币的活动。比特币是一种虚拟数字货币,挖矿是将一段时间内比特币系统中发生的交易进行确认,并记录在区块链上形成新区块的过程。 用于…

【字节流】写数据的三种方式以及两个问题

字节流写数据 1.字节流写数据三种方式 void write(int b)&#xff1a;将指定的字节写入此文件输出流一次写一个字节数据 package com.bytestream; import java.io.FileOutputStream; import java.io.IOException; public class FileOutputStreamDemo02 {public static void ma…

融云「北极星」数据监控平台:数据可视通晓全局,精准分析定位问题

↑ 点击预约“融云北极星”直播↑ 点击预约“实时社区”直播 近期&#xff0c;融云“北极星”数据系统完成功能迭代&#xff0c;新模块“数据监控平台”正式“履新上任”。关注【融云全球互联网通信云】了解更多 点击图片查看更多详情 此前&#xff0c;“北极星”系统主要为客…

水声功率放大器的作用是什么

水声功率放大器是一种专门用于水声设备的高功率电子设备&#xff0c;主要用于提升水下信号的传输距离和保证语音清晰度。它的作用在水下通信、水下测量、海洋科学等领域都非常重要。 其主要作用有以下几个方面&#xff1a; 增强信号传输距离 水声信号在水中传播会受到各种因素的…

有哪些好用的远程传输大文件的软件

随着网络技术的日益进步和普及&#xff0c;大文件远程传输已经成为了人们生活和工作中必不可少的一部分。然而&#xff0c;在远程传输大文件的过程中&#xff0c;经常会遇到传输速度慢、容易受到干扰等问题&#xff0c;因此需要一款高效、稳定、安全的大文件远程传输软件来解决…

离线安装docker

目录 1、下载docker 安装包 2、上传docker 到服务器目录/opt/ 3、解压docker-19.03.9.tgz 4、解压的docker文件夹全部移动至/usr/bin目录 5、将docker注册为系统服务 6、重启生效 6.1、重新加载配置文件 6.2、启动Docker服务 6.3、查看启动状态 ​6.4、 设置docker为开…

伦敦金分析时切勿过分自信

伦敦金价格会呈趋势变动&#xff0c;这是投资者进行技术分析最根本、最核心的因素。根据物理学上的动力法则&#xff0c;趋势的运行会延续&#xff0c;直到有反转的现象产生为止。事实上&#xff0c;虽然伦敦金的价格不断上下波动&#xff0c;但终究是朝一定的方向前进的&#…

数组

数组&#xff1a; 数字组成的组&#xff0c;组里即可以&#xff0c;int类型&#xff0c;string&#xff0c;字符串&#xff0c;数组当中的数据类型&#xff0c;可以由用户自定义 同一种&#xff0c;也可以是不同的数据类型组成的元素集合 数组最大的作用&#xff0c;可以一次…

JVM系列(5)——类加载过程

一、类的生命周期 加载&#xff08;Loading&#xff09;、验证&#xff08;Verification&#xff09;、准备&#xff08;Preparation&#xff09;、解析&#xff08;Resolution&#xff09;、初始化&#xff08;Initialization&#xff09;、使用&#xff08;Using&#xff09…

在ICC/ICC2/FC中运行Calibre

1. which calibre找到calibre的安装目录 > which calibre > /eda/mentor/ixl_cal_version/bin/calibre 2. 在 /eda/mentor/ixl_cal_version目录下使用find ./* -name "icc_calibre.tcl",找到icc_calibre.tcl 3. 打开icc_calibre.tcl里面有不同工具(ICC2/FC/…

uniapp 封装公共方法(无需每个页面引用,直接调用)

封装方法: 1. 在根目录下建立common文件夹 创建com.js 2.在main.js中挂载(写在定义vue之后) import $com from /common/com.js Vue.prototype.$com $com 3.在com.js中按照以下格式定义方法 export default {//定义需要的方法 } 4.使用 click"$com.已经定义的方法名&q…