java分布式之负载均衡

在传统的系统中,应用程序、数据服务器、文件服务器等都在同一台机器上部署。随着互联网的发展,系统的访问量的增加,一台机器根本满足不了多用户的高并发访问,

计算机领域,当单机性能达到瓶颈时,有两种方式可以解决性能问题,一是堆硬件,进一步提升配置,二是分布式,水平扩展。所以,假如一台机器不能

满足高并发的请求访问,那么就两台,两台还满足不了就增加到三台,这种方式我们称之为水平扩展,如何实现请求的平均分配便是负载均衡


负载均衡,英文名称(Load Balance),简称 LB。指由多台服务器以对称的方式组成一个服务器集合,每台服务器都具有等价的地位,都可以单独对外提供服务而无须其他服

务器的辅助。通过某种负载分担技术,将外部发送来的请求均匀分配到对称结构中的某一台服务器上,而接收到请求的服务器独立地回应客户的请求。负载均衡能够

平均分配客户请求到服 务器阵列,借此提供快速获取重要数据,解决大量并发访问服务问题,这种集群技术可以用最少的投资获得接近于大型主机的性能。


那么如何来实现把请求均匀地分配到不同的分布式服务器上呢。这里介绍几种算法:


首先我们先定义一个map的IP地址,指每台服务器


 public class IpMap
 2 {
 3     // 待路由的Ip列表,Key代表Ip,Value代表该Ip的权重
 4     public static HashMap<String, Integer> serverWeightMap = 
 5             new HashMap<String, Integer>();
 6     
 7     static
 8     {
 9         serverWeightMap.put("192.168.1.100", 1);
10         serverWeightMap.put("192.168.1.101", 1);
11         // 权重为4
12         serverWeightMap.put("192.168.1.102", 4);
13         serverWeightMap.put("192.168.1.103", 1);
14         serverWeightMap.put("192.168.1.104", 1);
15         // 权重为3
16         serverWeightMap.put("192.168.1.105", 3);
17         serverWeightMap.put("192.168.1.106", 1);
18         // 权重为2
19         serverWeightMap.put("192.168.1.107", 2);
20         serverWeightMap.put("192.168.1.108", 1);
21         serverWeightMap.put("192.168.1.109", 1);
22         serverWeightMap.put("192.168.1.110", 1);
23     }
24 }

1、轮询算法

public class RoundRobin
 2 {
 3     private static Integer pos = 0;
 4     
 5     public static String getServer()
 6     {
 7         // 重建一个Map,避免服务器的上下线导致的并发问题
 8         Map<String, Integer> serverMap = 
 9                 new HashMap<String, Integer>();
10         serverMap.putAll(IpMap.serverWeightMap);
11         
12         // 取得Ip地址List
13         Set<String> keySet = serverMap.keySet();
14         ArrayList<String> keyList = new ArrayList<String>();
15         keyList.addAll(keySet);
16         
17         String server = null;
18         synchronized (pos)
19         {
20             if (pos > keySet.size())
21                 pos = 0;
22             server = keyList.get(pos);
23             pos ++;
24         }
25         
26         return server;
27     }
28 }

由于serverWeightMap中的服务器可能会出现新增、下线或者宕机,为了避免可能出现的并发问题(?),方法内部要新建局部变量serverMap,现将

serverMap中的内容复制到线程本地,以避免被多 个线程修改。这样可能会引入新的问题,复制以后serverWeightMap的修改无法反映给serverMap,也就是

说这一轮选择服务器的过程中, 新增服务器或者下线服务器,负载均衡算法将无法获知。新增无所谓,如果有服务器下线或者宕机,那么可能会访问到不存在的

地址。因此,服务调用端需要有相应的容错处理,比如重新发起一次server选择并调用对于当前轮询的位置变量pos,为了保证服务器选择的顺序性,需要在操

作时对其加锁,使得同一时刻只能有一个线程可以修改pos的值。

2、随机法

 public class Random
 2 {
 3     public static String getServer()
 4     {
 5         // 重建一个Map,避免服务器的上下线导致的并发问题
 6         Map<String, Integer> serverMap = 
 7                 new HashMap<String, Integer>();
 8         serverMap.putAll(IpMap.serverWeightMap);
 9         
10         // 取得Ip地址List
11         Set<String> keySet = serverMap.keySet();
12         ArrayList<String> keyList = new ArrayList<String>();
13         keyList.addAll(keySet);
14         
15         java.util.Random random = new java.util.Random();
16         int randomPos = random.nextInt(keyList.size());
17         
18         return keyList.get(randomPos);
19     }
20 }

在选取server的时候,通过Random的nextInt方法取0~keyList.size()区间的一个随机值,然后获得服务器并返回。

3、哈希地址法

public class Hash
 2 {
 3     public static String getServer()
 4     {
 5         // 重建一个Map,避免服务器的上下线导致的并发问题
 6         Map<String, Integer> serverMap = 
 7                 new HashMap<String, Integer>();
 8         serverMap.putAll(IpMap.serverWeightMap);
 9         
10         // 取得Ip地址List
11         Set<String> keySet = serverMap.keySet();
12         ArrayList<String> keyList = new ArrayList<String>();
13         keyList.addAll(keySet);
14         
15         // 在Web应用中可通过HttpServlet的getRemoteIp方法获取
16         String remoteIp = "127.0.0.1";
17         int hashCode = remoteIp.hashCode();
18         int serverListSize = keyList.size();
19         int serverPos = hashCode % serverListSize;
20         
21         return keyList.get(serverPos);
22     }
23 }
哈希算法就是通过客户端的IP地址,取得它的hash值,然后对服务器列表个数取模,来取得相应的服务器。

总结:

轮询算法:优点是基本能够实现请求的均衡分配;缺点是为了使得服务分配的顺序性,必须得引入悲观锁(synchronized),影响并发访问的效率。

随机算法:基于概率统计原理,吞吐量越大,随机发越能接近轮询法的平均效果。

hash算法:保证了相同客户端IP地址将会被哈希到同一台后端服务器,直到后端服务器列表变更。根据此特性可以在服务消费者与服务提供者之间建立有状态的

session会话。缺点是如果服务器发生上下线或者宕机的情况,会造成不能正确路由到以前所路由到的服务器上,如果是session则取不到session,如果是缓存则

可能引发"雪崩"

4、加权轮询法或加权随机法

另外:由于不同服务器的配置不同,抗压能力也不尽相同,那么为了给那些配置好的多些负载,配置低的服务器少些负载,就引入了权重的概念。

public class WeightRoundRobin
 2 {
 3     private static Integer pos;
 4     
 5     public static String getServer()
 6     {
 7         // 重建一个Map,避免服务器的上下线导致的并发问题
 8         Map<String, Integer> serverMap = 
 9                 new HashMap<String, Integer>();
10         serverMap.putAll(IpMap.serverWeightMap);
11         
12         // 取得Ip地址List
13         Set<String> keySet = serverMap.keySet();
14         Iterator<String> iterator = keySet.iterator();
15         
16         List<String> serverList = new ArrayList<String>();
17         while (iterator.hasNext())
18         {
19             String server = iterator.next();
20             int weight = serverMap.get(server);
21             for (int i = 0; i < weight; i++)
22                 serverList.add(server);
23         }
24         
25         String server = null;
26         synchronized (pos)
27         {
28             if (pos > keySet.size())
29                 pos = 0;
30             server = serverList.get(pos);
31             pos ++;
32         }
33         
34         return server;
35     }
36 }

关键是在获得服务器之前加入了下面的权重代码,如果权重大,在serverList里面的该服务就多,就能多分得几次请求。

while (iterator.hasNext())
18         {
19             String server = iterator.next();
20             int weight = serverMap.get(server);
21             for (int i = 0; i < weight; i++)
22                 serverList.add(server);
23         }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值