负载均衡算法,轮询方式

2018-04-13 17:37 by 天才卧龙, 13 阅读, 0 评论, 收藏编辑

学无止境,精益求精

十年河东,十年河西,莫欺少年穷

学历代表你的过去,能力代表你的现在,学习代表你的将来

首先说下这个算法的背景:

假设公司需要存储的信息量非常非常大而且访问量也是非常非常滴大(例如淘宝,天猫,京东等数据存储量和访问量都很大)

就拿天猫来举例:

马云:小陈啊,最近公司业务发展,数据存储量及访问量灰常灰常大,为减轻服务器的负载,限你们技术部提出一个解决方案?

小陈:马大帅,你一个当老师的瞎操心什么技术(不屑的眼神)

马云:你知道杭州电子科技大学吗?

小陈:一脸懵逼...

马云:这所学校的前身是杭州师范学院 ~_~ 注:(马云从杭州师范学院外国语系英语专业毕业)

小陈:马大帅您竟然是电子科技大的高材生,佩服佩服。我马上召集技术部人员,集思广益。~_~ 注:(小陈并不知道马云英语专业毕业)

半小时后小陈提出了解决方案:负载均衡

要想做到负载均衡,就必须写一套负载均衡算法:

在介绍负载均衡算法之前,我们来介绍下负载均衡的使用场景,如下:

还是以阿里巴巴天猫举例:假设天猫只有一台数据库服务器,随着数据存储量及访问量的直线式增加,这台服务器的吞吐量达到了极值,造成了访问速度越来越慢。马总看到眼里,急在心里!于是就有了上述的对话!

小陈提出的负载均衡是怎么一回事呢?

把原来的一台服务器扩充至几十台或者几百台服务器,当第一台服务器吞吐量高时,将用户的请求转向第二台服务器。同理,当第二台服务器的吞吐量高时,将用户的请求转向第三台服务器,以此类推...

那么,如果自动做到负载均衡呢?这里就需要负载均衡的算法了!

假设:天猫总共有数据库服务器四台,每台服务器的性能不同,第一台可提供的最大连接数为2,第二台服务器可提供的最大连接数为4,第三台服务器可提供的最大连接数为8,最后一台为12

假设:现在可用的服务器为第三台和第四台。

负载均衡算法如下:

namespace SJMS.test
{
    public class Test
    {
        static int maxLinkCount;
        //
        private static object lockHelper = new object();
        /// <summary>
        /// 所有快照/服务器的权重列表 所谓权重我们可理解为最大连接数
        /// </summary>
        static List<int> snapWeightList = new List<int>() { 2,4,8,12};

        //可用的服务器权重列表
        static List<int> EnableWeightList = new List<int>() { 8,12 };
        /// <summary>
        /// 当前的快照索引和权重信息
        /// </summary>
        static int curentSnapIndex, currentWeight, EnableWeight;
        /// <summary>
        /// 快照权重列表中最大的权重值和最大公约数
        /// </summary>
        static int maxWeight, gcd;

        static Test()
        {
            curentSnapIndex = -1;
            currentWeight = 0;
            EnableWeight = 0;
            maxWeight = GetMaxWeight(snapWeightList);
            EnableWeight = GetMaxWeight(EnableWeightList);
            gcd = GCD(snapWeightList);
            maxLinkCount = EnableWeightList.Sum();
        }
        /// <summary>
        /// 获取最大值 权重
        /// </summary>
        /// <param name="snapWeightList"></param>
        /// <returns></returns>
        public static int GetMaxWeight(List<int> snapWeightList)
        {
            int maxWeight = 0;
            foreach (int snapWeight in snapWeightList)
            {
                if (maxWeight < snapWeight)
                    maxWeight = snapWeight;
            }
            return maxWeight;
        }

        /// <summary>
        /// 获取最大公约数
        /// </summary>
        /// <param name="snapWeightList"></param>
        /// <returns></returns>
        public static int GCD(List<int> snapWeightList)
        {
            // 排序,得到数字中最小的一个
            snapWeightList.Sort(new WeightCompare());
            int minNum = snapWeightList[0];

            // 最大公约数肯定大于等于1,且小于等于最小的那个数。
            // 依次整除,如果余数全部为0说明是一个约数,直到打出最大的那个约数
            int gcd = 1;
            for (int i = 1; i <= minNum; i++)
            {
                bool isFound = true;
                foreach (int snapWeight in snapWeightList)
                {
                    if (snapWeight % i != 0)
                    {
                        isFound = false;
                        break;
                    }
                }
                if (isFound)
                    gcd = i;
            }
            return gcd;
        }

        /// <summary>
        /// 权重轮询调度算法/负载均衡算法
        /// </summary>
        public static int RoundRobinScheduling()
        {
            lock (lockHelper)
            {
                while (true)
                {
                    curentSnapIndex = (curentSnapIndex + 1) % EnableWeightList.Count;
                    if (curentSnapIndex == 0)
                    {
                        currentWeight = currentWeight - gcd;
                        if (currentWeight <= 0)
                        {
                            currentWeight = maxWeight;
                            if (currentWeight == 0)
                                return -1;
                        }
                    }
                    int A = snapWeightList[curentSnapIndex];
                    if (A >= currentWeight)
                    {
                        return EnableWeightList[curentSnapIndex];
                    }
                }
            }
        }
    }

    public class WeightCompare : System.Collections.Generic.IComparer<int>
    {
        public int Compare(int weightA, int weightB)
        {
            return weightA - weightB;
        }
    }

    public class DbSnapInfo
    {
        public int SouceID { get; set; }
        public bool Enable { get; set; }
        public int Weight { get; set; }
    }
}

这段代码有个比较难理解的地方:最大公约数的使用!(只可意会不可言传)

要想弄清楚最大公约数的使用,建议大家多次调试(调试时:变更服务器及服务器连接数)。

总之:算法的结果是帮你找到一个可用的服务器连接!

@陈卧龙的博客

大话设计模式之工厂模式 C#

2018-04-12 15:36 by 天才卧龙, 19 阅读, 0 评论, 收藏编辑

学无止境,精益求精

十年河东,十年河西,莫欺少年穷

学历代表你的过去,能力代表你的现在,学习代表你的将来

大话设计模式一书中第一个开讲的设计模式是简单工厂模式,关于简单工厂模式大家可参考鄙人的博客:代码无错就是优?简单工厂模式 C#

当然,本篇博客所讲的工厂模式和简单工厂模式还是非常类似的,因此,在进行工厂模式讲解之前,我们有必要重温下简单工厂模式

何为工厂模式?不论是简单工厂模式还是本篇的工厂模式,其工厂类主要负责生产对象,然后通过相应的对象调用相关的方法

在重温简单工厂模式之前,我们再次看下简单工厂模式的UML类图

针对上述的简单工厂模式UML类图,我们得到如下叙述:

1、简单工厂类是和运算类是有关联的(实线加箭头代表关联),简单工厂类的主要功能是生产运算对象

2、运算类用斜体表示,说明运算类为抽象类,运算类有两个属性及一个返回值为 double 的方法

3、加减乘除类继承运算类并实现GetResult()方法。

针对上述三点叙述,我们可用如下代码来实现(如果你还看不懂UML类图,可以参考鄙人博客:UML类图应该怎么看?

    public class 简单工厂类
    {
        double NumberA, NumberB;
        public 简单工厂类() { }
        public 简单工厂类(double A, double B)
        {
            this.NumberA = A;
            this.NumberB = B;
        }
        double Oper = new double();
        public double Operate(string 符号)
        {
            switch (符号)
            {
                case "+": Oper = new 加法类().GetResult(NumberA, NumberB); break;
                case "-": Oper = new 减法类().GetResult(NumberA, NumberB); break;
                case "*": Oper = new 乘法类().GetResult(NumberA, NumberB); break;
                case "/": Oper = new 除法类().GetResult(NumberA, NumberB); break;
            }
            return Oper;
        }
    }

    public abstract class 运算类
    {
        public abstract double GetResult(double NumberA, double NumberB);
    }

    public class 加法类:运算类
    {
        public override double GetResult(double NumberA, double NumberB)
        {
            return NumberA + NumberB;
        }
    }

    public class 减法类 : 运算类
    {
        public override double GetResult(double NumberA, double NumberB)
        {
            return NumberA - NumberB;
        }
    }

    public class 乘法类 : 运算类
    {
        public override double GetResult(double NumberA, double NumberB)
        {
            return NumberA * NumberB;
        }
    }

    public class 除法类 : 运算类
    {
        public override double GetResult(double NumberA, double NumberB)
        {
            if (NumberB != 0)
                return NumberA / NumberB;
            else throw new Exception("被除数不能为零");

        }
    }
        static void Main(string[] args)
        {
            double A = 1;
            double B = 2;
            string F = "/";
            简单工厂类 M = new 简单工厂类(A,B);
            double Result =  M.Operate(F);
            Console.WriteLine(Result);
            Console.ReadKey();
        }

上述代码是鄙人看着UML类图自己设计的,和博客:代码无错就是优?简单工厂模式 C# 中的设计代码并不一样!当然,这两种代码都准确的表达的简单工厂的理念。有兴趣的也可以看下 代码无错就是优?简单工厂模式 中的代码实现形式。

OK,上述就是简单工厂模式的代码设计方案!

但是简单工厂模式违反了设计模式的开闭原则,所以我们有必要对其进一步优化!

所谓开闭原则:

这个原则其实有两个特性,一个是说对于扩展是开放的,另一个是说,对于修改是封闭的(ASD原则

如何优化呢?

工厂模式闪亮登场...

首先看下工厂模式关于加减乘除的UML类图

额,似乎复杂了很多!

不急,我们慢慢分析,然后再用代码实现!

1、运算工厂接口依赖运算类,加法工厂类依赖加法类,减法工厂类依赖减法类,乘法工厂类依赖乘法类,除法工厂类依赖除法类!(虚线加箭头代表依赖)

2、加减乘除工厂类继承运算工厂接口,加减成熟类继承运算类(三角加实线代表继承)

3、下方的M的N次方类和对应的工厂类是用来扩展的。

那么,分析了UML类图的信息,怎样用代码实现呢?

首先我们来创建左侧部分的五个类(运算类及加减乘除类),如下:

    /// <summary>
    /// 运算类
    /// </summary>
    public class Operation
    {
        public double NumberA, NumberB;
        public virtual double GetResult()
        {
            return 0;
        }
    }

    public class Add : Operation
    {
        public override double GetResult()
        {
            return NumberA + NumberB;
        }
    }

    public class Sub : Operation
    {
        public override double GetResult()
        {
            return NumberA - NumberB;
        }
    }

    public class Mul : Operation
    {
        public override double GetResult()
        {
            return NumberA * NumberB;
        }
    }

    public class Div : Operation
    {
        public override double GetResult()
        {
            if (NumberB == 0)
                throw new Exception("被除数不能为零");
            return NumberA / NumberB;
        }
    }

其次,我们来构建右侧部分的一个接口及四个类(加减乘除工厂类),如下:

    public interface IFactory
    {
        Operation GetOperation();
    }

    public class AddFactory : IFactory
    {
        public Operation GetOperation()
        {
            return new Add();
        }
    }

    public class SubFactory : IFactory
    {
        public Operation GetOperation()
        {
            return new Sub();
        }
    }

    public class MulFactory : IFactory
    {
        public Operation GetOperation()
        {
            return new Mul();
        }
    }

    public class DivFactory : IFactory
    {
        public Operation GetOperation()
        {
            return new Div();
        }
    }

客户端代码为:

        static void Main(string[] args)
        {
            IFactory F = new AddFactory();
            Operation AM = F.GetOperation();
            AM.NumberA = 8;
            AM.NumberB = 7;
            double sum = AM.GetResult();
            Console.WriteLine(sum);
            Console.ReadKey();
        }

最后,我们来运行一下(7+8=15):

写到这儿,我可以自豪的说:如果你要加平方根运算,我只需新增平方根类及平方根工厂。因此,现在的设计是不违反设计模式的开闭规则的!

我们知道,在简单工厂模式中,我们可以通过运工厂类的 Switch Case 来判断具体的运算类型,但是上述所写的工厂模式却做不到了!这样写无形中加重了客户端的负担(客户端必须自己来判断运算类型),因此:有没有好的办法解决这个弊端呢?

答案是有,而且还有一个有趣的名字,叫:雷锋工厂

如何用代码实现呢?

@陈卧龙的博客

负载均衡算法,轮询方式 大话设计模式之工厂模式 C#的更多相关文章

  1. Java实现负载均衡算法--轮询和加权轮询

    1.普通轮询算法 轮询(Round Robin,RR)是依次将用户的访问请求,按循环顺序分配到web服务节点上,从1开始到最后一台服务器节点结束,然后再开始新一轮的循环.这种算法简单,但是没有考虑到每 ...

  2. Nginx 负载均衡-加权轮询策略剖析

    本文介绍的是客户端请求在多个后端服务器之间的均衡,注意与客户端请求在多个nginx进程之间的均衡相区别(Nginx根据每个工作进程的当前压力调整它们获取监听套接口的几率,那些当前比较空闲的工作进程有更 ...

  3. Nginx的负载均衡 - 加权轮询 (Weighted Round Robin) 下篇

    Nginx版本:1.9.1 我的博客:http://blog.csdn.net/zhangskd 上篇blog讲述了加权轮询算法的原理.以及负载均衡模块中使用的数据结构,接着我们来看看加权轮询算法的具 ...

  4. 【Nginx】负载均衡-加权轮询策略剖析

    转自:江南烟雨 本文介绍的是客户端请求在多个后端服务器之间的均衡,注意与客户端请求在多个nginx进程之间的均衡相区别. 如果Nginx是以反向代理的形式配置运行,那么对请求的实际处理需要转发到后端服 ...

  5. Nginx的负载均衡 - 加权轮询 (Weighted Round Robin) 上篇

    Nginx版本:1.9.1 我的博客:http://blog.csdn.net/zhangskd 算法介绍 来看一个简单的Nginx负载均衡配置. http { upstream cluster { ...

  6. nginx负载均衡 加权轮询和ip_hash

    下面给大家总结了几种真正的nginx负载均衡的功能了,在此我们加了一个权重判断法就是根据nginx负载的状态实现分配访问用户到权重值少的机器了,具体配置如下. nginx为后端web服务器(apach ...

  7. 大话设计模式之工厂模式 C#

    学无止境,精益求精 十年河东,十年河西,莫欺少年穷 学历代表你的过去,能力代表你的现在,学习代表你的将来 大话设计模式一书中第一个开讲的设计模式是简单工厂模式,关于简单工厂模式大家可参考鄙人的博客:代 ...

  8. 大话设计模式--抽象工厂模式 Abstract Factory -- C++实现实例

    1. 抽象工厂模式: 提供一个创建一系列相关或者相互依赖对象的接口,而无需指定他们具体的类. 下面是工厂方法模式: 下面是抽象工厂模式: 和工厂方法模式相比 抽象工厂模式可以有多个Product抽象, ...

  9. 负载均衡算法WeightedRoundRobin(加权轮询)简介及算法实现

    Nginx的负载均衡默认算法是加权轮询算法,本文简单介绍算法的逻辑,并给出算法的Java实现版本. 本文参考了Nginx的负载均衡 - 加权轮询 (Weighted Round Robin).     ...

随机推荐

  1. EF CodeFirst 不得不说的Where与OrderBy

    先来聊上5毛钱的“排序” Code: using (ApplicationDbContext Db=new ApplicationDbContext()) { var res = Db.Threes. ...

  2. 【Python-2.7】删除空格

    有时我们在编程过程中,需要去除字符串两边的空格,可以用如下函数解决问题: rstrip():去除字符串右边的空格: lstrip():去除字符串左边的空格: strip():去除字符串两边的空格. 示 ...

  3. Shell script之How to write

    Write shell script: 1) Editor like vi or mcedi 2) Set execute permission for your script chmod  perm ...

  4. CAD使用GetXData读数据(com接口)

    主要用到函数说明: MxDrawEntity::GetXData 返回实体的扩展数据. c#代码实现如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 1 ...

  5. 【原】CentOS release 6.2 安装mysql

     1.  yum update升级以后的系统版本为 [root@yl-web yl]# cat /etc/redhat-release CentOS Linux release 7.1.1503 (C ...

  6. 字符串系列——KMP模板整理

    KMP模板整理 KMP与扩展KMP: /*vs 2017/ vs code以外编译器,去掉windows.h头文件和system("pause");*/ #include<i ...

  7. 06 Python流程控制

    目录: 12) if语句 13) 三目运算 14) while语句 15) break与continue关键字 16) while…else语句 12,if语句        Note: 在一个if语 ...

  8. C,LINUX,数据结构部分

    1604期 第1期测试(面试精选:C,LINUX,数据结构部分) 本试卷从考试酷examcoo网站导出,文件格式为mht,请用WORD/WPS打开,并另存为doc/docx格式后再使用 试卷编号:24 ...

  9. c#读取.config文件内容

    今天在做项目的时候,由于程序同时启动多种情况的数据,测试分为多个人,就需要把数据分离开来,于是用了一个临时的配置文件,让测试在配置文件修改相应数据从而让各个测试互相不影响! 步骤: 第一步:添加一个A ...

  10. Spring 使用注解注入 学习(四)

    <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.sp ...