首页 > 其他分享 >[2core]基于httpclient实现负载均衡

[2core]基于httpclient实现负载均衡

时间:2022-10-12 15:35:45浏览次数:44  
标签:负载 2core get tmpIndex tmpList item HttpClient public httpclient

一、准备

由于没有采用asp.net core框架提供的HttpClientFactory和依赖注入方式使用HttpClient,所以从asp.net迁移到asp.net core变化并不大,而且HttpClient的使用也基本没有变化。因此本文重点记录的是自己设计的基于工厂模式创建和管理HttpClient的过程,以及负载均衡的实现。

 

二、设计

经过对比知道ASP.NET Core中的HttpClient使用与ASP.NET中的HttpClient没有差异,当然底层实现变化不小,因此,就把重心放在了如何实现负载均衡上。设计思路如下:

1)HttpClient对象有工厂负责创建和维护。
2)HttpClient对象目标服务器通过appsettings.json配置方式管理。
3)编程时程序员仅需通过HttpFactory.Create("服务器名称")就可以获取HttpClient对象。
4)HttpFactory创建HttpClient对象后,按照配置文件中设定的负载均衡模式管理。
5)HttpFactory输出HttpClient对象时,按照HttpClient对象集所述负载均衡模式,有效选择HttpClient。
6)负载均衡支持“轮询模式”和“加权平均模式”。

 

三、实现
列出上述设计思路就可以进行编码了

1.配置文件和Options定义

{
  "ApiServers": [
    {
      "Name": "Did",
      "Mode": "Poll",
      "ApiEndPoints": [
        {
          "Address": "http://localhost:10100/",
          "Weight": 1
        }
      ]
    }
  ]
}
    public class ApiServerOptions
    {
        /// <summary>
        /// 服务名称,不允许重复,使用名称获取服务
        /// </summary>
        public string Name { get; set; }
        /// <summary>
        /// 服务模式(Poll|Weight),Poll表示通过轮询模式实现负载均衡(普通),Weight表示权重模式实现负载均衡(加权平均)
        /// </summary>
        public string Mode { get; set; }
        /// <summary>
        /// 服务集合,提供相同服务的服务器集合
        /// </summary>
        public List<ApiEndPointOptions> ApiEndPoints { get; set; }
    }

    public class ApiEndPointOptions
    {
        /// <summary>
        /// 终结点服务地址
        /// </summary>
        public string Address { get; set; }
        /// <summary>
        /// 权重值,仅用于Weight模式,取值范围[1-100],默认1
        /// </summary>
        public int Weight { get; set; } = 1;
    }

2.实现默认工厂

2.1.定义类模型

        private class ApiServerObject
        {
            public string Name { get; set; }
            public string Mode { get; set; } = LB_MODE_POLL;
            public List<ApiServerEndPointObject> EndPoints { get; set; }
        }
        private class ApiServerEndPointObject
        {
            public string Address { get; set; }
            public int Weight { get; set; } = 0;
            public int WeightCurrent { get; set; } = 0;
            public bool IsActive { get; set; } = true;
            public TestHttpHelper Helper { get; set; }
        }

2.2.依据配置文件生成HttpClient对象集合

internal class TestDefaultHttpFactory
    {
        private static object _objLocker = new object();
        private const string LB_MODE_WEIGHT = "weight";
        private const string LB_MODE_POLL = "poll";

        private static TestDefaultHttpFactory _instance = null!;
        public static TestDefaultHttpFactory Instance
        {
            get
            {
                if (_instance == null)
                {
                    lock (_objLocker)
                    {
                        if (_instance == null)
                        {
                            _instance = new TestDefaultHttpFactory();
                        }
                    }
                }
                return _instance;
            }
        }
        private TestDefaultHttpFactory()
        {
            Generate();
        }

        private void Generate()
        {
            var _tmpStr = JsonConvert.SerializeObject(AppSetting.Instance.ApiServers);
            var _tmpList = JsonConvert.DeserializeObject<List<ApiServerOptions>>(_tmpStr);
            foreach (var item in _tmpList)
            {
                if (!apiServerList.ContainsKey(item.Name))
                {
                    if (LB_MODE_WEIGHT == item.Mode.ToLower())
                    {
                        GenerateWeight(item);
                    }
                    else
                    {
                        GeneratePoll(item);
                    }
                }
            }
        }
        private void GeneratePoll(ApiServerOptions item)
        {
            var _tmpList = new List<ApiServerEndPointObject>();
            foreach (var subItem in item.ApiEndPoints)
            {
                if (!_tmpList.Exists(o => o.Address == subItem.Address))
                {
                    _tmpList.Add(new ApiServerEndPointObject
                    {
                        Address = subItem.Address,
                        Helper = new TestHttpHelper(subItem.Address)
                    });
                }
            }
            apiServerList.TryAdd(item.Name.ToLower(), new ApiServerObject
            {
                Name = item.Name.ToLower(),
                Mode = item.Mode.ToLower(),
                EndPoints = _tmpList
            });
        }
        private void GenerateWeight(ApiServerOptions item)
        {
            var _tmpList = new List<ApiServerEndPointObject>();
            if (item.ApiEndPoints != null && item.ApiEndPoints.Count > 0)
            {
                foreach (var subItem in item.ApiEndPoints)
                {
                    if (subItem.Weight < 1) subItem.Weight = 1;
                    if (subItem.Weight > 100) subItem.Weight = 100;

                    if (!_tmpList.Exists(o => o.Address == subItem.Address))
                    {
                        _tmpList.Add(new ApiServerEndPointObject
                        {
                            Address = subItem.Address,
                            Weight = subItem.Weight,
                            Helper = new TestHttpHelper(subItem.Address)
                        });
                    }
                }
            }
            apiServerList.TryAdd(item.Name.ToLower(), new ApiServerObject
            {
                Name = item.Name.ToLower(),
                Mode = item.Mode.ToLower(),
                EndPoints = _tmpList
            });
        }
}

上述代码首先由单例模式创建了工厂对象,然后通过Generate方法分别创建“轮询模式”和“加权平均模式”的HttpClient对象。

3.负载均衡

        public TestHttpHelper Create(string apiServerName)
        {
            ApiServerObject _tmpApiServer;
            if (apiServerList.TryGetValue(apiServerName, out _tmpApiServer))
            {
                if (LB_MODE_WEIGHT == _tmpApiServer.Mode)
                {
                    return ComputeWeight(_tmpApiServer);
                }
                else//poll
                {
                    return ComputePoll(_tmpApiServer);
                }
            }
            return null;
        }

外部请求者通过调用DefaultHttpFactory.Instance.Create(“服务器名称”),得到HttpHelper对象,HttpHelper封装了HttpClient对象。

3.1.轮询模式

private TestHttpHelper ComputePoll(ApiServerObject apiServer)
        {
            TestHttpHelper result = null;
            if (apiServer.EndPoints != null && apiServer.EndPoints.Count > 0)
            {
                var _tmpList = apiServer.EndPoints.FindAll(o => o.IsActive);
                if (_tmpList != null && _tmpList.Count > 0)
                {
                    int _tmpIndex = 0;
                    if (pollList.ContainsKey(apiServer.Name))
                    {
                        pollList.TryGetValue(apiServer.Name, out _tmpIndex);
                        if (_tmpIndex >= _tmpList.Count)
                        {
                            _tmpIndex = 0;
                        }

                        var _tmpIndex2 = (_tmpIndex + 1) >= _tmpList.Count ? 0 : (_tmpIndex + 1);
                        pollList.TryUpdate(apiServer.Name, _tmpIndex2, _tmpIndex);
                    }
                    else
                    {
                        var _tmpIndex2 = (_tmpIndex + 1) >= _tmpList.Count ? 0 : (_tmpIndex + 1);
                        pollList.TryAdd(apiServer.Name, _tmpIndex2);
                    }
                    result = _tmpList[_tmpIndex].Helper;
                }
            }
            return result;
        }

此模式的实现过程是,通过定义一个集合,记录目标服务器使用HttpClient的顺序,然后按照顺序依次分配。

3.2.负载均衡 - 加权平均模式

private TestHttpHelper ComputeWeight(ApiServerObject apiServer)
        {
            TestHttpHelper result = null;
            if (apiServer.EndPoints != null && apiServer.EndPoints.Count > 0)
            {
                var _tmpList = apiServer.EndPoints.FindAll(o => o.IsActive);
                if (_tmpList != null && _tmpList.Count > 0)
                {
                    if (_tmpList.Count == 1)
                    {
                        result = _tmpList[0].Helper;
                    }
                    else
                    {
                        var _tmpIndex = -1;
                        var _tmpSumWeight = 0;
                        for (int i = 0; i < _tmpList.Count; i++)
                        {
                            _tmpSumWeight += _tmpList[i].Weight;

                            _tmpList[i].WeightCurrent += _tmpList[i].Weight;
                            if (_tmpIndex == -1 || _tmpList[_tmpIndex].WeightCurrent < _tmpList[i].WeightCurrent)
                            {
                                _tmpIndex = i;
                            }
                        }
                        _tmpList[_tmpIndex].WeightCurrent -= _tmpSumWeight;
                        result = _tmpList[_tmpIndex].Helper;
                    }
                }
            }
            return result;
        }

此模式的实现过程,主要参考Nignx实现平滑加权平均的原理,俗称割韭菜法。

 

四、使用

    public class TestHttpFactory
    {
        public static TestHttpHelper Create(string apiServerName)
        {
            if (apiServerName.IsNotNullEmptyWhiteSpace())
            {
                return TestDefaultHttpFactory.Instance.Create(apiServerName.ToLower());
            }
            return null;
        }
    }

 

五、总结

通过上述方案就完成了HttpClient的技术迁移。

 

测试代码:https://gitee.com/kinbor/jks.core.test.httpclient.git

标签:负载,2core,get,tmpIndex,tmpList,item,HttpClient,public,httpclient
From: https://www.cnblogs.com/Jkinbor/p/16784652.html

相关文章

  • nginx负载均衡策略
    目前Nginx服务器的upstream模块支持6种方式的分配:轮询默认方式weight权重方式ip_hash依据ip分配方式least_conn最少连接方式fair(第三方)响应时间方......
  • Class 3 SLB负载均衡实践
    title:Class3SLB负载均衡实践excerpt:云上实践云上成长ECS7天实践训练营tags:[阿里云,在家学习,ECS,SLB,进阶班]categories:[学习,阿里云]index_img:......
  • MUCNetV2:内存瓶颈和计算负载问题一举突破?分类&检测都有较高性能(附源代码下载)
    公众号ID|ComputerVisionGzq​论文地址:https://arxiv.org/pdf/2110.15352.pdf源代码:https://mcunet.mit.edu计算机视觉研究院专栏作者:Edison_GMCUNetV2取得了MCU端新的ImageN......
  • HttpClient 403 Forbiddenn问题 模拟浏览器请求头
    403Forbiddenn问题模拟浏览器请求头重点配置如下://创建httpGET请求HttpGethttpGet=newHttpGet(uri);httpGet.setHeader("User-Agent","Mozilla/5.0(Windows;U......
  • HttpClient详细梳理
    HttpClient详细梳理1、httpClientHttpClient是Apache中的一个开源的项目。它实现了HTTP标准中Client端的所有功能,使用它能够很容易地进行HTTP信息的传输。它的各个版本......
  • [2core]跨域资源共享CORS
    迁移问题在ASP.NET4.x时期,解决CORS问题是非常容易的,仅需在配置文件web.config里增加相应的配置节点即可,无法在程序中进行编码。在ASP.NETCore中,一切都是DI+配置Options......
  • Ozone-适用于各种工作负载的灵活高效的存储系统
    ApacheOzone是一种分布式、可扩展和高性能的对象存储,可与Cloudera数据平台(CDP)一起使用,可以扩展到数十亿个不同大小的对象。它被设计为原生的对象存储,可提供极高的规模......
  • HttpClient和OkHttp发送http请求
    根据技术选型总结常见的三种方式发送http请求,本问介绍框架中常用的HttpClient和OkHttp方式,其他两种如下链接​​​springboot中使用restTemplate发送http请求​​ 一、http......
  • [2core]EFCore对象关系映射
    迁移问题新建一个webapi项目,然后安装EFCore类库,以及ERCore.SqlServer类库,像使用ASP.NET4.x一样采用DBFirst模式,创建ADO.NET实体数据模型。步骤没有错,可此时VS2022提示“......
  • .NET中大型项目开发必备(14)--数据库的负载均衡(续)
    前言:本系列文章适合有初/中级.NET知识的同学阅读(请在电脑上打开页面,获取更好的阅读效果)。(1)本系列文章,旨在讲述研发一个中大型项目所需要了解的一系列“基本构件”,并提供这......