数据库查询负载均衡

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();
}