数据库查询负载均衡
Database query load balancing
我有一个应用程序的多个实例 运行 针对多个 SQL 服务器数据库的相同查询。有一个手动负载平衡机制:每个实例使用一种算法来不对称地决定在给定时间查询哪个服务器。
查询的处理时间,以及服务器上的资源消耗,根据每次触发查询时不同的输入参数而有很大差异。
平衡算法的当前实施有时会导致其中一台服务器最终成为多个 "long/heavy" 查询的目标,而其他服务器未得到充分利用。
据我所知,如果查询很繁重,我该如何改进算法以防止服务器过载?
现在每个应用程序实例决定如何相互独立地进行平衡,所以我想我应该在所有实例之间共享负载信息,对吗?
谢谢!
自己回答:
最初,我一直在寻找能够实现不同类型平衡的东西 http://www.peplink.com/technology/load-balancing-algorithms/,
即使我找到了一篇不错的文章 http://www.codeproject.com/Articles/3338/NET-Dynamic-Software-Load-Balancing
最后我决定保持简单,因为我知道请求的权重 我将只收取较少费用的服务器。
编辑: 为每个服务器添加了基础权重。现在平衡是通过重量和负载来完成的。代码可以在linqpad
中测试
// Define other methods and classes here
public class LoadBalancer{
class Server{
public long Weight{ get; set;}
public long Load{ get; set;}
public string ConnectionString{ get; set;}
public long RequestCount;
// Return a weight based on the Load
public long CurrentWeight {
get{
var w = Weight - Load;
return w <= 0 ? 1: w;
}
}
}
List<Server> Servers;
public LoadBalancer(){
Servers = new List<Server>();
}
public void AddServer(long weight, string connection){
lock(Servers)
Servers.Add(new UserQuery.LoadBalancer.Server(){ ConnectionString = connection, Weight = weight });
}
static Random rnd = new Random();
// Returns server with less load
public string GetServer(int expectedLoad){
var hit = rnd.Next(0, (int)Servers.Sum(s => s.CurrentWeight));
long acc = 0;
foreach(var server in Servers){
if(hit < server.CurrentWeight + acc){
// Update load
lock(server){
server.Load += expectedLoad;
server.RequestCount++;
}
return server.ConnectionString;
}
acc += server.CurrentWeight;
}
throw new Exception("No servers available");
}
public void ReleaseServer(string conn, int expectedLoad){
var server = Servers.First(s => s.ConnectionString == conn);
// Update load
lock(server){
server.Load -= expectedLoad;
server.RequestCount--;
}
}
public IEnumerable<string> Dump(){
return Servers.Select(s => string.Format("Server: {0}, Requests: {1}, Weight: {2}, CurrentWeight: {3}",
s.ConnectionString, s.RequestCount, s.Weight, s.CurrentWeight));
}
}
void Main()
{
var balancer = new LoadBalancer();
// Add servers
balancer.AddServer(100, "Server1");
balancer.AddServer(100, "Server2");
balancer.AddServer(800, "Server3");
balancer.AddServer(200, "Server4");
balancer.AddServer(1000, "Server5");
var rnd = new Random();
var servers = new List<dynamic>();
Enumerable.Range(0, 100)
.All(i => {
var load = rnd.Next(1, 10);
var server = balancer.GetServer(load);
servers.Add(new {Server = server, Load = load});
if(i % 10 == 0){
balancer.Dump().Dump();
// Remove some load
var items = rnd.Next(0, servers.Count);
servers.Take(items)
.All(s => {
balancer.ReleaseServer(s.Server, s.Load);
return true;
});
servers = servers.Skip(items).ToList();
}
return true;
});
servers.All(s => {
balancer.ReleaseServer(s.Server, s.Load);
return true;
});
balancer.Dump().Dump();
}
我有一个应用程序的多个实例 运行 针对多个 SQL 服务器数据库的相同查询。有一个手动负载平衡机制:每个实例使用一种算法来不对称地决定在给定时间查询哪个服务器。
查询的处理时间,以及服务器上的资源消耗,根据每次触发查询时不同的输入参数而有很大差异。
平衡算法的当前实施有时会导致其中一台服务器最终成为多个 "long/heavy" 查询的目标,而其他服务器未得到充分利用。
据我所知,如果查询很繁重,我该如何改进算法以防止服务器过载?
现在每个应用程序实例决定如何相互独立地进行平衡,所以我想我应该在所有实例之间共享负载信息,对吗?
谢谢!
自己回答:
最初,我一直在寻找能够实现不同类型平衡的东西 http://www.peplink.com/technology/load-balancing-algorithms/, 即使我找到了一篇不错的文章 http://www.codeproject.com/Articles/3338/NET-Dynamic-Software-Load-Balancing
最后我决定保持简单,因为我知道请求的权重 我将只收取较少费用的服务器。 编辑: 为每个服务器添加了基础权重。现在平衡是通过重量和负载来完成的。代码可以在linqpad
中测试// Define other methods and classes here
public class LoadBalancer{
class Server{
public long Weight{ get; set;}
public long Load{ get; set;}
public string ConnectionString{ get; set;}
public long RequestCount;
// Return a weight based on the Load
public long CurrentWeight {
get{
var w = Weight - Load;
return w <= 0 ? 1: w;
}
}
}
List<Server> Servers;
public LoadBalancer(){
Servers = new List<Server>();
}
public void AddServer(long weight, string connection){
lock(Servers)
Servers.Add(new UserQuery.LoadBalancer.Server(){ ConnectionString = connection, Weight = weight });
}
static Random rnd = new Random();
// Returns server with less load
public string GetServer(int expectedLoad){
var hit = rnd.Next(0, (int)Servers.Sum(s => s.CurrentWeight));
long acc = 0;
foreach(var server in Servers){
if(hit < server.CurrentWeight + acc){
// Update load
lock(server){
server.Load += expectedLoad;
server.RequestCount++;
}
return server.ConnectionString;
}
acc += server.CurrentWeight;
}
throw new Exception("No servers available");
}
public void ReleaseServer(string conn, int expectedLoad){
var server = Servers.First(s => s.ConnectionString == conn);
// Update load
lock(server){
server.Load -= expectedLoad;
server.RequestCount--;
}
}
public IEnumerable<string> Dump(){
return Servers.Select(s => string.Format("Server: {0}, Requests: {1}, Weight: {2}, CurrentWeight: {3}",
s.ConnectionString, s.RequestCount, s.Weight, s.CurrentWeight));
}
}
void Main()
{
var balancer = new LoadBalancer();
// Add servers
balancer.AddServer(100, "Server1");
balancer.AddServer(100, "Server2");
balancer.AddServer(800, "Server3");
balancer.AddServer(200, "Server4");
balancer.AddServer(1000, "Server5");
var rnd = new Random();
var servers = new List<dynamic>();
Enumerable.Range(0, 100)
.All(i => {
var load = rnd.Next(1, 10);
var server = balancer.GetServer(load);
servers.Add(new {Server = server, Load = load});
if(i % 10 == 0){
balancer.Dump().Dump();
// Remove some load
var items = rnd.Next(0, servers.Count);
servers.Take(items)
.All(s => {
balancer.ReleaseServer(s.Server, s.Load);
return true;
});
servers = servers.Skip(items).ToList();
}
return true;
});
servers.All(s => {
balancer.ReleaseServer(s.Server, s.Load);
return true;
});
balancer.Dump().Dump();
}