负载均衡算法示例
声明:本文根据鲁班学院周瑜老师课程笔记整理而来
负载均衡的介绍?
算法的前提条件:
定义一个服务器列表,每个负载均衡的算法会从中挑选一个服务器作为算法的结果:
/** * 定义一个服务器列表,每个负载均衡算法会从中挑选一个服务器作为算法结果 * @author Administrator * */ public class ServerIps { public static final List<String> LIST = Arrays.asList( "192.168.0.1", "192.168.0.2", "192.168.0.3", "192.168.0.4", "192.168.0.5", "192.168.0.6", "192.168.0.7", "192.168.0.8", "192.168.0.9", "192.168.0.10"); }
随机算法--RandomLoadBalance
首先来个最简单的随机算法的实现。
/** * 随机算法 * @author Administrator * */ public class JavaRandom { public static String getServer(){ //生成一个随机数作为list的下标值 Random random = new Random(); int randomPos = random.nextInt(ServerIps.LIST.size()); return ServerIps.LIST.get(randomPos); } public static void main(String[] args) { //连续调用10次 for(int i=0;i<10;i++){ System.out.println(getServer()); } } }
运行结果:
当调用次数比较少时,Random产生的随机数可能会比较集中,此时多数请求会落到同一台服务器上,只有在经过多次请求后,才能使用请求进行“均匀”分配,调用量少这一点对我们来说不算什么,因为负载均衡机制正是为了应对请求量多的情况。所以随机算法也是用的比较多的一种算法。
但是,上面的随机算法适用于每台机器的性能差不多的时候,实际上,上产中可能某些机器的性能更高一点,它可以处理更多的请求,所以我们可以对每台机器设置一个权重。
我们在ServerIps类中增加服务器权重对应关系的Map,设置权重之和为50。
//增加权重 public static final Map<String,Integer> WEIGHT_LIST=new HashMap<>(); static{ WEIGHT_LIST.put("192.168.0.1", 1); WEIGHT_LIST.put("192.168.0.2", 8); WEIGHT_LIST.put("192.168.0.3", 3); WEIGHT_LIST.put("192.168.0.4", 6); WEIGHT_LIST.put("192.168.0.5", 5); WEIGHT_LIST.put("192.168.0.6", 5); WEIGHT_LIST.put("192.168.0.7", 4); WEIGHT_LIST.put("192.168.0.8", 7); WEIGHT_LIST.put("192.168.0.9", 2); WEIGHT_LIST.put("192.168.0.10", 9); }
那么现在的随机算法应该要改成权重随机算法,当调用量比较多的时候,服务器使用的分布应该近似对应权重的分布。
权重随机算法:
简单的思路是,把每个服务器按它对应的服务器进行复制。
/** * 增加权重的随机算法 * @author Administrator * */ public class JavaWeightRandom { public static String getServer(){ //1.首先根据权重进行list数组的赋值 List<String> ips = new ArrayList<>(); for(String ip : ServerIps.WEIGHT_LIST.keySet()){ Integer weight = ServerIps.WEIGHT_LIST.get(ip); //按权重进行赋值 for(int i = 0;i<weight;i++){ ips.add(ip); } } //2.在list数组中使用随机算法进行取值 //生成一个随机数作为list的下标值 Random random = new Random(); int randomPos = random.nextInt(ips.size()); return ips.get(randomPos); } public static void main(String[] args) { //连续调用10次 for(int i = 0;i<10;i++){ System.out.println(getServer()); } } }
运行结果:
这种实现方法在遇到权重之和特别大的时候,就会比较消耗内存,因为需要对IP地址进行复制,权重之和越大,那么上下文的IPS就需要越多的内存,下面介绍另外一种实现思路。
假设我们有一组服务器servers=[A,B,C],它们对应的权重为weights=[5,3,2],权重总和为10,现在把这些权重值平铺在一维坐标值上,[0,5)区间属于服务器A,[5,8)区间属于服务器B,[8,10)区间属于服务器C,接下来通过随机数生成器生成一个范围在[0,10)之间的随机数,然后计算这个随机数会落到哪个区间上,比如:数字3会落在服务器A对应的区间上,此时返回服务器A即可,权重越大的机器在坐标轴上对应的区间范围就越大,因此随机数生成器生成的数字就会有更大的概率落到此区间上。只要随机数生成器产生的随机数分不行很好,在经过多次选择之后,每个服务器被选中的次数比例接近其权重比例。比如,经过一万次选择后,服务器A被选中的次数大约为5000次,服务器B被选中的次数大约为3000次,服务器C被选中的次数大约为2000次。
假设现在的随机数offset=7;
1.offset<5 is false,所以不在[0,5)区间,将offset = offset-5(offset=2)
2.offset<3 is true,所以处在[5,8)区间,所以应该选择服务器B
/** * 将权重模拟在一维坐标轴上 * @author Administrator * */ public class JavaWeightRandom2 { public static String getServer(){ //定义总权重属性 int totalWeight = 0; boolean sameWeight = true;//如果所有权重都相等,那么就随机一个IP //得到所有的权重,生成一维坐标轴 Object[] weights = ServerIps.WEIGHT_LIST.values().toArray(); for(int i =0;i<weights.length;i++){ Integer weight = (Integer) weights[i]; totalWeight += weight; //判断是否所有权重都相等 if(sameWeight && i>0 && !weight.equals(weights[i-1])){ sameWeight = false; } } //生成一个随机数作为list的下标值 Random random = new Random(); int randomPos = random.nextInt(totalWeight); if(!sameWeight){//不是所有权重都相等时 for(String ip : ServerIps.WEIGHT_LIST.keySet()){ Integer value = ServerIps.WEIGHT_LIST.get(ip); if(randomPos < value){ return ip; } randomPos = randomPos -value; } } //如果所有权重都相等直接随机返回一个 return (String) ServerIps.WEIGHT_LIST.keySet().toArray()[new Random().nextInt(ServerIps.WEIGHT_LIST.size())]; } public static void main(String[] args) { //连续调用10次 for(int i=0;i<10;i++){ System.out.println(getServer()); } } }
测试结果:
这就是另外一种权重随机算法
轮询算法--RoundRobinLoadBalance
简单的轮询算法很简单
/** * 简单的轮询算法 * @author Administrator * */ public class JavaRoundRobin { //当前循环的位置 private static Integer pos = 0; public static String getServer(){ String ip = null; //pos同步 synchronized (pos) { if(pos >= ServerIps.LIST.size()){ pos = 0; } ip = ServerIps.LIST.get(pos); pos++; } return ip; } public static void main(String[] args) { for(int i=0;i<10;i++){ System.out.println(getServer()); } } }
测试结果:
这种算法很简单也很公平,每台服务器轮流来进行服务,但是,有的机器性能好,所以应当能者多劳,和随机算法一样,加上权重这个维度之后,其中一种实现方法就是复制发,这种复制算法和随机算法一样,缺点都是比较消耗内存,那么有没有用其他实现方法?我们下面来介绍一种算法。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· Blazor Hybrid适配到HarmonyOS系统
· Obsidian + DeepSeek:免费 AI 助力你的知识管理,让你的笔记飞起来!
· 分享4款.NET开源、免费、实用的商城系统
· 解决跨域问题的这6种方案,真香!
· 一套基于 Material Design 规范实现的 Blazor 和 Razor 通用组件库