带有权重的服务器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)>元素 ...
随机推荐
- memcached整理の分布式集群算法
memcached如何实现分布式? memcached是一个“分布式内存对象缓存系统”,然而memcached并不像mongodb那样,允许配置多个节点,且节点之间“自动分配数据”,就是说memcac ...
- js 格式化时间
//格式化时间 function time_format(time) { return new Date(parseInt(time) * 1000).toLocaleString().replace ...
- [原创] 改善 Firemonkey Canvas 几何绘图质量问题(移动平台)
说明: Fiiremonkey 的跨平台能力,大家有目共睹(一码同介面跨四平台),唯独移动平台在几何绘图方面,质量始终不尽人意,我也曾试着去修正(如:修正曲线平滑问题),也曾找过第三方案(如:AggP ...
- shiro中移除jsessionid的解决方案
在web.xml配置文件中设置 <session-config> <!-- Disables URL-based sessions (no more 'jsessionid' in ...
- RobotFramework的Setup和Teardown
测试套件级别的Setup会在本套件测试用例集合执行前先执行,同理Teardown会在本组所有用例执行完成后运行 测试用例级别的Setup会在本条测试用例执行前先执行,同理Teardown会在本条用例执 ...
- swoft| 源码解读系列一: 好难! swoft demo 都跑不起来怎么破? docker 了解一下呗~
title: swoft| 源码解读系列一: 好难! swoft demo 都跑不起来怎么破? docker 了解一下呗~description: 阅读 sowft 框架源码, swoft 第一步, ...
- php从文本读入数据,处理结果再导入到文本
1,php从文本逐行读入数据,保存到数据组.使用fopen读取文本内容,逐行读取文本是$majorId = trim(fgets($rfile, 4096));. $rfile = fopen(&qu ...
- 简易 PHP 教程小记
一.简介: 1.用处广 2.免费 3.PHP Hypertext Preprocessor 二.语法: 1.<?php coders ?> 2.注释:"#" " ...
- mybatis的CRUD实例(四)
接下来我们来实现新增用户功能: 一.新增用户 这里我们使用的sql为:insert into user(username,birthday,sex,address) values ("lwj ...
- 洛谷 P2053 [SCOI2007]修车(最小费用最大流)
题解 最小费用最大流 n和m是反着的 首先, \[ ans = \sum{cost[i][j]}*k \] 其中,\(k\)为它在当前技术人员那里,排倒数第\(k\)个修 我们可以对于每个技术人员进行 ...