2台服务器负载均衡后synchronized_一篇有趣的负载均衡算法实现

负载平衡(Load balancing)是一种在多个计算机(网络、CPU、磁盘)之间均匀分配资源,以提高资源利用的技术。使用负载均衡可以最大化服务吞吐量,可能最小化响应时间,同时由于使用负载均衡时,会使用多个服务器节点代单点服务,也提高了服务的可用性。

负载均衡的实现可以软件可以硬件,硬件如大名鼎鼎的 F5 负载均衡设备,软件如 NGINX 中的负载均衡实现,又如 Springcloud Ribbon 组件中的负载均衡实现。

如果看到这里你还不知道负载均衡是干嘛的,那么只能放一张图了,毕竟没图说个啥。

5985016b6e09162bd74f9a10e3f5abc5.png

正经的负载均衡示例

负载均衡要做到在多次请求下,每台服务器被请求的次数大致相同。但是实际生产中,可能每台机器的性能不同,我们会希望性能好的机器承担的请求更多一些,这也是正常需求。

如果这样说下来你看不懂,那我就再举个例子好了,一排可爱的小熊(服务器)站好。

5a353ebd0538350caf3c8135a41d0905.png

一排要被访问的服务器

这时有人(用户)要过来打脸(请求访问)。

227d60f40e7e20e887b902cbe91b10c8.png

用户请求

那么怎么样我们才能让这每一个可爱的小熊被打的次数大致相同呢?

又或者熊 4 比较胖,抗击打能力是别人的两倍,我们怎么提高熊 4 被打的次数也是别人的两倍呢?

又或者每次出手的力度不同,有重有轻,恰巧熊 4 总是承受这种大力度啪啪打脸,熊 4 即将不省熊事,还要继续打它吗?

这些都是值得思考的问题。

说了那么多,口干舌燥,我双手已经饥渴难耐了,迫不及待的想要撸起代码了。

1. 随机访问

上面说了,为了负载均衡,我们必须保证多次出手后,熊 1 到熊 4 被打次数均衡。比如使用随机访问法,根据数学上的概率论,随机出手次数越多,每只熊被打的次数就会越相近。代码实现也比较简单,使用一个随机数,随机访问一个就可以了。

/** 服务器列表 */private static List serverList = new ArrayList<>();static {    serverList.add("192.168.1.2");    serverList.add("192.168.1.3");    serverList.add("192.168.1.4");    serverList.add("192.168.1.5");}/** * 随机路由算法 */public static String random() {    // 复制遍历用的集合,防止操作中集合有变更    List tempList = new ArrayList<>(serverList.size());    tempList.addAll(serverList);    // 随机数随机访问    int randomInt = new Random().nextInt(tempList.size());    return tempList.get(randomInt);}

因为使用了非线程安全的集合,所以在访问操作时操作的是集合的拷贝,下面几种轮询方式中也是这种思想。

写一个模拟请求方法,请求10w次,记录请求结果。

public static void main(String[] args) {    HashMap serverMap = new HashMap<>();    for (int i = 0; i  entry : serverMap.entrySet()) {        System.out.println("IP:" + entry.getKey() + ",次数:" + entry.getValue());    }}

运行得到请求结果。

IP:192.168.1.3,次数:24979IP:192.168.1.2,次数:24896IP:192.168.1.5,次数:25043IP:192.168.1.4,次数:25082

每台服务器被访问的次数都趋近于 2.5w,有点负载均衡的意思。但是随机毕竟是随机,是不能保证访问次数绝对均匀的。

2. 轮询访问

轮询访问就简单多了,拿上面的熊1到熊4来说,我们一个接一个的啪啪 - 打脸,熊1打完打熊2,熊2打完打熊3,熊4打完打熊1,最终也是实现了被打均衡。但是保证均匀总是要付出代价的,随机访问中需要随机,轮询访问中需要什么来保证轮询呢?

/** 服务器列表 */private static List serverList = new ArrayList<>();static {    serverList.add("192.168.1.2");    serverList.add("192.168.1.3");    serverList.add("192.168.1.4");    serverList.add("192.168.1.5");}private static Integer index = 0;/** * 随机路由算法 */public static String randomOneByOne() {    // 复制遍历用的集合,防止操作中集合有变更    List tempList = new ArrayList<>(serverList.size());    tempList.addAll(serverList);    String server = "";    synchronized (index) {        index++;        if (index == tempList.size()) {            index = 0;        }        server = tempList.get(index);;    }    return server;}

由代码里可以看出来,为了保证轮询,必须记录上次访问的位置,为了让在并发情况下不出现问题,还必须在使用位置记录时进行加锁,很明显这种互斥锁增加了性能开销。

依旧使用上面的测试代码测试10w次请求负载情况。

IP:192.168.1.3,次数:25000IP:192.168.1.2,次数:25000IP:192.168.1.5,次数:25000IP:192.168.1.4,次数:25000

3. 轮询加权

上面演示了轮询方式,还记得一开始提出的熊4比较胖抗击打能力强,可以承受别人2倍的挨打次数嘛?上面两种方式都没有体现出来熊 4 的这个特点,熊 4 窃喜,不痛不痒。但是熊 1 到 熊 3 已经在崩溃的边缘,不行,我们必须要让胖着多打,能者多劳,提高整体性能。

/** 服务器列表 */private static HashMap serverMap = new HashMap<>();static {    serverMap.put("192.168.1.2", 2);    serverMap.put("192.168.1.3", 2);    serverMap.put("192.168.1.4", 2);    serverMap.put("192.168.1.5", 4);}private static Integer index = 0;/** * 加权路由算法 */public static String oneByOneWithWeight() {    List tempList = new ArrayList();    HashMap tempMap = new HashMap<>();    tempMap.putAll(serverMap);    for (String key : serverMap.keySet()) {        for (int i = 0; i 

这次记录下了每台服务器的整体性能,给出一个数值,数值越大,性能越好。可以承受的请求也就越多,可以看到服务器 192.168.1.5 的性能为 4,是其他服务器的两倍,依旧 10 w 请求测试。

IP:192.168.1.3,次数:20000IP:192.168.1.2,次数:20000IP:192.168.1.5,次数:40000IP:192.168.1.4,次数:20000

192.168.1.5 承担了 2 倍的请求。

4. 随机加权

随机加权的方式和轮询加权的方式大致相同,只是把使用互斥锁轮询的方式换成了随机访问,按照概率论来说,访问量增多时,服务访问也会达到负载均衡。

/** 服务器列表 */private static HashMap serverMap = new HashMap<>();static {    serverMap.put("192.168.1.2", 2);    serverMap.put("192.168.1.3", 2);    serverMap.put("192.168.1.4", 2);    serverMap.put("192.168.1.5", 4);}/** * 加权路由算法 */public static String randomWithWeight() {    List tempList = new ArrayList();    HashMap tempMap = new HashMap<>();    tempMap.putAll(serverMap);    for (String key : serverMap.keySet()) {        for (int i = 0; i 

依旧 10 w 请求测试,192.168.1.5 的权重是其他服务器的近似两倍,

IP:192.168.1.3,次数:19934IP:192.168.1.2,次数:20033IP:192.168.1.5,次数:39900IP:192.168.1.4,次数:20133

5. IP-Hash

上面的几种方式要么使用随机数,要么使用轮询,最终都达到了请求的负载均衡。但是也有一个很明显的缺点,就是同一个用户的多次请求很有可能不是同一个服务进行处理的,这时问题来了,如果你的服务依赖于 session ,那么因为服务不同, session 也会丢失,不是我们想要的,所以出现了一种根据请求端的 ip 进行哈希计算来决定请求到哪一台服务器的方式。这种方式可以保证同一个用户的请求落在同一个服务上。

private static List serverList = new ArrayList<>();static {    serverList.add("192.168.1.2");    serverList.add("192.168.1.3");    serverList.add("192.168.1.4");    serverList.add("192.168.1.5");}/** * ip hash 路由算法 */public static String ipHash(String ip) {    // 复制遍历用的集合,防止操作中集合有变更    List tempList = new ArrayList<>(serverList.size());    tempList.addAll(serverList);    // 哈希计算请求的服务器    int index = ip.hashCode() % serverList.size();    return tempList.get(Math.abs(index));}

6. 总结

上面的四种方式看似不错,那么这样操作下来真的体现了一开始说的负载均衡吗?答案是不一定的。就像上面的最后一个提问。

又或者每次出手的力度不同,有重有轻,恰巧熊 4 总是承受这种大力度啪啪打脸,熊 4 即将不省熊事,还要继续打它吗?

服务器也是这个道理,每次请求进行的操作对资源的消耗可能是不同的。比如说某些操作它对 CPU 的使用就是比较高,也很正常。所以负载均衡有时不能简单的通过请求的负载来作为负载均衡的唯一依据。还可以结合服务的当前连接数量、最近响应时间等维度进行总体均衡,总而言之,就是为了达到资源使用的负载均衡。

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

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

相关文章

mysql 重装之后_mysql重装之后 复制data

(哇&#xff0c;编程小白的第一篇博客丫&#xff0c;激动)Q one&#xff1a;mysql需要重装&#xff0c;数据该怎么办。方法一&#xff1a;数据表最好是导出成.sql文件&#xff0c;这样才比较安全。方法二&#xff1a;直接copy了data文件&#xff1a;在mysql安装盘下的programda…

vs2010 mysql linq to sql 系列_LINQ to SQL 系列 如何使用LINQ to SQL插入、修改、删除数据...

LINQ和 LINQ to SQL 都已经不是一个新事物了&#xff0c;但是我接触的比较晚&#xff0c;本着绝知此事要躬行的态度&#xff0c;决定写这个系列。本文使用的测试环境是VS 2010&#xff0c;和sql server 2005数据库。第一篇 从CUD开始&#xff0c;如何使用LINQ to SQL插入…

redis session 超时时间_Shiro性能优化:解决Session频繁读写问题

点击上方蓝色字体&#xff0c;选择“标星公众号”优质文章&#xff0c;第一时间送达作者 | 张永恒来源 | urlify.cn/YjEZNj背景Shiro 提供了强大的 Session 管理功能&#xff0c;基于 Shiro 实现 Session 共享非常方便&#xff0c;只需要定制一个我们自己的SessionDAO&#x…

mysql too many connections_mysql too many connections 解决方法

1、mysql -u root -p 回车输入密码进入mysql2、show processlist;查看连接数&#xff0c;可以发现有很多连接处于sleep状态&#xff0c;这些其实是暂时没有用的&#xff0c;所以可以kill掉3、show variables like "max_connections";查看最大连接数&#xff0c;应该是…

qt更改类名_Qt编写自定义控件属性设计器

以前做.NET开发中&#xff0c;.NET直接就集成了属性设计器&#xff0c;VS不愧是宇宙第一IDE&#xff0c;你能够想到的都给你封装好了&#xff0c;用起来不要太爽&#xff01;因为项目需要自从全面转Qt开发已经6年有余&#xff0c;在工业控制领域&#xff0c;有一些应用场景需要…

sudo mysql压缩备份解压操作_高效管理文件之压缩及解压缩 .bz2 文件

对文件进行压缩&#xff0c;可以通过使用较少的字节对文件中的数据进行编码来显著地减小文件的大小&#xff0c;并且在跨网络的文件的备份和传送时很有用。 另一方面&#xff0c;解压文件意味着将文件中的数据恢复到初始状态。Linux 中有几个文件压缩和解压缩更具&#xff0c;比…

zygoteinit.java_源码跟踪之启动流程:从ZygoteInit到onCreate

InstrumentationSDK版本名称: PieAPI Level: 28一、源码调用时序图1. Activity的启动流程说明&#xff1a;其中ActivityThread中执行的scheduleTransaction方法在其父类ClientTransactionHandler中&#xff0c;发送了ActivityThread.H.EXECUTE_TRANSACTION&#xff0c;Activity…

小城交通大转型!苏州金龙助力杭州建德公交开新格局

新安江畔&#xff0c;密林丛生&#xff0c;一辆辆绿色巴士穿梭而行&#xff0c;杭州市首款纯电动无站立位公交车正在试运行中。 12月19日&#xff0c;杭州建德&#xff0c;23辆苏州金龙海格牌6米无站立位新能源纯电动公交车正式交付建德市公共交通运输有限公司。自此&#xff…

java虚拟机性能优化_死磕Java虚拟机-性能调优实战篇

Java命令分为如下三种1. 以java - 开头&#xff1a;标准参数2. 以java -X 开头&#xff1a;非标参数3. 以java -XX 开头&#xff1a;性能调优主要用这个开头的参数&#xff0c;但是无法找到相关参数的帮助文档&#xff0c;下面我教大家几个常用的命令-XX:UseSerialGC Seria…

java volatile 原子性_Java中volatile不能保证原子性的证明

Java并发编程之验证volatile不能保证原子性通过系列文章的学习&#xff0c;凯哥已经介绍了volatile的三大特性。1&#xff1a;保证可见性 2&#xff1a;不保证原子性 3&#xff1a;保证顺序。那么怎么来验证可见性呢&#xff1f;本文凯哥(凯哥Java:kaigejava)将通过代码演示来证…

mysql 漏洞如何修复_Mysql漏洞修复方法思路及注意事项

【系统环境】系统环境&#xff1a;Red Hat Enterprise Linux Server release 5.4 (Tikanga) 5.7.16 MySQL Community Server (GPL)【漏洞信息】漏洞信息报告&#xff0c;根据集团第三方软件扫描出对应数据库版本的漏洞信息&#xff0c;可以从DVE号跟当前数据库发布版本时间来判…

Java飞机大战敌机消失_Shoot 飞机大战,功能是子弹打在敌机上, 消失 且在内存中 , 小蜜蜂上同理 Games 游戏 247万源代码下载- www.pudn.com...

文件名称: Shoot下载 收藏√ [5 4 3 2 1 ]所属分类: Games开发工具: Java文件大小: 371 KB上传时间: 2015-12-01下载次数: 0提 供 者: 刘星详细说明&#xff1a;飞机大战&#xff0c;功能是子弹打在敌机上&#xff0c;子弹消失敌机消失且在内存中消失&#xff0c;打在小蜜…

日志分析告警实现java_关于Aborted connection告警日志的分析

前言&#xff1a;有时候&#xff0c;连接MySQL的会话经常会异常退出&#xff0c;错误日志里会看到"Got an error reading communication packets"类型的告警。本篇文章我们一起来讨论下该错误可能的原因以及如何来规避。1.状态变量Aborted_clients和Aborted_connects…

网页java在div输出内容_JS实现读取xml内容并输出到div中的方法示例

本文实例讲述了JS实现读取xml内容并输出到div中的方法。分享给大家供大家参考&#xff0c;具体如下&#xff1a;note.xml文件结构:GeorgeJohnReminderaJohnReminderGeorgeJohnReminder利用js将xml输出到div中&#xff1a;www.jb51.net js读取xml.aaaa{width: 30%;height: 50px;…

java枚举加载顺序_java 中类的加载顺序(转)

1、虚拟机在首次加载Java类时&#xff0c;会对静态初始化块、静态成员变量、静态方法进行一次初始化2、只有在调用new方法时才会创建类的实例3、类实例创建过程&#xff1a;按照父子继承关系进行初始化&#xff0c;首先执行父类的初始化块部分&#xff0c;然后是父类的构造方法…

java相遇问题_两车追及或相遇问题(hdu1275)数学题

两车追及或相遇问题Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 902 Accepted Submission(s):259Problem Description外号叫“猪头三”的小学生在数学课上&#xff0c;经常遇到两车相遇或追及的方程题&#xff0c;…

java常用class类_java常用类

java常用类内部类1.成员内部类&#xff1a;在一个类的内部定义一个完整的类例如&#xff1a;外部类public class Body{内部类class Header{}}内部类可以直接访问外部类的私有成员&#xff0c;而且不破坏封装内部类可以为外部类提供必要的功能组件&#xff0c;成员内部类 在类的…

mysql 分类计数器_PHP MySQL映像计数器

我是PHP新手,一直在研究计数器.计数器很好用,但是现在我想将数字转换成图像.我创建了12张图片0-9,一个空格和一个逗号图片.我在上下搜索,以获取将数字格式转换为图像所需的提示,但没有成功.到目前为止,我所发现的就是如何仅使用文件PHP / MySQL来建立基本的计数器,以及如何使用…

java gc时会暂停运行吗,java gc 项目终止运行

当前位置:我的异常网 编程 java gc 项目终止运行java gc 项目终止运行www.myexceptions.net 网友分享于&#xff1a;2013-09-03 浏览&#xff1a;6次java gc 项目停止运行首先感谢阿宝同学的帮助&#xff0c;我才对这个gc算法的调整有了一定的认识&#xff0c;而不是停留在过…

php 取消页面一些样式,jquery如何去除样式

jquery去除样式的方法&#xff1a;1、使用【removeClass()】方法&#xff0c;代码为【removeClass(function(index,class))】&#xff1b;2、使用toggleClass方法&#xff0c;代码为【toggleClass(class)】。本教程操作环境&#xff1a;windows7系统、jquery3.2.1版&#xff0c…