当前位置: 首页 > 科技观察

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

时间:2023-03-22 17:28:33 科技观察

轮询算法:接收到的请求依次转发给后端服务器,它对所有的服务器都是均衡的(equaltreatment),不管实际连接数多少当前服务器和当前系统负载。这里实现了一个简单的轮询系统:publicclassRoundRobin{staticIntegerposition=0;publicstaticListinitServerList(){Listservers=newArrayList<>();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");returnservers;}publicstaticStringgetServerUrl(){//新建一个List赋值,避免服务器下线导致的并发问题ListserverList=newArrayList<>();serverList.addAll(initServerList());Stringserver=null;synchronized(position){if(position>=serverList.size()){position=0;}server=serverList.get(position);position++;}returnserver;}publicstaticvoidmain(String[]args){while(true){System.out.println(getServerUrl());}}}在实际生产环境中,我们要考虑很多因素,比如:如何处理新的服务器ip?这个比较简单,直接添加到initServerList()中即可。服务宕机怎么办?比如192.168.10.01所在服务器宕机,请求转发给它,就会报错。这时候需要服务的消费者就考虑容错处理。在这种情况下,比如你再发一个请求,就会转发到192.168.10.02这台机器上,这是正常的。这种方式最大的缺点是使用了悲观锁synchronized,影响了系统的并发性能。每台机器的配置都不一样,有单核CPU,2G内存,也有8核CPU,32G内存。这种情况下使用上面的轮询是不公平的,对弱配置的机器压力很大。为此,我们可以引入加权循环:每个服务器都被赋予一个权重值。权重高,分配的请求多,权重小,分配的请求少。实现思路也很简单。根据权重值,重建服务列表,然后再次轮询。最后一张图:下面是代码实现:publicclassWeightRoundRobin{staticIntegerposition=0;publicstaticMapinitServicesMap(){MapservicesMap=newHashMap<>();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);returnservicesMap;}publicstaticStringgetServerUrl(){//新建一个List赋值,避免服务器下线导致的并发问题MapinitMap=newHashMap<>();initMap=initServicesMap();SetservicesSet=newHashSet<>();servicesSet.addAll(initMap.keySet());IteratorservicesIterator=servicesSet.iterator();ListservicesList=newArrayList<>();while(servicesIterator.hasNext()){Stringserver=servicesIterator.next();Integerweight=initMap.get(server);if(weight>0){for(inti=0;i<重量;i++){servicesList.add(server);}}}Stringserver=null;synchronized(position){if(position>=servicesList.size()){position=0;}server=servicesList.get(position);position++;}returnserver;}publicstaticvoidmain(String[]args){while(true){System.out.println(getServerUrl());}}}随机算法:顾名思义:有N个服务器ip地址。请求过来后,会随机转发到某台服务器上,从概率上看,随着请求数的增加,分配给每台服务器的请求大致相等。这是一种比轮询算法更少的悲观锁,并发性能得到了很大的提升。实现也很简单:如下: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");服务器。add("192.168.10.06");returnservers;}publicstaticStringgetServerUrl(){//新建一个List赋值,避免服务器下线导致的并发问题ListserverList=newArrayList<>();serverList.addAll(initServerList());intposition=newRandom().nextInt(serverList.size());returnserverList.get(position);}publicstaticvoidmain(String[]args){while(true){System.out.println(getServerUrl());}}但它也有和简单轮询算法一样的问题:对性能不同的服务器一视同仁是不公平的。对于低配置,您应该请求更少的请求。这就引出了加权随机算法。其实现思路与加权循环算法相同。不同配置的服务器配置不同的权重值。代码实现也和加权轮询的思路一样。构建满足权重值的服务集后,进行随机选择。这里就不写了,留给大家自己写吧。源地址哈希(hashCode)方法:根据客户端的请求ip,通过哈希计算得到一个值,然后与服务器列表的个数进行取模运算,得到请求访问服务器列表的序号。这种方法的好处是当服务器列表不变时,客户端总是会访问固定的服务器,这样就可以构建一个客户端-服务器状态会话。代码实现:publicclassHashDemo{publicstaticListinitServerList(){Listservers=newArrayList<>();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");returnservers;}publicstaticStringgetServerUrl(){//新建一个List赋值,避免服务器下线导致的并发问题ListserverList=newArrayList<>();serverList.addAll(initServerList());intrequestIpHashCode="192.168.10.06.109".hashCode();intposition=requestIpHashCode%serverList.size();returnserverList.get(position);}publicstaticvoidmain(String[]args){while(true){System.out.println(getServerUrl());}}}【编者推荐】如何才能全面实现软件定义数据中心(SDDC)?[推荐]负载均衡难吗?看完这篇文章,让我彻底了解Linux小技巧,如何实现免密码登录,为服务器运维节省时间。如何在没有网关的情况下实现LoRa组网?想玩转负载均衡,这些你都知道吗?