数据库查询负载均衡

时间:2015-05-07 20:49:21

标签: sql sql-server algorithm load-balancing

我有几个应用程序针对多个SQL Server数据库运行相同查询的实例。有一个手动负载平衡机制:每个实例都使用一种算法来确定在给定时间查询哪个服务器。

查询的处理时间以及服务器上的资源消耗量根据输入参数的不同而有很大差异,每次触发查询时输入参数都不同。

平衡算法的当前实现有时会导致其中一个服务器最终成为几个" long / heavy"的目标。查询,而其他服务器未被充分利用。

如我所知,如果查询很重,我怎么能改进算法以防止服务器过载?

现在每个应用程序实例决定如何彼此独立地进行平衡,所以我想我应该在所有实例之间共享负载信息,对吗?

谢谢!

1 个答案:

答案 0 :(得分:4)

回答自己:

最初,我一直在寻找能够实现不同类型的平衡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();
}