当前位置: 首页 > news >正文

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

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博客

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 网络安全-网络安全及其防护措施6
  • 智能合约中授权与转账的分离可行性分析
  • 岭回归(Ridge Regression)
  • redis其他类型和配置文件
  • Mybatis 之批量处理
  • OpenResty使用Lua笔记
  • 题解|2023暑期杭电多校02
  • 关键路径-matlab
  • 【BUG】已解决:IndexError: list index out of range
  • 今日科技圈最新时事新闻(2024年7月12日
  • C++——类和对象(下)
  • k8s入门:从安装到实际应用
  • 【Linux杂货铺】期末总结篇3:用户账户管理命令 | 组账户管理命令
  • redis-缓存三剑客
  • FreeRTOS的中断管理、临界资源保护、任务调度
  • Angular 响应式表单之下拉框
  • canvas 绘制双线技巧
  • co.js - 让异步代码同步化
  • express如何解决request entity too large问题
  • HomeBrew常规使用教程
  • Intervention/image 图片处理扩展包的安装和使用
  • java架构面试锦集:开源框架+并发+数据结构+大企必备面试题
  • Laravel核心解读--Facades
  • Markdown 语法简单说明
  • nginx(二):进阶配置介绍--rewrite用法,压缩,https虚拟主机等
  • Node + FFmpeg 实现Canvas动画导出视频
  • React-Native - 收藏集 - 掘金
  • vagrant 添加本地 box 安装 laravel homestead
  • 对超线程几个不同角度的解释
  • 和 || 运算
  • 基于webpack 的 vue 多页架构
  • 极限编程 (Extreme Programming) - 发布计划 (Release Planning)
  • 开源中国专访:Chameleon原理首发,其它跨多端统一框架都是假的?
  • 力扣(LeetCode)21
  • 手机app有了短信验证码还有没必要有图片验证码?
  • 吐槽Javascript系列二:数组中的splice和slice方法
  • 我这样减少了26.5M Java内存!
  • 小程序滚动组件,左边导航栏与右边内容联动效果实现
  • 小而合理的前端理论:rscss和rsjs
  • mysql面试题分组并合并列
  • 长三角G60科创走廊智能驾驶产业联盟揭牌成立,近80家企业助力智能驾驶行业发展 ...
  • 直播平台建设千万不要忘记流媒体服务器的存在 ...
  • #如何使用 Qt 5.6 在 Android 上启用 NFC
  • (16)UiBot:智能化软件机器人(以头歌抓取课程数据为例)
  • (2)MFC+openGL单文档框架glFrame
  • (4)事件处理——(7)简单事件(Simple events)
  • (Matlab)使用竞争神经网络实现数据聚类
  • (补充):java各种进制、原码、反码、补码和文本、图像、音频在计算机中的存储方式
  • (附源码)ssm考试题库管理系统 毕业设计 069043
  • (经验分享)作为一名普通本科计算机专业学生,我大学四年到底走了多少弯路
  • (一)Java算法:二分查找
  • (一)pytest自动化测试框架之生成测试报告(mac系统)
  • (转)ORM
  • (转)程序员疫苗:代码注入
  • (转)拼包函数及网络封包的异常处理(含代码)