负载均衡的几种算法原理及代码实现

栏目: 服务器 · 发布时间: 6年前

内容简介:轮询算法: 将接收到的请求依次转发到后端服务器上,它均衡对待(一视同仁)所有服务器,而不关心当前服务器实际连接数及当前系统负载。 这里实现一个简单的轮询系统:在实际生产环境中,我们还得考虑诸多因素,比如:

轮询算法: 将接收到的请求依次转发到后端服务器上,它均衡对待(一视同仁)所有服务器,而不关心当前服务器实际连接数及当前系统负载。 这里实现一个简单的轮询系统:

public class RoundRobin { 
   static Integer  position = 0; 
   public static List<String> initServerList() { 
       List<String> servers = new ArrayList<>(); 
       servers.add("192.168.10.00"); 
       servers.add("192.168.10.01"); 
       servers.add("192.168.10.02"); 
       servers.add("192.168.10.03"); 
       servers.add("192.168.10.04"); 
       servers.add("192.168.10.05"); 
       servers.add("192.168.10.06"); 
       return servers; 
   } 
   public static String getServerUrl() { 
       //新建立一个List赋值,避免服务器上下线导致的并发问题 
       List<String> serverList = new ArrayList<>(); 
       serverList.addAll(initServerList()); 
       String server = null; 
       synchronized (position){ 
           if(position >= serverList.size()) { 
               position = 0; 
           } 
           server = serverList.get(position); 
           position ++; 
       } 
       return server; 
   } 
   public static void main(String[] args) { 
       while (true){ 
           System.out.println(getServerUrl()); 
       } 
   } 
} 

在实际生产环境中,我们还得考虑诸多因素,比如:

负载均衡的几种算法原理及代码实现

新增服务器ip如何处理? 这个比较简单,直接添加到initServerList()即可。

出现服务宕机怎么办? 比如192.168.10.01 所在服务器挂掉了,请求被转发给它,就会报错。这时,需要服务的消费者考虑容错处理,在这种情况下,比如再发一次请求,那就会被转发到192.168.10.02 机器上,正常。 该方法最大缺点是引用了悲观锁 synchronized,影响系统的并发性能。

每台机器的配置不一样,有单核CPU,2G内存,有8核CPU,32G内存。这种情形下,使用上述轮询,那就不公平了,对弱配置机器,压力很大。 这个,我们可以引入

加权轮询: 每台服务器,给一个权重值,权值高的,多分配点儿请求,权值少的,少分配点儿请求,。 实现思路也很简单,根据权值,重新构建服务列表,然后再轮询。上个图示:

如下是代码实现:

public class WeightRoundRobin { 
   static Integer  position = 0; 
   public static Map<String, Integer> initServicesMap() { 
       Map<String, Integer> servicesMap = new HashMap<>(); 
       servicesMap.put("192.168.10.00", 1); 
       servicesMap.put("192.168.10.02", 3); 
       servicesMap.put("192.168.10.03", 3); 
       servicesMap.put("192.168.10.04", 5); 
       servicesMap.put("192.168.10.05", 5); 
       servicesMap.put("192.168.10.06", 5); 
       return servicesMap; 
   } 
   public static String getServerUrl() { 
       //新建立一个List赋值,避免服务器上下线导致的并发问题 
       Map<String, Integer> initMap = new HashMap<>(); 
       initMap = initServicesMap(); 
       Set<String> servicesSet = new HashSet<>(); 
       servicesSet.addAll(initMap.keySet()); 
       Iterator<String> servicesIterator = servicesSet.iterator(); 
       List<String> servicesList = new ArrayList<>(); 
       while (servicesIterator.hasNext()) { 
           String server = servicesIterator.next(); 
           Integer weight = initMap.get(server); 
           if(weight > 0) { 
               for(int i=0; i<weight; i++) { 
                   servicesList.add(server); 
               } 
           } 
       } 
       String server = null; 
       synchronized (position){ 
           if(position >= servicesList.size()) { 
               position = 0; 
           } 
           server = servicesList.get(position); 
           position ++; 
       } 
       return server; 
   } 
   public static void main(String[] args) { 
       while (true){ 
           System.out.println(getServerUrl()); 
       } 
   } 
} 

随机算法:

顾名思义:现有N个服务器ip地址,请求来了后,随机转发到某个服务器上。从概率的角度来说,随着请求数的增多,最终每台服务器分配到的请求,近似于均等。这就比轮询算法少了个悲观锁,并发性能上,有了极大的提升。

实现也很简单:

如下:

public class RandomDemo { 
   public static List<String> initServerList() { 
       List<String> servers = new ArrayList<>(); 
       servers.add("192.168.10.00"); 
       servers.add("192.168.10.01"); 
       servers.add("192.168.10.02"); 
       servers.add("192.168.10.03"); 
       servers.add("192.168.10.04"); 
       servers.add("192.168.10.05"); 
       servers.add("192.168.10.06"); 
       return servers; 
   } 
   public static String getServerUrl() { 
       //新建立一个List赋值,避免服务器上下线导致的并发问题 
       List<String> serverList = new ArrayList<>(); 
       serverList.addAll(initServerList()); 
       int position = new Random().nextInt(serverList.size()); 
       return serverList.get(position); 
   } 
   public static void main(String[] args) { 
       while (true) { 
           System.out.println(getServerUrl()); 
       } 
   } 
} 

但他也有与简单轮询算法一样的问题:

对于不同性能的服务器,依旧一视同仁,那其实是不公平的。低配置,应该少分点请求嘛。

这就有了

加权随机算法,其实现思想同 加权轮询算法一样,给不同配置的服务器,配置不同的权重值。代码实现也同加权轮询思路一样,构建出符合权重值的服务集合后,再进行随机选取,这里就不写了,留给大家自己去写吧。

源地址哈希(hashCode)法 : 根据客户端的请求ip,通过哈希计算,得到一个数值,随后与服务器列表个数,进行取模计算,得到该请求 访问服务器列表的序号。该方法,有个好处是,当服务器列表不变时,某个客户端,会始终访问某一个固定的服务器,这样就可以构建一个客户端--服务器之间,有状态的session。

代码实现:

public class HashDemo {  
   public static List<String> initServerList() {  
       List<String> servers = new ArrayList<>();  
       servers.add("192.168.10.00");  
       servers.add("192.168.10.01");  
       servers.add("192.168.10.02");  
       servers.add("192.168.10.03");  
       servers.add("192.168.10.04");  
       servers.add("192.168.10.05");  
       servers.add("192.168.10.06");  
       return servers;  
   }  
   public static String getServerUrl() {  
       //新建立一个List赋值,避免服务器上下线导致的并发问题  
       List<String> serverList = new ArrayList<>();  
       serverList.addAll(initServerList());  
       int requestIpHashCode = "192.168.10.06.109".hashCode();  
       int position = requestIpHashCode % serverList.size();  
       return serverList.get(position);  
   }  
   public static void main(String[] args) {  
       while (true) {  
           System.out.println(getServerUrl());  
       }  
   }  
}  

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

图解网络硬件

图解网络硬件

[日] 三轮贤一 / 盛荣 / 人民邮电出版社 / 2014-7 / 69.00元

本书详细介绍了计算机网络硬件的相关知识,在对硬件设备、相关技术及规范进行详尽考据和整理的同时,侧重工程实践,重点讲述了在实际网络建设工程中真实使用的网络硬件设备及其相关背景知识,能够帮助读者深入理解计算机网络在工程实践中某些容易混淆的概念,如L3交换机和路由器等。 本书在讲解的同时,还辅以丰富的图例,使计算机网络设备的真实情况一目了然,同时深入浅出地介绍了原本复杂抽象的计算机网络术语,因此对......一起来看看 《图解网络硬件》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具