前言
负载均衡,大家应该听的也不少了,也实践过N次了。
当然也会知道,负载均衡是有不少算法的:随机,轮询,加权轮询,最少连接。。。。
本文重点说的是轮询。
先举个例子看看轮询算法是如何运作的。
假设我们的API站点有3台负载(10.0.10.1,10.0.10.2和10.0.10.3),客户端第一次请求API的时候,会访问.1拿到结果,第二次会访问.2拿到结果,第三次则会访问.3拿到结果,后面就是依次类推。
在致就是这个样子的访问顺序。
.1->.2->.3>.1>.2......
当然,上面的情况是太太太理想了!!只是能帮助我们理解轮询是怎么一回事!
下面是比较官方的描述:
按顺序把每个新的连接请求分配给下一个服务器,最终把所有请求平分给所有的服务器。
下面来简单看看如何实现
简单实现
我们围绕的重点如下:
- 服务器列表
- 上一次访问的是那台机器
- 下一次要访问的是那台机器
下面是实现
public class RoundRobin<T>
{
//服务器列表
private readonly IList<T> _items;
//锁
private readonly object _syncLock = new object();
//当前访问的服务器索引,开始是-1,因为没有人访问
private int _currentIndex = -1;
public RoundRobin(IEnumerable<T> sequence)
{
_items = sequence.ToList();
if(_items.Count <= 0 )
{
throw new ArgumentException("Sequence contains no elements.", nameof(sequence));
}
}
public T GetNextItem()
{
lock (this._syncLock)
{
_currentIndex++;
//超过数量,索引归0
if (_currentIndex >= _items.Count)
_currentIndex = 0;
return _items[_currentIndex];
}
}
}
根据用户不同的设计,服务器有可能是一个字符串,也有可能是自定义的一个类,所以设计成泛型参数会比较合适。
下面测试一下
static void Main(string[] args)
{
//负载的api地址
var lbUrls = new List<string>
{
"http://10.0.10.1/api/values",
"http://10.0.10.2/api/values",
"http://10.0.10.3/api/values",
"http://10.0.10.4/api/values",
};
//构造轮询的对象
var robin = new RoundRobin<string>(lbUrls);
//访问次数
var visitCount = lbUrls.Count * new Random().Next(3, 5);
//常规的情况
Console.WriteLine("begin one by one..");
for (int i = 0; i < visitCount; i++)
{
Console.WriteLine($"{i + 1}:Sending request to {robin.GetNextItem()}");
}
//并行的情况
Console.WriteLine("begin parallel..");
Parallel.For(0, visitCount, i =>
{
Console.WriteLine($"{i + 1}:Sending request to {robin.GetNextItem()}");
});
Console.ReadKey();
}
结果:
示例代码: