详解.NET中负载均衡的使用

 更新时间:2022年06月24日 09:59:27   作者:​ 菜鸟厚非   ​  
这篇文章主要介绍了详解.NET中负载均衡的使用,负载均衡即LB,就是将并发的用户请求通过规则后平衡、分摊到多台服务器上进行执行,以此达到压力分摊、数据并行的效果

一、简介

负载均衡(Load Balance),简称 LB,就是将并发的用户请求通过规则后平衡、分摊到多台服务器上进行执行,以此达到压力分摊、数据并行的效果。常见的算法也有许多随机、轮询、加权等,今天我们就使用 C# 来实现这几种算法,并讲解在实际项目中的使用。

二、应用场景

负载均衡算法在开发层面,使用场景其实并不多。通常在项目重构、转型、上线大版本新功能等,为了避免上线出现 Bug 应用功能 100% 的挂掉。可以在程序中使用负载均衡,将部分 HTTP 流量,打入项目中新的功能模块,然后进行监控,出现问题可以及时进行调整。

这样 AB 测试的场景,也可以在运维或者网关等其他层面实现流量分配。但现实是大多数公司项目因为一些原因没有这样的支持,这时开发就可以在项目中使用代码进行实现。

三、实际案例

有这样一个需求,电商系统中,有一个预估运费的微服务(ShippingCharge )。此时上面领导来了需求,预估运费要改版,开发预估了一下改动不小。经过两周的奋斗 ShippingCharge 需求终于开发测试好了,此时要上线,但是掐指一算,万一有问题不就死翘翘了,而且还和钱相关。

此时负载均衡算法就派上用场了,我们可以让 10% 的流量打入这次的改动,可以先进行监控,可以再全部切过来。实际项目中,使用的肯定是权重的,后面随机、轮询也简单进行介绍一下其实现。

假设在改动 ShippingCharge 时,没有修改旧的功能,是在 controller 下面,对 call business 层换成了这次需求的,这样我们就可以使用负载均衡,让 10% 的流量打入新的 business,其余的依然走老的 business。

四、算法实现

这里不会说的太精细,会将核心实现代码做介绍,实际项目中使用需要自己进行一下结合,举一反三哈

下面定义了一个 ServiceCenterModel 主要用作承载需要负载均衡的对象信息,可以是 call 下游的 url,也可以是程序内的某一算法标

4.1 随机

随机算法的先对来讲,较为简单一些,主要根据 Random 与 ServiceList 的数量结合实现。

如下:

/// <summary>
/// 随机
/// </summary>
public class RandomAlgorithm
{
    /// <summary>
    /// Random Function
    /// </summary>
    private static readonly Random random = new Random();

    /// <summary>
    /// serviceList
    /// </summary>
    /// <param name="serviceList">service url set</param>
    /// <returns></returns>
    public static string Get(List<ServiceCenterModel> serviceList)
    {
        if (serviceList == null)
            return null;

        if (serviceList.Count == 1)
            return serviceList[0].Service;

        // 返回一个小于所指定最大值的非负随机数
        int index = random.Next(serviceList.Count);

        string url = serviceList[index].Service;

        return url;
    }
}

模拟 10 次 http request,可以看到对OldBusiness、NewBusiness进行了随机的返回

public static void Main(string[] args)
{
    // 模拟从配置中心读取 Service 
    var serviceList = new List<ServiceCenterModel>()
    {
        new ServiceCenterModel { Service ="OldBusiness"},
        new ServiceCenterModel { Service ="NewBusiness"},
    };

    // 模拟 Http 请求次数
    for (int i = 0; i < 10; i++)
    {
        Console.WriteLine(RandomAlgorithm.Get(serviceList));
    }
}

4.2 轮询

轮询的实现思路,将每次读取 ServiceList 的 Index 放到静态全局变量中,当到 ServiceList 最后一个时从0开始读取。

如下:

/// <summary>
/// 轮询
/// </summary>
public class PollingAlgorithm
{
    private static Dictionary<string, int> _serviceDic = new Dictionary<string, int>();
    private static SpinLock _spinLock = new SpinLock();

    /// <summary>
    /// Get URL From Service List
    /// </summary>
    /// <param name="serviceList">Service URL Set</param>
    /// <param name="serviceName">Service Name</param>
    /// <returns></returns>
    public static string Get(List<ServiceCenterModel> serviceList, string serviceName)
    {
        if (serviceList == null || string.IsNullOrEmpty(serviceName))
            return null;

        if (serviceList.Count == 1)
            return serviceList[0].Service;

        bool locked = false;
        _spinLock.Enter(ref locked);//获取锁
        int index = -1;
        if (!_serviceDic.ContainsKey(serviceName)) // Not Exist
            _serviceDic.TryAdd(serviceName, index);
        else
            _serviceDic.TryGetValue(serviceName, out index);
        string url = string.Empty;
        ++index;
        if (index > serviceList.Count - 1) //当前索引 > 最新服务最大索引
        {
            index = 0;
            url = serviceList[0].Service;
        }
        else
        {
            url = serviceList[index].Service;
        }
        _serviceDic[serviceName] = index;

        if (locked) //释放锁
            _spinLock.Exit();

        return url;
    }
}

模拟 10 次 http request,可以看到对OldBusiness、NewBusiness进行了轮询返回

public static void Main(string[] args)
{
    // 模拟从配置中心读取 Service 
    var serviceList = new List<ServiceCenterModel>()
    {
        new ServiceCenterModel { Service ="OldBusiness"},
        new ServiceCenterModel { Service ="NewBusiness"},
    };

    // 模拟 Http 请求次数
    for (int i = 0; i < 10; i++)
    {
        Console.WriteLine(PollingAlgorithm.Get(serviceList, "ShippingChargeBusiness"));
    }
}

4.3 权重

权重的实现思路,将配置权重的 Service 按照数量放置在一个集合中,然后按照轮询的方式进行读取,需要注意的是这的 weight 只能配置大于 0 的整数。

如下:

/// <summary>
/// 权重
/// </summary>
public class WeightAlgorithm
{
    private static ConcurrentDictionary<string, WeightAlgorithmItem> _serviceDic = new ConcurrentDictionary<string, WeightAlgorithmItem>();
    private static SpinLock _spinLock = new SpinLock();

    public static string Get(List<ServiceCenterModel> serviceList, string serviceName)
    {
        if (serviceList == null)
            return null;

        if (serviceList.Count == 1)
            return serviceList[0].Service;

        bool locked = false;
        _spinLock.Enter(ref locked);//获取锁

        WeightAlgorithmItem weightAlgorithmItem = null;
        if (!_serviceDic.ContainsKey(serviceName))
        {
            weightAlgorithmItem = new WeightAlgorithmItem()
            {
                Index = -1,
                Urls = new List<string>()
            };
            BuildWeightAlgorithmItem(weightAlgorithmItem, serviceList);
            _serviceDic.TryAdd(serviceName, weightAlgorithmItem);
        }
        else
        {
            _serviceDic.TryGetValue(serviceName, out weightAlgorithmItem);
            weightAlgorithmItem.Urls.Clear();
            BuildWeightAlgorithmItem(weightAlgorithmItem, serviceList);
        }

        string url = string.Empty;
        ++weightAlgorithmItem.Index;
        if (weightAlgorithmItem.Index > weightAlgorithmItem.Urls.Count - 1) //当前索引 > 最新服务最大索引
        {
            weightAlgorithmItem.Index = 0;
            url = serviceList[0].Service;
        }
        else
        {
            url = weightAlgorithmItem.Urls[weightAlgorithmItem.Index];
        }
        _serviceDic[serviceName] = weightAlgorithmItem;

        if (locked) //释放锁
            _spinLock.Exit();

        return url;
    }

    private static void BuildWeightAlgorithmItem(WeightAlgorithmItem weightAlgorithmItem, List<ServiceCenterModel> serviceList)
    {
        serviceList.ForEach(service => //有几个权重就加几个实例
        {
            for (int i = 0; i < service.Weight; i++)
            {
                weightAlgorithmItem.Urls.Add(service.Service);
            }
        });
    }
}
public class WeightAlgorithmItem
{
    public List<string> Urls { get; set; }
    public int Index { get; set; }
}

模拟 10 次 http request,可以看到对 OldBusiness 返回了 9 次,NewBusiness 返回了一次

public static void Main(string[] args)
{
    // 模拟从配置中心读取 Service 
    var serviceList = new List<ServiceCenterModel>()
    {
        new ServiceCenterModel { Service ="OldBusiness",Weight = 9 },
        new ServiceCenterModel { Service ="NewBusiness",Weight = 1 },
    };

    // 模拟 Http 请求次数
    for (int i = 0; i < 10; i++)
    {
        Console.WriteLine(WeightAlgorithm.Get(serviceList, "ShippingChargeBusiness"));
    }
}

到此这篇关于详解.NET中负载均衡的使用的文章就介绍到这了,更多相关 .NET负载均衡 内容请搜索得牛网以前的文章或继续浏览下面的相关文章希望大家以后多多支持得牛网!

相关文章

  • ASP.NET中AJAX的异步加载(Demo演示)

    ASP.NET中AJAX的异步加载(Demo演示)

    这篇文章主要介绍了ASP.NET中AJAX的异步加载(Demo演示),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-05-05
  • asp .net实现给图片添加图片水印方法示例

    asp .net实现给图片添加图片水印方法示例

    图片上加水印相信每位程序员都会遇到这个需求,下面这篇文章主要给大家介绍了asp .net实现给图片添加图片水印的方法,文中给出了完整的实例代码,相信对大家具有一定的参考价值,需要的朋友们下面来一起看看吧。
    2017-03-03
  • 一步步做自己的webinstall安装包

    一步步做自己的webinstall安装包

    众所周知,在VS环境下自带的WEBINSTALL项目无法选择安装路径,这让很多开发者头痛不已。现提供一种办法供大家参考
    2012-10-10
  • asp.net 分页存储过程实例剖析心得

    asp.net 分页存储过程实例剖析心得

    最近修改了个分页存储过程,作为菜鸟,还是从中获益良多,这里就开始今天的分页之旅了
    2011-10-10
  • c# 执行事务函数代码

    c# 执行事务函数代码

    c#下 执行多条sql语句,实现事务
    2009-05-05
  • ASP.NET动态增加HTML元素的方法实例小结

    ASP.NET动态增加HTML元素的方法实例小结

    这篇文章主要介绍了ASP.NET动态增加HTML元素的方法,结合实例形式总结分析了asp.net针对样式、Meta、js等元素动态增加相关操作技巧,需要的朋友可以参考下
    2017-01-01
  • asp.net core MVC 过滤器之ActionFilter过滤器(2)

    asp.net core MVC 过滤器之ActionFilter过滤器(2)

    这篇文章主要为大家详细介绍了asp.net core MVC过滤器之ActionFilter过滤器,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-08-08
  • ASP.NET Core利用Jaeger实现分布式追踪详解

    ASP.NET Core利用Jaeger实现分布式追踪详解

    这篇文章主要给大家介绍了关于ASP.NET Core利用Jaeger实现分布式追踪的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用ASP.NET Core具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-04-04
  • ASP.NET Core 配置和使用环境变量的实现

    ASP.NET Core 配置和使用环境变量的实现

    这篇文章主要介绍了ASP.NET Core 配置和使用环境变量的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-08-08
  • .NET5控制台程序使用EF连接MYSQL数据库的方法

    .NET5控制台程序使用EF连接MYSQL数据库的方法

    这篇文章主要介绍了.NET5控制台程序使用EF连接MYSQL数据库,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-08-08

最新评论