一、简介

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

二、应用场景

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

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

三、实际案例

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

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

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

四、算法实现

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

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

public class ServiceCenterModel
{/// <summary>/// Service/// 1. call 下游 server,可以放 url/// 2. 在同一个程序内,可以放一个业务标识/// </summary>public string Service { get; set; }public int Weight { get; set; }
}

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中负载均衡的使用相关推荐

  1. 互联网研发中负载均衡算法一点探索

    负载均衡在线上服务中有着很重要作用,因为一台web服务比如tomcat,能够处理qps(每秒处理请求数) 是有限的.那么就需要有有前端负载均衡服务将大的流量分发为多个后端服务进行处理. 负载均衡产品有 ...

  2. Dubbo中负载均衡的应用

    配置的属性名称: roundrobin/random/ leastactive/ consistenthash <dubbo:service interface="..."  ...

  3. asp.net core中负载均衡场景下http重定向https的问题

    上周欣喜地发现,微软官方终于针对 asp.net core 在使用负载均衡的情况下从 http 强制重定向至 https 的问题提供了解决方法. app.UseForwardedHeaders(new ...

  4. 简谈docker swarm中负载均衡原理

    同一集群内部的负载均衡模式 基于在swarm中创建节点即可分配内部域名的情况下: dnsrr 单纯通过内部DNS内部组件进行负载均,由于DNS缓存机制等问题,有局限性. VIP: 简单来讲是 (内部) ...

  5. 解析nginx负载均衡

    摘要:对于一个大型网站来说,负载均衡是永恒的话题.随着硬件技术的迅猛发展,越来越多的负载均衡硬件设备涌现出来,如F5 BIG-IP.Citrix NetScaler.Radware等等,虽然可以解决问 ...

  6. Web负载均衡学习笔记之K8S内Ngnix微服务服务超时问题

    0x00 概述 本文是从K8S内微服务的角度讨论Nginx超时的问题 0x01 问题 在K8S内部署微服务后,发现部分微服务链接超时,Connection Time Out. 最近碰到了一个 Ngin ...

  7. Spring Cloud Alibaba - 07 Ribbon 应用篇及内置的负载均衡算法

    文章目录 Ribbon整合三部曲 artisan-cloud-ribbon-order step1 搞依赖 step2 搞注解 (在RestTemplate上加入@LoadBalanced注解) St ...

  8. Nginx代理功能与负载均衡详解

    序言 Nginx的代理功能与负载均衡功能是最常被用到的,关于nginx的基本语法常识与配置已在上篇文章中有说明,这篇就开门见山,先描述一些关于代理功能的配置,再说明负载均衡详细. Nginx代理服务的 ...

  9. ecs 对比 本地服务器_ECS训练营Day03_SLB负载均衡实践 - 魔笔钨丝浣

    创建资源 云服务器状态确认 分别访问实验提供的两台云服务器ECS,观察有什么异同点. 打开浏览器,在输入框中输入 云产品资源 提供的 云服务器ECS-1 的 弹性IP 说明:正常情况下不会显示 后端服 ...

最新文章

  1. python使用open打开文件时显示文件不存在-Python打开文件open()的注意事项
  2. 如何在Dart中读取控制台输入/ stdin?
  3. iOS 7 改变Status Bar 颜色
  4. SQLite 入门教程(二)创建、修改、删除表
  5. axios请求拦截 做Loading加载
  6. 国外开源.Net 系统概述
  7. [vue] 说说你对选项el,template,render的理解
  8. T61 拆机4短报警
  9. IPTV机顶盒和网络盒子及转换
  10. 商务网站建设与维护【7】
  11. 520C语言表白神器
  12. 修改无线网密码后服务器拒绝访问,路由器重设密码怎么上不了网
  13. html表格中复选框代码怎么写,获取html表中的选中复选框
  14. RuoYi若依打包发布与部署
  15. git pull常见操作
  16. 滤波电路(上),无源滤波器
  17. 杰理芯片移植涂鸦OTA步骤
  18. Java Web 表单开发
  19. Excel表格中替换的高级用法
  20. 心疼!内蒙古一4岁男孩在幼儿园被老师打,园方不承认施暴

热门文章

  1. OneNote2016单独安装
  2. php+b2b2c+商城,PHP源码:SHOPNC b2b2c电商平台系统,im+结算补丁+商城专题页插件
  3. Android基于环信SDK开发IM即时聊天(二)
  4. Power2Go 13安装教程
  5. HTK工具箱的安装和使用(WAV到MFCC)
  6. 如何围绕用户数字化运营?
  7. Blender设置相机围绕物体旋转
  8. Scott 数据 映射 MySQL
  9. html500错误原因1003无标题,web工程中404/500错误页面配置+404页面模板
  10. 【可解释机器学习】Shapley Values and SHAP (SHapley Additive exPlanations)