基于一致性哈希实现的负载均衡。一致性哈希主要需要注意以下几点:
一,根据用户IP或者ID等大体固定的数据进行hash求值,以保证每次相同的用户尽量可以hash到固定的服务器上去。
二,为了保证每台服务器的效能能够充分利用,例如有的服务器性能较好,性能为3,有的服务器性能一般,性能为2。不同的服务器可以对其不同的虚拟节点,以保证效能的充分利用。
三,考虑雪崩现象,一般hash也可以达到前两点,但是如果一台服务器崩溃,那么所有的用户请求压到下一台服务器,很可能该服务器也崩溃,以此类推,造成雪崩现象。
四,属于优化点,当服务器正常运行,此时新加一台服务器,应当适量的为该服务器增加以下映射量。
大体思路:使用数组模拟虚拟节点,不同的服务器为其传递不同的权值,根据权值映射到该虚拟数组中。例如,开辟一百个大小的数组,初始值均为零,新加一台权值为4的服务器,那么进行hash四次,映射到的位置保存该服务器的编号值。当客户端的连接来到的时候,根据固定值进行hash求值,得到对应的服务器编号,从map表中找到对应的服务器,转发该消息。
特殊情况:减少服务器时,该服务器在虚拟数组上的hash位置的值存储为其上一个点或者下一个点(有效点,即值非0的点)的值。本代码存储上一个有效点。
极端情况:如果需要频繁的增加和删除。注意,这里是和,不是或。那么可能会造成虚拟节点趋近于相同化,即某个固定值极对应的位置极可能很相近。
先附上代码,再附上找负载均衡时候总结的资料。
<balance.h>
#include <iostream>
#include <map>
#include <vector>
#include <algorithm>
#include <string>
#include <set>
class server
{
public:
server(int socket, int weight) :_socket(socket),_num(0),_online_num(0),_weight(weight){}
int get_socket(){ return _socket; }
int OnlineNum() { return _online_num; }
void addClient(){ _online_num++; }
void delClient(){ _online_num--; }
int get_ServerNum(){ return _num; } //该编号就是balance类中的键值
void set_ServerNum(int num){ _num = num; }
int get_Weight(){ return _weight; }
void sendMsg(std::string &strMsg);
void recvMsg(std::string &strMsg){ _strMsg = strMsg; }
//~server(){ close _socket; }
private:
int _socket;
int _online_num; //在线人数
int _num; //编号
int _weight; //权值
std::string _strMsg; //Msg消息
};
class client
{
public:
client(int socket, int id) :_socket(socket),_id(id){}
void set_num(int iNum){ _num = iNum; }
int get_num(){ return _num; }
int getId(){ return _id; }
void sendMsg(std::string &strMsg); //s->c
void recvMsg(std::string &strMsg){ _strMsg = strMsg; }
//~client(){ close(_socket); }
private:
int _socket;
int _num; //虚拟数组编号
int _id; //id
std::string _strMsg; //消息字符串
};
class balance
{
public:
static balance *getInstance(int iSize){
if (instance == NULL){
instance = new balance(iSize);
}
return instance;
}
void addOnlineNum(){ _online_num++; }
void delOnlineNum(){ _online_num--; }
void delOnlineNum(int iNum){ _online_num -= iNum; }
int getOnlineNum(){ return _online_num; }
bool addServer(server *ser);
bool delServer(server *ser);
int allWriteNum();
//映射节点
void addVirualPoint(server *ser);
//去掉映射节点
void delVirualPoint(server *ser);
//获取一个map中的空位置 error:-1
int getSpacePos();
//随机一个数组的位置
int getVirualVecPos();
//一个新连接
void addClient(client *cli)