负载均衡之权重轮询调度算法
一、负载均衡
nginx不单可以作为强大的web服务器,也可以作为一个反向代理服务器。如果nginx是以反向代理的形式配置运行,那么对请求的实际处理需要转发到后端服务器运行,如果后端服务器有多台,如何选择一台合适的后端服务器来处理当前请求,这就是负载均衡
二、nginx负载均衡策略之round_robin
round_robin策略做为默认策略:每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器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在用作反向代理服务器时,对于后端的服务器可以采用两种分流策略:加权分流和ip hash。nginx默认采用round_robin加权算法:对于权重较高的机器,被选中的概率大,对于权重相同的机器,则采用轮询方式。上面的这个配置,如果的3个请求,则会有1个请求分发到10.1.1.107服务器上,2个请求分发到10.1.1.132服务器上。
三、轮询调度算法(Round-Robin Scheduling)
轮询调度算法的原理是每一次把来自用户的请求轮流分配给内部中的服务器,从1开始,直到N(内部服务器个数),然后重新开始循环。
轮询调度算法假设所有服务器的处理性能都相同,不关心每台服务器的当前连接数和响应速度。当请求服务间隔时间变化比较大时,轮询调度算法容易导致服务器间的负载不平衡。所以此种均衡算法适合于服务器组中的所有服务器都有相同的软硬件配置并且平均服务请求相对均衡的情况。
四、权重轮询调度算法(Weighted 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;
}
2.Java代码实现
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 serverCount;
private List servers = new ArrayList();
/*
* 得到两值的最大公约数
*/
public int greaterCommonDivisor(int a, int b){
if(a % b == 0){
return b;
}else{
return greaterCommonDivisor(b,a % b);
}
}
/*
* 得到list中所有权重的最大公约数,实际上是两两取最大公约数d,然后得到的d
* 与下一个权重取最大公约数,直至遍历完
*/
public int greatestCommonDivisor(List 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中的最大的权重
*/
public int greatestWeight(List servers){
int weight = 0;
for(Server server : servers){
if(weight < server.getWeight()){
weight = server.getWeight();
}
}
return weight;
}
/**
* 算法流程:
* 假设有一组服务器 S = {S0, S1, …, Sn-1}
* 有相应的权重,变量currentIndex表示上次选择的服务器
* 权值currentWeight初始化为0,currentIndex初始化为-1 ,当第一次的时候返回 权值取最大的那个服务器,
* 通过权重的不断递减 寻找 适合的服务器返回
*/
public Server getServer(){
while(true){
currentIndex = (currentIndex + 1) % serverCount;
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 = greatestCommonDivisor(servers);
serverCount = 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());
}
}
}
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 void setIp(String ip) {
this.ip = ip;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
}
运行结果:
server 192.168.191.8 weight=8
server 192.168.191.8 weight=8
server 192.168.191.8 weight=8
server 192.168.191.8 weight=8
server 192.168.191.4 weight=4
server 192.168.191.8 weight=8
server 192.168.191.4 weight=4
server 192.168.191.8 weight=8
server 192.168.191.2 weight=2
server 192.168.191.4 weight=4
server 192.168.191.8 weight=8
server 192.168.191.1 weight=1
server 192.168.191.2 weight=2
server 192.168.191.4 weight=4
server 192.168.191.8 weight=8