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

目录
  • 一、简介
  • 二、应用场景
  • 三、实际案例
  • 四、算法实现
    • 4.1 随机
    • 4.2 轮询
    • 4.3 权重

一、简介

负载均衡(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负载均衡 内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • .Net Core + Nginx实现项目负载均衡的全步骤

    nginx大家如果没用过那或多或少都应该听过,vue的部署.反向代理.负载均衡nginx都能帮你做到. 今天主要说一下nginx负载均衡我们的项目,如下图所示,请求到达nginx,nginx再帮我们转发. 首先使用Docker安装nginx. docker pull nginx:latest 运行容器,将本地的8080端口映射到容器内部的 80 端口. docker run --name nginx -p 8080:80 -d nginx 查看nginx容器,如果有错请看日志. 浏览器中访问一下

  • ASP.NET Core3.1 Ocelot负载均衡的实现

    1.负载均衡 Ocelot可以在每个路由的可用下游服务中实现负载均衡,这使我们更有效地选择下游服务来处理请求.负载均衡类型: LeastConnection:根据服务正在处理请求量的情况来决定哪个服务来处理新请求,即将新请求发送到具有最少现有请求的服务去处理.算法状态没有分布在Ocelot集群中. RoundRobin:遍历可用服务并发送请求.算法状态没有分布在Ocelot集群中. NoLoadBalancer:从配置或服务发现中获取第一个可用服务来处理新请求. CookieStickySess

  • asp.net实现负载均衡

    我的目标是我一个人搭建一个负载均衡网站.不接受这是网络部,或者运维,或者系统部的事情,所有事情都是我一个人来完成,包括掏钱,包括将来发展等等,同时也别告诉我有没有意义,just do  it !给我方案,给我方法. 拥有资源:不够可以买,多了可以先闲着. 现在我已经买了5台阿里云服务器,ip地址分别为 ip地址 名字简称 操作系统 iis服务器 cpu 内存DDR3 机械硬盘 111.13.101.204 ay1 window7 iis7 4核 8GB 1TB 111.13.101.205 ay

  • 如何解决asp.net负载均衡时Session共享的问题

    每个客户端在访问网站时,都会创建相应的Session,用来保存客户的状态信息,网站如果做了负载均衡,session共享是要做的,IIS对于session的存储有五种模式 一.ASP.Net session存储方式 1.InProc模式(进程内模式) .为默认设置. 会话状态存储在Web服务器上的内存中. 2.StateServer模式(状态服务器模式). 会话状态存储在一个名为ASP.Net状态服务的单独进程中.这确保了在重新启动Web应用程序时会保留会话状态,并让会话状态可用于网路场中的多个W

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

    目录 一.简介 二.应用场景 三.实际案例 四.算法实现 4.1 随机 4.2 轮询 4.3 权重 一.简介 负载均衡(Load Balance),简称 LB,就是将并发的用户请求通过规则后平衡.分摊到多台服务器上进行执行,以此达到压力分摊.数据并行的效果.常见的算法也有许多随机.轮询.加权等,今天我们就使用 C# 来实现这几种算法,并讲解在实际项目中的使用. 二.应用场景 负载均衡算法在开发层面,使用场景其实并不多.通常在项目重构.转型.上线大版本新功能等,为了避免上线出现 Bug 应用功能

  • 详解SpringCloud的负载均衡

    目录 一.什么是负载均衡 二.负载均衡的简单分类 三.为什么需要做负载均衡 四.springCloud如何开启负载均衡 五.IRule 1.RandomRule:表示随机策略,它将从服务清单中随机选择一个服务: 2.ClientConfigEnabledRoundRobinRule:ClientConfigEnabledRoundRobinRule并没有实现什么特殊的处理逻辑,但是他的子类可以实现一些高级策略, 当一些本身的策略无法实现某些需求的时候,它也可以做为父类帮助实现某些策略,一般情况下

  • 详解Spring Cloud负载均衡重要组件Ribbon中重要类的用法

    Ribbon是Spring Cloud Netflix全家桶中负责负载均衡的组件,它是一组类库的集合.通过Ribbon,程序员能在不涉及到具体实现细节的基础上"透明"地用到负载均衡,而不必在项目里过多地编写实现负载均衡的代码. 比如,在某个包含Eureka和Ribbon的集群中,某个服务(可以理解成一个jar包)被部署在多台服务器上,当多个服务使用者同时调用该服务时,这些并发的请求能被用一种合理的策略转发到各台服务器上. 事实上,在使用Spring Cloud的其它各种组件时,我们都能

  • 详解Nginx HTTP负载均衡和反向代理配置

    当前大并发的网站基本都采用了Nginx来做代理服务器,并且做缓存,来扛住大并发.先前也用nginx配置过简单的代理,今天有时间把整合过程拿出来和大家分享,不过其中大部分也是网上找来的资源. nginx完整的反向代理代码如下所示  : [root@data conf]# vim nginx.conf user www www; worker_processes 10; error_log /var/log/nginx/nginx_error.log; pid logs/nginx.pid; wor

  • 详解SpringCloud Ribbon 负载均衡通过服务器名无法连接的神坑

    一,问题 采取eureka集群.客户端通过Ribbon调用服务,Ribbon端报下列异常 java.net.UnknownHostException: SERVICE-HI java.lang.IllegalStateException: No instances available for SERVICE-HI java.lang.IllegalStateException: Request URI does not contain a valid hostname: http://SERVI

  • 详解Java实现负载均衡的几种算法代码

    本篇文章主要介绍Java实现负载均衡的几种算法,具体如下: 轮询: package class2.zookeeper.loadbalance; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import java.util.Set; /** * 負載均衡算法,輪詢法 * @author guoy * */ public class TestRoundRobin { static Map<St

  • 详解Nacos中注册中心和配置中心的实现

    目录 1.Nacos 简介 Nacos 特性介绍 2.注册中心实现 2.1 创建服务提供者 2.2 创建服务消费者 3.配置中心实现 3.1 新建项目并添加依赖 3.2 配置 Nacos Config 信息 3.3 编写代码读取配置文件 3.4 Nacos 控制台添加配置信息 3.5 动态刷新功能 4.项目源码 小结 Spring Cloud Alibaba 是阿里巴巴提供的一站式微服务开发解决方案,目前已被 Spring Cloud 官方收录.而 Nacos 作为 Spring Cloud A

  • 详解mysql中的存储引擎

    mysql存储引擎概述 什么是存储引擎? MySQL中的数据用各种不同的技术存储在文件(或者内存)中.这些技术中的每一种技术都使用不同的存储机制.索引技巧.锁定水平并且最终提供广泛的不同的功能和能力.通过选择不同的技术,你能够获得额外的速度或者功能,从而改善你的应用的整体功能. 例如,如果你在研究大量的临时数据,你也许需要使用内存存储引擎.内存存储引擎能够在内存中存储所有的表格数据.又或者,你也许需要一个支持事务处理的数据库(以确保事务处理不成功时数据的回退能力). 这些不同的技术以及配套的相关

  • 详解Java中的reactive stream协议

    背景 每个数据流都有一个生产者一个消费者.生产者负责产生数据,而消费者负责消费数据.如果是同步系统,生产一个消费一个没什么问题.但是如果在异步系统中,就会产生问题. 因为生产者无法感知消费者的状态,不知道消费者到底是繁忙状态还是空闲状态,是否有能力去消费更多的数据. 一般来说数据队列的长度都是有限的,即使没有做限制,但是系统的内存也是有限的.当太多的数据没有被消费的话,会导致内存溢出或者数据得不到即使处理的问题. 这时候就需要back-pressure了. 如果消息接收方消息处理不过来,则可以通

  • 详解Java中ThreadLocal类型及简单用法

    目录 1 基本概念 2 简单使用 3 应用场景 4 底层原理 4.1 set(Object) 4.2 get() 4.3 remove() 4.4 ThreadLocalMap 5 内存泄漏隐患和防止策略 5.1 为什么会发生内存泄漏? 5.2 怎样防止内存泄漏? 1 基本概念 ThreadLocal类提供了线程局部变量.这些变量与普通变量的不同之处在于,每个访问一个变量(通过其get或set方法)的线程都有自己的.独立初始化的变量副本.ThreadLocal实例通常是希望将状态与线程关联起来的

随机推荐