既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
从技术上讲,就是ICP行业面临的网络资源有效利用问题,也就是如何进行对网络的访问分流,以便能够快速响应用户反应,即:负载均衡。
从这篇文章起,我们将讲述在负载均衡技术实现中的核心技术:负载均衡算法(算法)的原理及其实现,使大家对负载均衡底层技术有一个深刻的了解。这些算法是负载均衡设备中的核心实现基础。
本篇文章先讲述轮询调度算法 (Round-Robin)及其在此基础上改进型的权重轮询算法(Weighted Round-Robin)。
轮询调度算法(Round-Robin Scheduling)
轮询调度算法的原理是每一次把来自用户的请求轮流分配给内部中的服务器,从1开始,直到N(内部服务器个数),然后重新开始循环。
算法的优点是其简洁性,它无需记录当前所有连接的状态,所以它是一种无状态调度。
轮询调度算法流程:
假设有一组服务器N台,S = {S1, S2, …, Sn},一个指示变量i表示上一次选择的服务器ID。变量i被初始化为N-1。其算法如下:
j = i;
do
{
j = (j + 1) mod n;
i = j;
return Si;
} while (j != i);
return NULL;
这种算法的逻辑实现如图1所示:
轮询调度算法假设所有服务器的处理性能都相同,不关心每台服务器的当前连接数和响应速度。当请求服务间隔时间变化比较大时,轮询调度算法容易导致服务器间的负载不平衡。
所以此种均衡算法适合于服务器组中的所有服务器都有相同的软硬件配置并且平均服务请求相对均衡的情况。
权重轮询调度算法(Weighted Round-Robin Scheduling)
上面所讲的轮询调度算法并没有考虑每台服务器的处理能力,在实际情况中,可能并不是这种情况。由于每台服务器的配置、安装的业务应用等不同,其处理能力会不一样。所以,我们根据服务器的不同处理能力,给每个服务器分配不同的权值,使其能够接受相应权值数的服务请求。
权重轮询调度算法流程:
假设有一组服务器S = {S0, S1, …, Sn-1},W(Si)表示服务器Si的权值,一个指示变量i表示上一次选择的服务器,指示变量cw表示当前调度的权值,max(S)表示集合S中所有服务器的最大权值,gcd(S)表示集合S中所有服务器权值的最大公约数。变量i初始化为-1,cw初始化为零。其算法如下:
while (true) {
i = (i + 1) mod n;
if (i == 0) {
cw = cw - gcd(S);
if (cw <= 0) {
cw = max(S);
if (cw == 0)
return NULL;
}
}
if (W(Si) >= cw)
return Si;
}
这种算法的逻辑实现如图2所示,图中我们假定四台服务器的处理能力为3:1:1:1。
由于权重轮询调度算法考虑到了不同服务器的处理能力,所以这种均衡算法能确保高性能的服务器得到更多的使用率,避免低性能的服务器负载过重。所以,在实际应用中比较常见。
总结
轮询调度算法以及权重轮询调度算法的特点是实现起来比较简洁,并且实用。目前几乎所有的负载均衡设备均提供这种功能。
C++的实现代码
/\*
\* 权重轮询调度算法(Weighted Round-Robin Scheduling)
\* 在多台机器实现负载均衡的时候,存在调度分配的问题.
\* 如果服务器的配置的处理能力都一致的话,平均轮询分配可以直接解决问题,然而有些时候机器的处理能力是不一致的.
\* 假如有2台机器 A和B , A的处理能力是B的2倍,则A的权重为2,B的权重为1.权值高的服务器先收到的连接,
\* 权值高的服务器比权值低的服务器处理更多的连接,相同权值的服务器处理相同数目的连接数。
\* \*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <vector>
using namespace std;
#define SERVER\_COUNT 10
#define RAND\_WEIGHT 10
#define BUFFER\_SIZE 1024
struct srv_info
{
srv_info()
{
ip = new char[BUFFER_SIZE];
weight = 0;
}
char* ip;
int weight;
};
static vector<srv\_info> server; //服务器信息
static int i = -1; //上一次选择的服务器
static int cw = 0; //当前调度的权值
int get_gcd(); //获得所有服务器权值的最大公约数
int get_max_weight(); //获得所有服务器中的最大权值
int get_server(srv_info* s); //轮询调度
int main(int argc, char **argv)
{
srand(time(NULL));
char tmp[BUFFER_SIZE];
server.clear();
for (int i = 0; i < SERVER_COUNT; i++)
{
const char* s = "192.168.0.10";
memset(tmp, '\0', BUFFER_SIZE);
sprintf(tmp, "%s%d", s, i);
struct srv_info sinfo;
memcpy(sinfo.ip, tmp, BUFFER_SIZE);
sinfo.weight = rand() % RAND_WEIGHT;
server.push_back(sinfo);
}
printf("server count: %ld\n", server.size());
for (size_t i = 0; i < server.size(); i++)
{
printf("%s weight: %d\n", server[i].ip, server[i].weight);
}
printf("====================================\n");
int used_count[SERVER_COUNT] = {0};
srv_info s;
for (int i = 0; i < 100; i++)
{
int ret = get_server(&s);
![img](https://img-blog.csdnimg.cn/img_convert/f984e1d81dff84f06d64ffec57f71b3a.png)
![img](https://img-blog.csdnimg.cn/img_convert/6dc96777df3a63313f3594d69d90a920.png)
![img](https://img-blog.csdnimg.cn/img_convert/cabfd431a6635d456c06eda25e7602d2.png)
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!**
**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**
**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618658159)**
,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!**
**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**
**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618658159)**