带有权重的服务器SLB的实现
1)参考了网络上的算法,但是那个算法仅仅是用于展示“权重轮循”的意图,在真正的网络下,因为是并行的,所以不可能单纯一个简单的循环可以解决问题。
2)用lock的话性能显然有损失。
3)想了一阵,结合CAS和volatile等细粒度的锁的方式,一个真正可以用软件描述SLB带有权重的算法大概是这个样子(如下):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading; namespace WBasedRobin
{
/// <summary>
/// 用于计算WeightRobin的数据结构
/// </summary>
public class WeightedRobin
{
private readonly int _weight;
private int _count;
/// <summary>
/// 命中次数(累加)
/// </summary>
public int ChoosenCount
{
get
{
return ++_count;
}
}
/// <summary>
/// 权重
/// </summary>
public int Weight
{
get
{
return _weight;
}
}
/// <summary>
/// 输出当前的权重
/// </summary>
public override string ToString()
{
return "Weight:" + Weight.ToString() + "\tCount:" + _count.ToString();
}
/// <summary>
/// 初始化每一个Server的内部值
/// </summary>
public WeightedRobin(int weight, int count = )
{
_weight = weight;
_count = count;
}
} public class WeightRobinRule
{
private List<WeightedRobin> _servers = null; private volatile int _index = -;
private volatile int _currentWeight = ;
private volatile bool _isServerChanging = false; private volatile int _maxWeight = ;
private volatile int _gcdWeight = ; private int GetMaxWeight(IEnumerable<WeightedRobin> weights)
{
return weights.Max(w => w.Weight);
} private int GetGCDWeight(int big, int small)
{
if (big < small)
{
big ^= small;
small ^= big;
big ^= small;
} if (big % small == )
{
return small;
}
return GetGCDWeight(small, big % small);
} private int GetTotalGCD()
{
int gcd = GetGCDWeight(_servers[].Weight, _servers[].Weight); for (int i = ; i < _servers.Count; ++i)
{
gcd = GetGCDWeight(gcd, _servers[i].Weight);
} return gcd;
} /// <summary>
/// 初始化权重服务器,至少2台服务器。
/// </summary>
public WeightRobinRule(int totalServers = )
{
Random r = new Random();
_servers = new List<WeightedRobin>(totalServers); for (int i = ; i < totalServers; i++)
{
_servers.Add(new WeightedRobin(r.Next(, totalServers+),));
}
_maxWeight = GetMaxWeight(_servers);
_gcdWeight = GetTotalGCD();
} public void DoRolling()
{
int copyIndex = ;
int copyIndexNext = ;
int copycw = ; //当服务器数量发生变化的时候,锁住该服务直到完毕。
reloop: while (_isServerChanging) ; for (;;)
{
//拷贝本地的index,用做同步
copyIndex = _index;
//计算轮询的时候下一个的值
copyIndexNext = (copyIndex + ) % _servers.Count;
//同步作用
copycw = _currentWeight; //假定轮询后的Next=0,说明完成一轮轮询,权重减去最大公约数
if (copyIndexNext == )
{
copycw -= _gcdWeight; //如果权重已经扣完,重新从大的开始
if (copycw <= )
{
copycw = _maxWeight;
}
} //如果copyIndex和_index相同,说明是同一个线程抢到的,那么直接用本地的替换index进行替换
if (Interlocked.CompareExchange(ref _index, copyIndexNext, copyIndex) == copyIndex)
{
_currentWeight = copycw; try
{
//如果轮询的权重大于等于本地权重,选中它即可。
if (_servers[copyIndexNext].Weight >= copycw)
{
int t = _servers[copyIndexNext].ChoosenCount;
break;
}
}
//如果是Index溢出,那么说明服务器数量肯定发生变化了,所以跳过此次轮询,等下一轮,不处理。
catch (IndexOutOfRangeException)
{
goto reloop;
} }
}
}
/// <summary>
/// 移除指定的服务器
/// </summary>
public WeightedRobin RemoveByIndex(int index)
{
_isServerChanging = true;
var removedServer = _servers[index];
_servers.RemoveAt(index);
_gcdWeight = GetTotalGCD();
_maxWeight = GetMaxWeight(_servers);
_isServerChanging = false;
return removedServer;
}
/// <summary>
/// 增加新的服务器
/// </summary>
public void AddNewServer(int weight)
{
_isServerChanging = true;
_servers.Add(new WeightedRobin(weight, ));
_gcdWeight = GetTotalGCD();
_maxWeight = GetMaxWeight(_servers);
_isServerChanging = false;
}
/// <summary>
/// 格式化输出结果
/// </summary>
public override string ToString()
{
StringBuilder sbu = new StringBuilder(); foreach (WeightedRobin wr in _servers)
{
sbu.AppendLine(wr.ToString() + Environment.NewLine);
}
return sbu.ToString();
}
}
}
调用测试代码如下:
using System;
using System.Threading;
using System.Threading.Tasks; namespace WBasedRobin
{
class Program
{
static Random r = new Random(); static void Rounding(WeightRobinRule wr)
{
wr.DoRolling();
}
static void Main(string[] args)
{
WeightRobinRule wr = new WeightRobinRule(); Timer t = new Timer((j) => { var removedS = wr.RemoveByIndex(); Console.WriteLine("移除了服务器:"+removedS); }, null, , Timeout.Infinite); t = new Timer((o) => { wr.AddNewServer(); Console.WriteLine("新增加服务器了。"); }, null, , Timeout.Infinite); Parallel.For(, , (num) =>
{
Thread.Sleep(r.Next(, ));
Rounding(wr);
});
Console.WriteLine(wr);
Console.ReadLine();
}
}
}
带有权重的服务器SLB的实现的更多相关文章
- iOS:搭建本地的服务器
一.介绍 作为一个专业的程序员,不管你是前端还是移动端或者是后台,能够自己试着搭建一个本地的服务器还是很有必要的,有的时候,我们可以自己测试一些数据,很方便开发.其实,mac是自带有本地的服务器的,用 ...
- 搭建一个三台服务器的Memcached集群
关于memcached的基础知识可以查看博客其他博文,这里只记录了搭建的过程,谢谢! 1.分别在三台服务器上安装Memcached并启动 第一.由于memcached是基于libevent的事件处理, ...
- [link] 构建负载均衡服务器之一 负载均衡与集群详解
一.什么是负载均衡 首先我们先介绍一下什么是负载均衡: 负载平衡(Load balancing)是一种计算机网络技术,用来在多个计算机(计算机集群).网络连接.CPU.磁盘驱动器或其他资源中分配负载, ...
- CentOS FTP服务器系统套件全面讲解
对大家推荐很好使用的CentOS FTP系统,像让大家对CentOS FTP系统有所了解,然后对CentOS FTP系统全面讲解介绍,希望对大家有用. 1.vsFTPd,目前常用CentOS FTP服 ...
- [ntp]查看ntp服务器的连接情况
转自:http://www.cnblogs.com/liuyou/archive/2012/07/29/2614338.html 命令和工具 # watch ntpq -p # ntpq -p, /e ...
- 发生在阿里云 SLB 4 层的一次故障记录
阿里云 SLB 与 ECS 之间发生故事.环境如下: SLB api-node: 该 SLB 后端接着 10 台节点服务器 SLB sql-node: 该 SLB 后端接着 2 台节点服务器 问题描述 ...
- Vert.x HTTP 服务器与客户端
编写HTTP 服务器与客户端 Vert.x让编写非阻塞的HTTP 服务器与客户端变得非常轻松. 创建HTTP 服务器 缺省状况: HttpServer server = vertx.createHtt ...
- vnc服务器和windows2012密钥
[root@localhost ~]# vncserver #启动服务器 windows 2012 64位-server版本的密钥 Windows Server 2012 Standard 密钥:NB ...
- Css3 权重
Css权重 权重--很多规则应用到同一个元素上时,权重是决定哪个生效的(优先级) 权重等级与权值 行内样式(1000)>ID选择器(100)>类.属性选择器或伪类选择器(10)>元素 ...
随机推荐
- vim command
问题:对多行缩进 简述:向左缩是<,向右缩是> 详述:在命令状态,按v进入visual状态,选中多行,再按>,相当于一个TAB键:再选中多行,按<试试 ------------ ...
- C# 调用带输入输出参数的存储过程
//调用存储过程执行类似于2//select count(*) from userinfo where username=username and pwd=pwd and grade=grade3// ...
- delphi弹出选择对话框选择目录|SelectDirectory 函数(转)
SelectDirectory 函数 通过显示一个对话框来让用户选择一个目录.注意:在使用前要在Uses 语句中添加包含FileCtrl 的说明.函数原型如下:function SelectDirec ...
- xml构建
<a target="_blank" href="http://wpa.qq.com/msgrd?v=3&uin=346252320&site=qq ...
- mysql group by 详解
GROUP BY X意思是将所有具有相同X字段值的记录放到一个分组里. 那么GROUP BY X, Y呢? GROUP BY X, Y意思是将所有具有相同X字段值和Y字段值的记录放到一个分组里.
- 【项目总结】扯一扯电商网站前端css的整体架构设计(1)
最近半忙不忙的写了一个外包网站,网站主要功能是艺术品竞拍和艺术衍生品的销售.工程已经完成了80%左右,现在前后端代码量已经50W行左右,我主要负责的是前端设计和前端布局.下面就先放一个网站的设计图吧, ...
- Django 标签过滤器
django内置标签 autoescape 控制当前的自动转义行为.这个标记可以作为参数打开或关闭,它决定自动转义是否在块内有效.块使用endautoescape结束标记关闭. 当自动转义生效时,所有 ...
- IO模型《五》异步IO
Linux下的asynchronous IO其实用得不多,从内核2.6版本才开始引入.先看一下它的流程: 用户进程发起read操作之后,立刻就可以开始去做其它的事.而另一方面,从kernel的角度,当 ...
- “全栈2019”Java第六十四章:接口与静态方法详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...
- Leetcode 856. Score of Parentheses 括号得分(栈)
Leetcode 856. Score of Parentheses 括号得分(栈) 题目描述 字符串S包含平衡的括号(即左右必定匹配),使用下面的规则计算得分 () 得1分 AB 得A+B的分,比如 ...