为保证程序的稳定性和质量,内存要求使用智能指针(c++11),同时使用了boost(智能指针使用c++11)。
1 自定义标准头文件se_std.h
#ifndef H_CF4BC297_2737_4B2E_AB51_C0915F823960
#define H_CF4BC297_2737_4B2E_AB51_C0915F823960
#include <stdexcept>
#include <string>
#include <boost/exception/all.hpp>
/*检查指针参数是否有效*/
#define CHECK_PTRPARAM_ISNULL(x)\
do { \
if(NULL == x) \
SE_THROW("invalid parameter!"); \
} while (0)
/*检查智能指針是否成功,失败抛出异常*/
#define CHECK_SMART_PTR(x)\
do { \
if(!x) \
SE_THROW("out of memory!"); \
} while (0)
/*检查分配内存是否成功,失败抛出异常*/
#define CHECK_MALLOC_ISFAIL(x)\
do { \
if(NULL == x) \
SE_THROW("out of memory!"); \
} while (0)
/*检查并释放内存*/
#define CHECK_FREE(x)\
do {\
if(NULL != x) { \
free(x); x = NULL; \
} \
} while (0)
/*这个宏仅用于代码折叠*/
#define SE_COLLAPSE
/*自定义数据类型,使之在各个平台上都能符合要求*/
#define BYTE unsigned char
#define INT2 short
#define UINT2 unsigned short
#define INT4 int
#define UINT4 unsigned int
#define FLOAT4 float
#define FLOAT8 double
#if defined(_MSC_VER )
#define INT8 __int64
#define UINT8 unsigned __int64 INT8
#else
#define INT8 long long int
#define UINT8 unsigned long long int
#endif
/*
* 自定义异常类和异常类型
*/
struct se_exception : virtual std::exception, virtual boost::exception {};
typedef boost::error_info<struct _tag_error_messsage_, std::string> se_error_message;
/*
* 抛出异常(异常消息、文件名、行号、抛出异常的函数)
* 获取异常消息: std::string err_msg = *boost::get_error_info<se_error_message>(exp);
* 获取文件名: std::string file_name = *boost::get_error_info<boost::throw_file>(exp);
* 获取行号: int at_line = *boost::get_error_info<boost::throw_line>(exp);
* 获取抛出异常的函数: std::string str_api_function = *boost::get_error_info<boost::throw_function>(exp);
*/
#define SE_THROW(msg) throw se_exception()<<se_error_message(msg)\
<<boost::throw_file(__FILE__)\
<<boost::throw_line((int)__LINE__)\
<<boost::throw_function(BOOST_THROW_EXCEPTION_CURRENT_FUNCTION)
#endif /* H_CF4BC297_2737_4B2E_AB51_C0915F823960 */
2 平滑加权轮询算法se_balancing.hpp
/*============================================================================
Author :
Version : 1.0
Copyright :
Description : 负载均衡,根据权重系数计算使用那台服务器,参考Nginx源码实现,平滑加权轮询(smooth weighted round-robin balancing)
算法实现se_balancer::get_next_server_index
Create : 2018-01-06
LastChange :
============================================================================*/
#ifndef H_DC4C657C_63BF_450F_8AD5_42ADCBFF69A8
#define H_DC4C657C_63BF_450F_8AD5_42ADCBFF69A8
#include <string>
#include <vector>
#include <boost/noncopyable.hpp>
#include "se_std.h"
using namespace std;
/*服务器权重系数配置类*/
class se_server {
private:
/*此服务器配置时的权重系数,用于恢复服务器*/
const INT4 m_oldweight;
INT4 m_weight, m_curweight;
public:
se_server(const INT4 &weight) :
m_weight(weight), m_oldweight(weight), m_curweight(0) {}
se_server(const se_server &server) :
m_weight(server.weight()), m_oldweight(server.oldweight()), m_curweight(server.curweight()) {}
virtual ~se_server() {}
public:
inline const INT4 &weight() const {
return this->m_weight;
}
inline void weight(const INT4 &weight) {
this->m_weight = weight;
}
inline const INT4 &curweight() const {
return this->m_curweight;
}
inline void curweight(const INT4 &curweight) {
this->m_curweight = curweight;
}
inline const INT4 &oldweight() const {
return this->m_oldweight;
}
/*获取当前服务器是否健康*/
inline bool health() const {
return (0 == this->m_weight) ? false : true;
}
};
/*实现平滑加权轮询(smooth weighted round-robin balancing)算法类*/
class se_balancer : public boost::noncopyable {
public:
se_balancer() {}
virtual ~se_balancer() {}
public:
/*平滑加权轮询(smooth weighted round-robin balancing)算法*/
inline INT4 get_next_server_index(vector<se_server> &ss) const {
if (1 == ss.size())
return 0;
INT4 i(0), index(-1), total(0);
for (vector<se_server>::iterator it(ss.begin()); it != ss.end(); ++it, ++i) {
it->curweight((it->curweight() + it->weight()));
total += it->weight();
if (-1 == index || ss.at(index).curweight() < it->curweight()) {
index = i;
}
}
se_server &server = ss.at(index);
server.curweight(server.curweight() - total);
return index;
}
/*
* 健康检查线程每过10分钟检查一次不健康的服务器
* 如不健康的服务器可用时,恢复服务器为可用状态
*/
inline void health(const INT4 &index, vector<se_server> &ss) const {
se_server &server = ss.at(index);
server.weight(server.oldweight());
server.curweight(0);
}
/*
* 不再使用不健康的数据库
* 在服务中获取数据库链接后,检查连接状态为关闭时,该数据库将标记为不再使用
* 然后再次通过get_next_server_index获取可使用的数据库
* 如不健康的数据库恢复,数据库健康检查线程在过一段时间后恢复可用
*/
inline void unhealthy(const INT4 &index, vector<se_server> &ss) const {
se_server &server = ss.at(index);
server.weight(0);
server.curweight(0);
}
};
#endif /* H_168E7C16_7638_4EE4_93F6_EE982858139D */
3 模拟测试
#include <cstdlib>
#include <iostream>
#include <vector>
#include "se_std.h"
#include "se_balancing.hpp"
using namespace std;
/*
*
*/
int main(int argc, char** argv) {
try {
se_balancer balancer;
/*保存服务数量和权重系数*/
vector<se_server> ss;
/*
* 模拟设置4台服务器,使用系数分别为0、1、2、3
* 其中权重系数为0的服务器永远不能使用
*/
for (INT4 i(0); i < 4; ++i) {
ss.push_back(se_server(i));
}
/*模拟100次请求分布到各个服务器的情况*/
for (INT4 i(1); i <= 100; ++i)
cout << "第" << i << "次请求:" << balancer.get_next_server_index(ss) << endl;
return 0;
} catch (se_exception &exp) {
cerr << (*boost::get_error_info<se_error_message>(exp)) << endl;
}
}