(31)负载均衡模块基础设计(LoadBalanceAgent部分)-【Lars-基于C++负载均衡远程服务器调度系统教程】

【Lars教程目录】

Lars源代码
https://github.com/aceld/Lars


【Lars系统概述】
第1章-概述
第2章-项目目录构建


【Lars系统之Reactor模型服务器框架模块】
第1章-项目结构与V0.1雏形
第2章-内存管理与Buffer封装
第3章-事件触发EventLoop
第4章-链接与消息封装
第5章-Client客户端模型
第6章-连接管理及限制
第7章-消息业务路由分发机制
第8章-链接创建/销毁Hook机制
第9章-消息任务队列与线程池
第10章-配置文件读写功能
第11章-udp服务与客户端
第12章-数据传输协议protocol buffer
第13章-QPS性能测试
第14章-异步消息任务机制
第15章-链接属性设置功能


【Lars系统之DNSService模块】
第1章-Lars-dns简介
第2章-数据库创建
第3章-项目目录结构及环境构建
第4章-Route结构的定义
第5章-获取Route信息
第6章-Route订阅模式
第7章-Backend Thread实时监控


【Lars系统之Report Service模块】
第1章-项目概述-数据表及proto3协议定义
第2章-获取report上报数据
第3章-存储线程池及消息队列


【Lars系统之LoadBalance Agent模块】
第1章-项目概述及构建
第2章-主模块业务结构搭建
第3章-Report与Dns Client设计与实现
第4章-负载均衡模块基础设计
第5章-负载均衡获取Host主机信息API
第6章-负载均衡上报Host主机信息API
第7章-过期窗口清理与过载超时(V0.5)
第8章-定期拉取最新路由信息(V0.6)
第9章-负载均衡获取Route信息API(0.7)
第10章-API初始化接口(V0.8)
第11章-Lars Agent性能测试工具
第12章- Lars启动工具脚本


5) 负载均衡模块基础设计

5.1 基础

​ 每个模块modid/cmdid下有若干节点,节点的集合称为此模块的路由; 对于每个节点,有两种状态:

  • idle:此节点可用,可作为API(相当于Agent的客户端)请求的节点使用;

  • overload:此节点过载,暂时不可作为API请求的节点使用

    ​ 在请求节点时,有几个关键属性:

  • 虚拟成功次数vsucc,API汇报节点调用结果是成功时,该值+1

  • 虚拟失败次数verr,API汇报节点调用结果是失败时,该值+1

  • 连续成功次数contin_succ,连续请求成功的次数

  • 连续失败次数contin_err,连续请求失败的次数

这4个字段,在节点状态改变时(idle<—>overload),会被重置。

5.2 调度方式

  • 图1


    (31)负载均衡模块基础设计(LoadBalanceAgent部分)-【Lars-基于C++负载均衡远程服务器调度系统教程】_第1张图片
    4-Lars-agent.png
  • 图2


    (31)负载均衡模块基础设计(LoadBalanceAgent部分)-【Lars-基于C++负载均衡远程服务器调度系统教程】_第2张图片
    5-Lars-algorithm.png

如图所示,整体的调度节点的方式大致如下。这里每个节点就是一个Host主机信息,也就是我们需要被管理的主机信息,一个主机信息应该包括基本的ip和port还有一些其他属性。

如图1,API相当于我们的Agent模块的客户端,也是业务端调用的请求主机接口。 API发送GetHost请求,发送给Agent的server端,传递信息包括modID/cmdID. AgentServer 使用UDPserver处理的API网络请求,并且交给了某个"负载均衡算法".

如图2,一个负载均衡算法,我们称之为是一个"load balance", 一个"load balance"对应针对一组modID/cmdID下挂在的全部host信息进行负载。每个"load balance"都会有两个节点队列。一个队列是"idle_list",存放目前可用的Host主机信息(ip+port), 一个队列是"overload_list",存放目前已经过载的Host主机信息(ip+port).

当API对某模块发起节点获取时:

  • Load Balance从空闲队列拿出队列头部节点,作为选取的节点返回,同时将此节点重追到队列尾部;
  • probe机制 :如果此模块过载队列非空,则每经过probe_num次节点获取后(默认=10),给过载队列中的节点一个机会,从过载队列拿出队列头部节点,作为选取的节点返回,让API试探性的用一下,同时将此节点重追到队列尾部;
  • 如果空闲队列为空,说明整个模块过载了,返回过载错误;且也会经过probe_num次节点获取后(默认=10),给过载队列中的节点一个机会,从过载队列拿出队列头部节点,作为选取的节点返回,让API试探性的用一下,同时将此节点重追到队列尾部;

调度就是:从空闲队列轮流选择节点;同时利用probe机制,给过载队列中节点一些被选择的机会

5.2 API层与Agent Load Balance的通信协议

/Lars/base/proto/lars.proto

syntax = "proto3";

package lars;

/* Lars系统的消息ID */
enum MessageId {
    ID_UNKNOW                = 0;  //proto3 enum第一个属性必须是0,用来占位
    ID_GetRouteRequest       = 1;  //向DNS请求Route对应的关系的消息ID
    ID_GetRouteResponse      = 2;  //DNS回复的Route信息的消息ID
    ID_ReportStatusRequest   = 3;  //上报host调用状态信息请求消息ID
    ID_GetHostRequest        = 4;  //API 发送请求host信息给 Lb Agent模块 消息ID
    ID_GetHostResponse       = 5;  //agent 回执给 API host信息的 消息ID
}

enum LarsRetCode {
    RET_SUCC                 = 0;
    RET_OVERLOAD             = 1; //超载
    RET_SYSTEM_ERROR         = 2; //系统错误
    RET_NOEXIST              = 3; //资源不存在
}

//...
//...

// API 请求agent 获取host信息 (UDP)
message GetHostRequest {
    uint32 seq = 1;
    int32 modid = 2;
    int32 cmdid = 3;
}

// Agent回执API的 host信息 (UDP)
message GetHostResponse {
    uint32 seq = 1;
    int32 modid = 2;
    int32 cmdid = 3;
    int32 retcode = 4;
    HostInfo host = 5;    
}

这里主要增加两个ID:ID_GetHostRequestID_GetHostResponse,即,API的getHost请求的发送ID和回收ID。其中两个ID对应的message包为GetHostRequestGetHostResponse

5.3 host_info与Load Balance初始化

我们首先应该定义几个数据结构,分别是

host_info:表示一个host主机的信息

load_balance:针对一组modid/cmdid的负载均衡模块

route_lb:一共3个,和agent的udp server(提供api服务)的数量一致,一个server对应一个route_lb,每个route_lb负责管理多个load_balance

(31)负载均衡模块基础设计(LoadBalanceAgent部分)-【Lars-基于C++负载均衡远程服务器调度系统教程】_第3张图片
20-loadbalance-data-structure.png

host_info

lars_loadbalance_agent/include/host_info.h

#pragma once

/*
 *   被代理的主机基本信息
 *
 * */
struct host_info {
    host_info(uint32_t ip, int port, uint32_t init_vsucc):
        ip(ip),
        port(port),
        vsucc(init_vsucc),
        verr(0),
        rsucc(0),
        rerr(0),
        contin_succ(0),
        contin_err(0),
        overload(false)
    {
        //host_info初始化构造函数
    }

    uint32_t ip;            //host被代理主机IP
    int port;               //host被代理主机端口
    uint32_t vsucc;         //虚拟成功次数(API反馈),用于过载(overload),空闲(idle)判定
    uint32_t verr;          //虚拟失败个数(API反馈),用于过载(overload),空闲(idle)判定
    uint32_t rsucc;         //真实成功个数, 给Reporter上报用户观察
    uint32_t rerr;          //真实失败个数,给Reporter上报用户观察
    uint32_t contin_succ;   //连续成功次数
    uint32_t contin_err;    //连续失败次数

    bool overload;          //是否过载
};

host_info包含,最关键的主机信息ip+port.除了这个还有一些用户负载均衡算法判断的属性。

load_balance

lars_loadbalance_agent/include/load_balance.h

#pragma once
#include 
#include 
#include "host_info.h"
#include "lars.pb.h"

//ip + port为主键的 host信息集合
typedef __gnu_cxx::hash_map   host_map;   // key:uint64(ip+port), value:host_info
typedef __gnu_cxx::hash_map::iterator host_map_it;

//host_info list集合
typedef std::list host_list; 
typedef std::list::iterator host_list_it;


/*
 * 负载均衡算法核心模块
 * 针对一组(modid/cmdid)下的全部host节点的负载规则
 */
class load_balance {
public:
    load_balance(int modid, int cmdid):
        _modid(modid),
        _cmdid(cmdid)
    {
        //load_balance 初始化构造
    }


    //判断是否已经没有host在当前LB节点中
    bool empty() const;

    //从当前的双队列中获取host信息
    int choice_one_host(lars::GetHostResponse &rsp);

    //如果list中没有host信息,需要从远程的DNS Service发送GetRouteHost请求申请
    int pull();

    //根据dns service远程返回的结果,更新_host_map
    void update(lars::GetRouteResponse &rsp);


    //当前load_balance模块的状态
    enum STATUS
    {
        PULLING, //正在从远程dns service通过网络拉取
        NEW      //正在创建新的load_balance模块
    };
    STATUS status;  //当前的状态
    
private:

    int _modid;
    int _cmdid;
    int _access_cnt;    //请求次数,每次请求+1,判断是否超过probe_num阈值

    host_map _host_map; //当前load_balance模块所管理的全部ip + port为主键的 host信息集合

    host_list _idle_list;       //空闲队列
    host_list _overload_list;   //过载队列
};

一个load_balance拥有两个host链表集合,还有一个以ip/port为主键的_host_map集合。

属性:

_idle_list:全部的空闲节点Host集合列表。

_overload_list:全部的过载节点Host集合列表。

_host_map:当前load_balance中全部所管理的ip+port是host总量,是一个hash_map类型。

_modid,_cmdid:当前load_balance所绑定的modid/cmdid

_access_cnt:记录当前load_balance被api的请求次数,主要是用户判断是否触发probe机制(从overload_list中尝试取节点)

status: 当前load_balance所处的状态。包括PULLING,NEW. 是当load_balance在向远程dns service请求host 的时候,如果正在下载中,则为PULLING状态,如果是增加被创建则为NEW状态。

方法

choice_one_host():根据负载均衡算法从两个list中取得一个可用的host信息放在GetRouteResponse &rsp

pull():如果list中没有host信息,需要从远程的DNS Service发送GetRouteHost请求申请。

update():根据dns service远程返回的结果,更新_host_map

以上方法我们暂时先声明,暂不实现,接下来,我们来定义route_lb数据结构

route_lb

/lars_loadbalance_agent/include/route_lb.h

#pragma once
#include "load_balance.h"

//key: modid+cmdid    value: load_balance
typedef __gnu_cxx::hash_map route_map;
typedef __gnu_cxx::hash_map::iterator route_map_it;


/*
 * 针对多组modid/cmdid ,route_lb是管理多个load_balanace模块的
 * 目前设计有3个,和udp-server的数量一致,每个route_lb分别根据
 * modid/cmdid的值做hash,分管不同的modid/cmdid
 *
 * */
class route_lb {
public:
    //构造初始化
    route_lb(int id);

    //agent获取一个host主机,将返回的主机结果存放在rsp中
    int get_host(int modid, int cmdid, lars::GetHostResponse &rsp);

    //根据Dns Service返回的结果更新自己的route_lb_map
    int update_host(int modid, int cmdid, lars::GetRouteResponse &rsp);


private:
    route_map _route_lb_map;  //当前route_lb下的管理的loadbalance
    pthread_mutex_t _mutex; 
    int _id; //当前route_lb的ID编号
};

属性

_route_lb_map: 当前route_lb下的所管理的全部load_balance(一个load_balance负责一组modid/cmdid的集群负载)。其中key是modid/cmdid,value则是load_balance对象.

_mutex:保护_route_lb_map的锁。

_id:当前route_lb的id编号,编号从1-3,与udpserver的数量是一致的。一个agent udp server对应一个id。

方法

get_host():直接处理API业务层发送过来的ID_GetHostRequest请求。agent获取一个host主机,将返回的主机结果存放在rsp中.

update_host():这个是load_balance触发pull()操作,远程Dns Service会返回结果,route_lb根据Dns Service返回的结果更新自己的_route_lb_map.


关于作者:

作者:Aceld(刘丹冰)

mail: [email protected]
github: https://github.com/aceld
原创书籍gitbook: http://legacy.gitbook.com/@aceld

原创声明:未经作者允许请勿转载, 如果转载请注明出处

你可能感兴趣的:((31)负载均衡模块基础设计(LoadBalanceAgent部分)-【Lars-基于C++负载均衡远程服务器调度系统教程】)