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的实现的更多相关文章

  1. iOS:搭建本地的服务器

    一.介绍 作为一个专业的程序员,不管你是前端还是移动端或者是后台,能够自己试着搭建一个本地的服务器还是很有必要的,有的时候,我们可以自己测试一些数据,很方便开发.其实,mac是自带有本地的服务器的,用 ...

  2. 搭建一个三台服务器的Memcached集群

    关于memcached的基础知识可以查看博客其他博文,这里只记录了搭建的过程,谢谢! 1.分别在三台服务器上安装Memcached并启动 第一.由于memcached是基于libevent的事件处理, ...

  3. [link] 构建负载均衡服务器之一 负载均衡与集群详解

    一.什么是负载均衡 首先我们先介绍一下什么是负载均衡: 负载平衡(Load balancing)是一种计算机网络技术,用来在多个计算机(计算机集群).网络连接.CPU.磁盘驱动器或其他资源中分配负载, ...

  4. CentOS FTP服务器系统套件全面讲解

    对大家推荐很好使用的CentOS FTP系统,像让大家对CentOS FTP系统有所了解,然后对CentOS FTP系统全面讲解介绍,希望对大家有用. 1.vsFTPd,目前常用CentOS FTP服 ...

  5. [ntp]查看ntp服务器的连接情况

    转自:http://www.cnblogs.com/liuyou/archive/2012/07/29/2614338.html 命令和工具 # watch ntpq -p # ntpq -p, /e ...

  6. 发生在阿里云 SLB 4 层的一次故障记录

    阿里云 SLB 与 ECS 之间发生故事.环境如下: SLB api-node: 该 SLB 后端接着 10 台节点服务器 SLB sql-node: 该 SLB 后端接着 2 台节点服务器 问题描述 ...

  7. Vert.x HTTP 服务器与客户端

    编写HTTP 服务器与客户端 Vert.x让编写非阻塞的HTTP 服务器与客户端变得非常轻松. 创建HTTP 服务器 缺省状况: HttpServer server = vertx.createHtt ...

  8. vnc服务器和windows2012密钥

    [root@localhost ~]# vncserver #启动服务器 windows 2012 64位-server版本的密钥 Windows Server 2012 Standard 密钥:NB ...

  9. Css3 权重

    Css权重 权重--很多规则应用到同一个元素上时,权重是决定哪个生效的(优先级) 权重等级与权值 行内样式(1000)>ID选择器(100)>类.属性选择器或伪类选择器(10)>元素 ...

随机推荐

  1. cenos7切换阿里源

    备份并安装base reop源 cd /etc/yum.repos.d sudo mv CentOS-Base.repo CentOS-Base.repo.bak 下载阿里源并配置 sudo wget ...

  2. Android开发环境包下载地址

    Android SDK Android NDK Android Studio 官方下载地址   (网上转来的) 如果下载速度很慢或者无法下载,有三种解决方法 1.忍耐. 2.使用P2SP下载工具,比如 ...

  3. /Date(1512551901709+0800)/转换

    var convertDT=function(dt) { dt.replace(/Date\([\d+]+\)/, function (a) { eval('d = new ' + a) }); al ...

  4. ASP 缓存处理及URL 重写

    1 缓存 1.1.1 <%--通过设置VaryByParam =" VaryByParam ="none" %> 1.1.2 <%--带参数缓存,只要包 ...

  5. ORM概述及常用ORM框架

    一.ORM ORM(Object-relational mapping),即对象关系映射,是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术.也就是说,ORM是通过使用描述对象和数据库之间映 ...

  6. 《Beginning Java 7》 - 1 - Initializer 初始化器

    Initializer 分两类:class initializer 类初始化器   instance initializer 实例初始化器 1. class initializer,在编译时运行,通过 ...

  7. BZOJ2430 chocolate

    有一个显然的想法是因为最后要花分成n*m个小块,所以每条边一定是要被切开的. 所以直接排序就可以了qwq,按照代价从大到小切一定是最优的. #include<iostream> #incl ...

  8. 201621123012《Java程序设计》第12次学习总结

    作业12-流与文件 1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多流与文件相关内容. 2. 面向系统综合设计-图书馆管理系统或购物车 使用流与文件改造你的图书馆管理系统或购物车 ...

  9. 得到windows聚焦图片(windows 10)

    有些Windows聚焦图片确实很漂亮,很希望保留下来,但是Windows聚焦图片总更好,网上有得到聚焦图片的方法,每次都手动去弄真麻烦,于是自己编了一个小程序,自动得到Windows聚焦图片,下面是运 ...

  10. 小记一次shellscript的麻烦

    小记一次shellscript的麻烦 一.起因: 之前写过篇文章 文本分析实例 ,大致的内容就是对 "nginx的web服务器进行日志分析,删除不被访问的截图". 点我打开哔哩哔哩 ...