首页 > 编程知识 正文

实现服务器负载均衡有多种方法常见的方法有,负载均衡几种算法

时间:2023-05-03 09:54:15 阅读:265387 作者:1400

在很多分布式系统里面会遇到一个均衡节点选取的问题:一般是1个负载管理服务器,多个应用服务单元。当有连接或者业务来是,先会去询问负载管理器获取一个负载轻的服务单元,一般的选取就是选取负载最轻的那个。通常情况下是不会有问题的,如果你的应用服务器单元跑的是类似视频服务这种应用,就会出现这样一种情况,某个视频服务A崩溃或者异常了,这个视频服务的所有用户在瞬间会转移到负载最轻的B上,这个时候可能B也异常了,B 和A的用户又全部转到C,这样会产生多咪若效应,所有的服务在瞬间全部不可用。碰到这样的问题我们该怎么避免?问题的根本是负载评估是周期性的,不是每接入一个用户就报一次负载给负载管理器。最理想的是,根据负载管理上所有单元的负载做权重随机。

算法描述如下

假设有N个服务单元,(服务单元的负载是1 ~ 100,100是满负荷运转)。他们的负载分别是L1 L2 L3 .... Ln。

第i台服务的选中的权值 Ti = 100 - Li;

那么整个掉落区间就为 Mn= T1 + T2 + T3 + ... + Tn;

T0 = 0;

随进产生一个0 ~ Mn之间的数V,如果 V < T0 + T1 +...Ti 并且V > T0 + T1 + ... +T(i - 1),那么就 选取第i台服务作为处理新业务的服务单元。


代码实现:

节点负载结构:

typedef struct NodeLoadInfo{uint32_tnode_id;//节点IDuint16_tnode_load;//节点负载值,0到100,100表示负载最大NodeLoadInfo(){node_id = 0;node_load = 100;};}NodeLoadInfo; 选取区间结构:

typedef struct NodeRange{int32_tmin_value;//T0 + T1 + ... + T(i-1)int32_tmax_value;//T0 + T1 + ... + Tiuint32_tnode_id;//节点的服务IDNodeRange(){min_value = 0;max_value = 0;node_id = 0;};}NodeRange;负载选取器的实现接口:

class CNodeLoadManager{public:CNodeLoadManager();~CNodeLoadManager();voidadd_node(const NodeLoadInfo& info);//添加一个新的节点负载voidupdate_node(const NodeLoadInfo& info);//更新一个节点的负载voiddel_node(uint32_t node_id);//删除一个节点uint32_tselect_node();//选取一个适合的节点private:NodeLoadInfoMapnode_info_map_;//节点负载表NodeRangeArraynode_ranges_;//一定周期的概率区间表boolcreate_range_;//是否需要重建概率选取表int32_tregion_;//概率全区间};在上面的接口当中,select_node是核心函数,一下是select_node的伪代码实现:

uint32_t select_node(){uint32_t ret = 0;node_ranges_.clear();region_ = 0;int32_t interval = 0;NodeRange range;//计算各个节点的掉落区间for(NodeLoadInfoMap::iterator it = node_info_map_.begin(); it != node_info_map_.end(); ++it){if(it->second.node_load <= MAX_LOAD_VALUE) //计算负载区间,如果负载太大,不参与计算{interval = MAX_LOAD_VALUE - it->second.node_load + 1;range.node_id = it->second.node_id;range.min_value = region_;region_ += interval;range.max_value = region_ - 1;node_ranges_.push_back(range);}}if(region_ > 0) //随机概率选取ret = locate_server(region_);return ret;}在上面的代码中,实现了区间的计算。locate_server函数查找对应的服务节点,伪代码:

uint32_t locate_server(int32_t region){uint32_t ret = 0;//产生一个随机数int32_t seed = rand() % region;int32_t ranges_size = node_ranges_.size();int32_t max_pos = ranges_size;int32_t min_pos = 0;int32_t pos = 0;//2分法查询掉落到的节点do {pos = (min_pos + max_pos) / 2;if(pos > ranges_size - 1){ret = node_ranges_[ranges_size - 1].node_id;break;}if(pos < 0){ret = node_ranges_[0].node_id;break;}if(node_ranges_[pos].max_value >= seed && node_ranges_[pos].min_value <= seed){ret = node_ranges_[pos].node_id;break;}else if(node_ranges_[pos].max_value < seed){min_pos = pos + 1;}else if(node_ranges_[pos].min_value > seed){max_pos = pos - 1;}} while (true);return ret;}

完全的代码在revolver的base_nodes_load.hbase_nodes_load.cpp之中。


测试结果:

我们模拟了10个节点,随机指定10 ~ 100的负载值,然后选取1000次业务处理的节点,结果如下图:



从结果看来是比较均衡的选取,比较理想。



版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。