要求做一个任务分配的处理。
采用轮询算法,保存当前处理后的索引,方便下次处理时可以拿到开始位置。
轮询算法是最简单的一种负载均衡算法。他的原理是把来自用户请求轮流的分配给内部的服务器: 服务器从一开始,知道服务器N,然后开始循环。
算法的邮电是其简洁性,他无需记录当前所有连接的状态,所以他是一种无状态调度。
轮询算法假设所有服务器处理性能都相同,不关心每台服务器的当前连接数和响应速度,当请求服务间隔时间变化比较大时。轮询算法容易导致服务器间的负载不均衡。所以这种负载均衡算法适合于服务器组中的所有服务器都相同的软硬件配置,并且平均请求相对均衡的情况。
package com.taotao.xuexi.lunxun;
/**
*采用轮询算法,VB奥村当前处理后的索引,仿版下次处理时拿到开始的位置
*/
public class RoundRobinPattern {
/**
* 简介: 1, 将目标放在一容器内
* 2,定义一标识,记录上次访问的该目标的对象(标识应该是索引等,需要有规律性)
* 3,(标识加一)取模,然后获取到该目标对象,同事更新该目标标识
* @param args
*/
public static void main(String[] args) {
int [] arr={10,9,8,7,6,5,4,3,2,1,0};
int index=4;//索引:指定开始位置
for (int i = 0; i <17 ; i++) {
int nextIndex=(index+1) % arr.length;
index=nextIndex;
System.out.println(arr[index]+",index="+index);
}
}
}
2种方法实现负载均衡
package com.taotao.xuexi.lunxun;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
public class MyLoadBalance {
public static void main(String[] args) {
List<String> ips=new ArrayLis
ips.add("192.168.0.1");
ips.add("192.168.0.2");
ips.add("192.168.0.3");
//测试第一种方法
System.out.println("选择ip:"+doSelect2(ips));
System.out.println("选择ip:"+doSelect2(ips));
System.out.println("选择ip:"+doSelect2(ips));
System.out.println("选择ip:"+doSelect2(ips));
System.out.println("选择ip:"+doSelect2(ips));
System.out.println("选择ip:"+doSelect2(ips));
System.out.println("选择ip:"+doSelect2(ips));
//测试第二种方法
System.out.println("选择ip:"+doSelect(ips));
System.out.println("选择ip:"+doSelect(ips));
System.out.println("选择ip:"+doSelect(ips));
System.out.println("选择ip:"+doSelect(ips));
System.out.println("选择ip:"+doSelect(ips));
System.out.println("选择ip:"+doSelect(ips));
System.out.println("选择ip:"+doSelect(ips));
}
private static Integer index = 0;
/**
* 加锁同步实现线程安全的轮询负载均衡算法
* @param iplist
* @return
*/
public static String doSelect(List<String> iplist) {
synchronized (index) {
if (index >= iplist.size()) {
index = 0;
}
String ip = iplist.get(index);
index++;
return ip;
}
}
private static AtomicInteger index_ = new AtomicInteger(0);
/**
* 原子类实现线程安全的轮询负载均衡算法
* @param iplist
* @return
*/
public static String doSelect2(List<String> iplist) {
if (index_.get() >= iplist.size()) {
index_ = new AtomicInteger(0);
}
String ip = iplist.get(index_.get());
index_.incrementAndGet();
return ip;
}
}
3,nginx负载均衡策略之round_robin
nginx不单可以作为强大的web服务器,也可以作为一个方向代理服务器。如果nginx时以反向代理的形式配置运行,那么对请求的实际处理需要转发到后端服务器运行,如果后端服务器有多台,如何选择一台合适的后端服务器来处理当前的请求,这就是负载均衡
round_bin策略为默认策略:每个请求按时间顺序注意分配到不同的后端服务器,如果厚度那服务器down掉,能自动剔除。
例如:
upstream tomcats{
server 10.1.1.107.88 max_fails=3 fail_timeout=3s weight =1;
server 10.1.1.132.80 max_fails=3 fail_timeout=3s weight=2;
}
功能:nginx在用做反向代理服务器时,对于后端的服务器可以采用2种分流策略:加权分流和iphash。 nginx默认采用round_robin加权算法;对于权重较高的机器,被选中的概率大,对于权重相同的机器,则采用轮询方式。上面的这个配置,如果3个请求,则有一个会被分发到10.1.1.107服务器上。2个请求分发到10.1.1.132服务器上。
4,权重轮询调度算法(Weight Round-Robin Scheduling)
上面讲的轮询调度方法并没有了考虑到每台服务器的处理能力,在实际情况中,可能并不是这种情况。由于每台服务器的配置,安装的业务应用等不同,其处理能力也不一样。所以,我们根据服务器的不同处理能力,给每个服务器分配不同的权值,使其能接受相应权指数的服务请求。
1.权重轮询调度算法流程
假设有一组服务器S = {S0, S1, …, Sn-1},W(Si)表示服务器Si的权值,一个指示变量i表示上一次选择的服务器,指示变量cw表示当前调度的权值,max(S)表示集合S中所有服务器的最大权值,gcd(S)表示集合S中所有服务器权值的最大公约数。变量i初始化为-1,cw初始化为零。其算法如下
while (true) {
i = (i + 1) mod n;
if (i == 0) {
cw = cw - gcd(S);
if (cw <= 0) {
cw = max(S);
if (cw == 0)
return NULL;
}
}
if (W(Si) >= cw)
return Si;
}
java代码实现:
Server
package com.taotao.xuexi.lunxun;
public class Server {
private String ip;
private int weight;
public Server(String ip, int weight) {
this.ip = ip;
this.weight = weight;
}
public String getIp() {
return ip;
}
public Server setIp(String ip) {
this.ip = ip;
return this;
}
public int getWeight() {
return weight;
}
public Server setWeight(int weight) {
this.weight = weight;
return this;
}
}
WeightRoundRobin
package com.taotao.xuexi.lunxun;
import java.util.ArrayList;
import java.util.List;
/**
* 权重轮训调度
*/
public class WeightRoundRobin {
/***
* 上次选中的服务器
*/
private int currentIndex = -1;
//当前调度的权值
private int currentWeight = 0;
//最大权重
private int maxWeight;
//权重最大的公约数
private int gcdWeight;
//服务器数
private int serverCout;
private List<Server> servers = new ArrayList<Server>();
/**
* 保持2值最大的公约数
*/
public int greaterCommonDivisor(int a, int b) {
if (a % b == 0) {
return b;
} else {
return greaterCommonDivisor(b, a % b);
}
}
/**
* 得到list 中所有权重的最大公约数吗,实际上俩俩取最大公约数d ,然后得到d d
* 与下一个权重取最大公约数,直到遍历完
*/
public int greaterCommonDivisor(List<Server> servers) {
int divisor = 0;
for (int index = 0, len = servers.size(); index < len - 1; index++) {
if (index == 0) {
divisor = greaterCommonDivisor(
servers.get(index).getWeight(), servers.get(index + 1).getWeight());
} else {
divisor = greaterCommonDivisor(divisor, servers.get(index).getWeight());
}
}
return divisor;
}
/**
* 得到list中的最大权重
*
* @param servers
* @return
*/
public int greatestWeight(List<Server> servers) {
int weight = 0;
for (Server server : servers) {
if (weight < server.getWeight()) {
weight = server.getWeight();
}
}
return weight;
}
/***
* 算法流程
* 假设有一组服务器 s={s0,s1,s2};
* 有相应的权重,变量currentIndex 表示上次选择的服务器
* 权值currentWeight初始化为0,currentIndex初始化为-1,当第一次的时候返回权值最大的
* 通过权重的不断递减 寻找 合适的服务器返回
* @return
*/
public Server getServer() {
while (true) {
currentIndex = (currentIndex + 1) % serverCout;
if (currentIndex == 0) {
currentWeight = currentWeight - gcdWeight;
if (currentWeight <= 0) {
currentWeight = maxWeight;
if (currentWeight == 0) {
return null;
}
}
}
if (servers.get(currentIndex).getWeight() >= currentWeight) {
return servers.get(currentIndex);
}
}
}
public void init() {
servers.add(new Server("192.168.191.1", 1));
servers.add(new Server("192.168.191.2", 2));
servers.add(new Server("192.168.191.4", 4));
servers.add(new Server("192.168.191.8", 8));
maxWeight = greatestWeight(servers);
gcdWeight = greaterCommonDivisor(servers);
serverCout = servers.size();
}
public static void main(String[] args) {
WeightRoundRobin weightRoundRobin =new WeightRoundRobin();
weightRoundRobin.init();
for (int i = 0; i <15 ; i++) {
Server server=weightRoundRobin.getServer();
System.out.println("server"+server.getIp()+"weight="+server.getWeight());
}
}
}