负载均衡-轮询-两种简易实现

1、描述

下游可用的服务器目前有5个(node),设计一个方法,方法没有任何参数,采用轮询的方式返回其中一个node;

2、使用环形链表

每次取下一个node即可。注意:需要保证线程安全!

// 节点定义
@Data
class Node {Node next;String name;String ip;}
// 环形状node集合
class LoadBalanceCycle {private Node head;private Node nextNode;/*** 添加节点*/public synchronized void addNode(String name, String ip) {Node newNode = new Node();newNode.name = name;newNode.ip = ip;if (head == null) {head = newNode;head.next = head;} else {Node temp = head;while (temp.next != head) {temp = temp.next;}temp.next = newNode;newNode.next = head;}}/*** 获取下一个节点*/public synchronized Node getNextNode() {if (nextNode == null) {nextNode = head;} else {nextNode = nextNode.next;}return nextNode;}}
// 测试验证
public static void main(String[] args) {LoadBalanceCycle loadBalanceCycle = new LoadBalanceCycle();// 初始化三个节点的loadBalanceCycle.addNode("node1", "192.168.0.1");loadBalanceCycle.addNode("node2", "192.168.0.2");loadBalanceCycle.addNode("node3", "192.168.0.3");AtomicInteger n1Count = new AtomicInteger();AtomicInteger n2Count = new AtomicInteger();AtomicInteger n3Count = new AtomicInteger();CountDownLatch latch = new CountDownLatch(30);// 多线程,返回负载均衡中的节点for (int i = 0; i < 3; i++) {new Thread(() -> {int j = 10;while (j > 0) {try {String name = loadBalanceCycle.getNextNode().getName();System.out.println(Thread.currentThread().getName() + " " + name);if ("node1".equals(name)) {n1Count.incrementAndGet();}if ("node2".equals(name)) {n2Count.incrementAndGet();}if ("node3".equals(name)) {n3Count.incrementAndGet();}j--;} finally {latch.countDown();}}}).start();}try {latch.await();} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("==============================负载均衡调用结果===================================");System.out.println("node1 被调用的次数: " + n1Count.get());System.out.println("node2 被调用的次数: " + n2Count.get());System.out.println("node3 被调用的次数: " + n3Count.get());}}

3、使用AtomicLong

long 类型的最大值?

这个值是 2^63 - 1,即 9223372036854775807,是 long 类型能表示的最大正数值。

是多少亿?

Long.MAX_VALUE 大约是 92233.72 亿。(如果你的请求次数即【负载均衡调用次数】会超过这个值,那么或许下面的例子会存在问题)

@Data
class Node2 {String name;String ip;public Node2(String node1, String s) {this.name = node1;this.ip = s;}
}

/*** 基于AtomicLong实现的一个结构*/
class LoadBalanceByAtomic {final List<Node2> nodeList = new ArrayList<>();AtomicLong mark = new AtomicLong(0);public void add(Node2 node) {synchronized (nodeList) {nodeList.add(node);}}public Node2 getNext() {long andIncrement = mark.getAndIncrement();return nodeList.get((int) (andIncrement % nodeList.size()));}}

测试代码

public static void main(String[] args) {LoadBalanceByAtomic loadBalanceByAtomic = new LoadBalanceByAtomic();// 初始化三个节点的loadBalanceByAtomic.add(new Node2("node1", "192.168.0.1"));loadBalanceByAtomic.add(new Node2("node2", "192.168.0.2"));loadBalanceByAtomic.add(new Node2("node3", "192.168.0.3"));AtomicInteger n1Count = new AtomicInteger();AtomicInteger n2Count = new AtomicInteger();AtomicInteger n3Count = new AtomicInteger();CountDownLatch latch = new CountDownLatch(30);// 多线程,返回负载均衡中的节点for (int i = 0; i < 3; i++) {new Thread(() -> {int j = 10;while (j > 0) {try {String name = loadBalanceByAtomic.getNext().getName();System.out.println(Thread.currentThread().getName() + " " + name);if ("node1".equals(name)) {n1Count.incrementAndGet();}if ("node2".equals(name)) {n2Count.incrementAndGet();}if ("node3".equals(name)) {n3Count.incrementAndGet();}j--;} finally {latch.countDown();}}}).start();}try {latch.await();} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("==============================负载均衡调用结果===================================");System.out.println("node1 被调用的次数: " + n1Count.get());System.out.println("node2 被调用的次数: " + n2Count.get());System.out.println("node3 被调用的次数: " + n3Count.get());}

结果:

问题

在大并发下使用 AtomicInteger ,相比于使用锁,Atomic会不断自旋重试,在线程比较多的场景下会造成cpu资源消耗高么?

在大并发场景下,使用 AtomicInteger 相比使用显式的锁(如 synchronized)确实有一些区别和考虑因素。

  1. 自旋和CPU消耗:

    • AtomicInteger 使用了一些技术(如 CAS,即比较并交换),它会尝试更新值直到成功。如果更新失败,它会自旋(重试)。在低并发情况下,自旋几乎没有额外开销,因为更新通常很快成功。
    • 在高并发情况下,自旋可能会导致一定的CPU资源消耗。如果有大量线程竞争同一个 AtomicInteger,并且更新操作不断失败,导致频繁自旋,会增加CPU负载。
  2. 性能比较:

    • AtomicInteger 在低到中等并发情况下通常比显式锁(如 synchronized)效率更高,因为它利用了硬件级别的原子操作,避免了线程阻塞和切换的开销。
    • 在非常高的并发情况下,性能可能会受到影响,因为自旋操作可能会消耗大量CPU资源,而且不能保证性能和可扩展性的优势。
  3. 选择合适的工具:

    • 在选择 AtomicInteger 还是显式锁时,需要考虑具体的应用场景和并发需求。通常情况下,AtomicInteger 更适合用于简单的计数或者状态标记等,而显式锁更适合于需要复杂的条件同步和数据操作的场景。

综上所述,虽然 AtomicInteger 在大多数情况下性能优于显式锁,但在极端高并发情况下,它可能会因为自旋而增加CPU消耗。因此,在高并发场景下,需要进行性能测试和基准测试,以便选择最适合的并发控制方法。

二者比较

锁跟Atomic-CAS在大并发场景下的效率比较-CSDN博客

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

子数组问题

目录 最大子数组和 环形子数组的最大和 乘积最大子数组 乘数为正数的最长子数组长度 等差数列划分 最长湍流子数组 单词拆分 环绕字符串中唯一的子字符串 声明&#xff1a;接下来主要使用动态规划来解决问题&#xff01;&#xff01;&#xff01; 最大子数组和 题目 …

C 语言指针进阶

1.0 指针的定义 指针是内存中一个最小单元的编号&#xff08;内存单元的编号称之为地址【地址就是指针指针就是地址】&#xff09;指针通常是用来存放内存地址的一个变量。本质上指针就是地址&#xff1a;口语上说的指针起始是指针变量&#xff0c;指针变量就是一个变量&#…

ROS2从入门到精通5-1:详解代价地图与costmap插件编写(以距离场ESDF为例)

目录 0 专栏介绍1 代价地图介绍1.1 基本概念1.2 代价定义 2 代价地图配置2.1 通用配置2.2 障碍层配置2.3 静态层配置2.4 膨胀层配置 3 代价地图插件案例3.1 构造地图插件类3.2 注册并导出插件3.3 编译与使用插件 0 专栏介绍 本专栏旨在通过对ROS2的系统学习&#xff0c;掌握RO…

GIT使用_提交IDEA代码到GIT分支上

以下是本人常用的GIT提交与上传代码&#xff0c;请选择适配自己的方式&#xff0c;仅供参考。 第一步&#xff0c;一般来说&#xff0c;我们从GIT上拉下来项目分支代码后&#xff0c;做些修改什么的&#xff0c;相关的代码都会变色。当然我们提交的部分就是我们修改的部分。有的…

算法思想总结:字符串

一、最长公共前缀 . - 力扣&#xff08;LeetCode&#xff09; 思路1&#xff1a;两两比较 时间复杂度mn 实现findcomon返回两两比较后的公共前缀 class Solution { public:string longestCommonPrefix(vector<string>& strs) {//两两比较 string retstrs[0];size…

Flutter实现局部刷新的几种方式

目录 前言 1.局部刷新的重要性 1.概念 2.重要性 2.局部刷新实现的几种方式 1.使用setState方法进行局部刷新 2.使用StatefulWidget和InheritedWidget局部刷新UI 3.ValueNotifier和ValueListenableBuilder 4.StreamBuilder 5.Provider 6.GetX 7.使用GlobalKey 前言 …

实战:功能强大齐全BBS论坛项目Echo简介

项目简介 Echo 是一套前后端不分离的开源社区系统&#xff0c;基于目前主流 Java Web 技术栈&#xff08;SpringBoot MyBatis MySQL Redis Kafka Elasticsearch Spring Security ...&#xff09;&#xff0c;并提供详细的开发文档和配套教程。包含帖子、评论、私信、系…

HarmonyOS NEXT:一次开发,多端部署

寄语 这几年特别火的uni-app实现了“一次开发&#xff0c;多端使用”&#xff0c;它这个端指的是ios、安卓、各种小程序这些&#xff0c;而HarmonyOS NEXT也提出了“一次开发&#xff0c;多端部署”&#xff0c;而它这个端指的是终端设备&#xff0c;也就是我们的手机、平板、电…

记录些MySQL题集(2)

MySQL 不使用limit的分页查询 limit问题&#xff1a;limit&#xff0c;offset递增问题。随着offset的增加&#xff0c;条数不变&#xff0c;耗时却增加了。 limit 0,10 耗时1ms limit 300000,10 耗时152ms limit 600000,10 耗时312ms 毫秒级别可能没感觉。假…

gitlab 搭建使用

1. 硬件要求 ##CPU 4 核心500用户 8 核心1000用户 ##内存 4 G内存500用户 8 G内存1000用户 2. 下载 链接 3. 安装依赖 yum -y install curl openssh-server postfix wget 4. 安装gitlab组件 yum -y localinstall gitlab-ce-15.9.3-ce.0.el7.x86_64.rpm 5. 修改配置文…

使用Python的Turtle模块绘制小猪佩奇

引言 在编程学习中&#xff0c;Turtle是一个非常有趣且实用的模块&#xff0c;尤其适合初学者。它允许用户通过控制一个可以在屏幕上移动的小海龟来绘制图形&#xff0c;从而直观地理解坐标、角度和循环等概念。本篇博客将介绍如何使用Python的Turtle模块来绘制一个可爱的卡通…

PostgreSQL日志文件配置,记录所有操作记录

为了更详细的记录PostgreSQL 的运行日志&#xff0c;我们一般需要修改PostgreSQL 默认的配置文件&#xff0c;这里整理了一些常用的配置 修改配置文件 打开 PostgreSQL 配置文件 postgresql.conf。该文件通常位于 PostgreSQL 安装目录下的 data 文件夹中。 找到并修改以下配…

IDEA实现热部署

什么是热部署&#xff1f; 热部署&#xff08;Hot Deployment&#xff09;是指在应用程序运行过程中&#xff0c;无需停止整个应用程序或重新启动服务器&#xff0c;就能够部署新的代码、资源或配置文件&#xff0c;使其立即生效。这种部署方式有助于提高开发效率和系统的可用性…

【边缘计算网关教程】4.西门子PPI协议对接

前景回顾&#xff1a;【边缘计算网关教程】3.创建第二个流程-CSDN博客 目录 1. 硬件连接 2. PLC串口参数 2.1. 打开STEP7软件 2.2. 查看通信参数 3. 网关设置 3.1. PLC连接设置 3.2. 数据点位设置 3.3. 测试 西门子 PPI 协议 适配PLC&#xff1a;S7-200 西门子S7-200 PLC…

【RHCE】综合实验0710综合实验

题目&#xff1a; 主服务器192.168.244.130 防火墙允许服务的放行&#xff1a; selinux放行 [rootlocalhost ~]# ll -Z /nfs/rhce 总用量 4 -rw-r--r--. 1 root root unconfined_u:object_r:default_t:s0 8 7月 10 16:52 index.html -rw-r--r--. 1 nobody nobody system_…

推荐一款uniapp拖动验证码插件

插件地址&#xff1a;易盾验证码 - DCloud 插件市场 具体使用方式访问插件地址自行获取

企业网三层架构

企业网三层架构&#xff1a;是一种层次化模型设计&#xff0c;旨在将复杂的网络设计分成三个层次&#xff0c;每个层次都着重于某些特定的功能&#xff0c;以提高效率和稳定性。 企业网三层架构层次&#xff1a; 接入层&#xff1a;使终端设备接入到网络中来&#xff0c;提供…

什么叫图像的双边滤波,并附利用OpenCV和MATLB实现双边滤波的代码

双边滤波&#xff08;Bilateral Filtering&#xff09;是一种在图像处理中常用的非线性滤波技术&#xff0c;主要用于去噪和保边。它在空间域和像素值域上同时进行加权&#xff0c;既考虑了像素之间的空间距离&#xff0c;也考虑了像素值之间的相似度&#xff0c;从而能够有效地…

西安明德理工学院师生莅临泰迪智能科技开展参观见习活动

为进一步深化校企合作&#xff0c;落实高校应用型人才培养。7月8日&#xff0c;西安明德理工学院与广东泰迪智能科技股份有限公司联合开展学生企业见习活动。西安明德理工学院金融产业学院副院长刘敏、金融学专业负责人张莉萍、金融学专业教师曹艳飞、赵浚妤、泰迪智能科技董事…

板级调试小助手(2)ZYNQ自定义IP核构建属于自己的DDS外设

一、前言 在上期文章中讲述了小助手的系统结构和原理。在PYNQ的框架开发中&#xff0c;我们一般可以将PL端当做PS端的一个外设&#xff0c;通过读写寄存器的方式来操作外设的功能&#xff0c;就类似于在开发ARM和DSP中操作外设一样&#xff0c;不同时的是&#xff0c;我们可以通…