(34)過期窗口清理與過載超時(V0.5)(LoadBalanceAgent部分)-【Lars-基于C++負(fù)載均衡遠(yuǎn)程服務(wù)器調(diào)度系統(tǒng)教程】

【Lars教程目錄】

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


【Lars系統(tǒng)概述】
第1章-概述
第2章-項(xiàng)目目錄構(gòu)建


【Lars系統(tǒng)之Reactor模型服務(wù)器框架模塊】
第1章-項(xiàng)目結(jié)構(gòu)與V0.1雛形
第2章-內(nèi)存管理與Buffer封裝
第3章-事件觸發(fā)EventLoop
第4章-鏈接與消息封裝
第5章-Client客戶端模型
第6章-連接管理及限制
第7章-消息業(yè)務(wù)路由分發(fā)機(jī)制
第8章-鏈接創(chuàng)建/銷毀Hook機(jī)制
第9章-消息任務(wù)隊(duì)列與線程池
第10章-配置文件讀寫功能
第11章-udp服務(wù)與客戶端
第12章-數(shù)據(jù)傳輸協(xié)議protocol buffer
第13章-QPS性能測試
第14章-異步消息任務(wù)機(jī)制
第15章-鏈接屬性設(shè)置功能


【Lars系統(tǒng)之DNSService模塊】
第1章-Lars-dns簡介
第2章-數(shù)據(jù)庫創(chuàng)建
第3章-項(xiàng)目目錄結(jié)構(gòu)及環(huán)境構(gòu)建
第4章-Route結(jié)構(gòu)的定義
第5章-獲取Route信息
第6章-Route訂閱模式
第7章-Backend Thread實(shí)時監(jiān)控


【Lars系統(tǒng)之Report Service模塊】
第1章-項(xiàng)目概述-數(shù)據(jù)表及proto3協(xié)議定義
第2章-獲取report上報數(shù)據(jù)
第3章-存儲線程池及消息隊(duì)列


【Lars系統(tǒng)之LoadBalance Agent模塊】
第1章-項(xiàng)目概述及構(gòu)建
第2章-主模塊業(yè)務(wù)結(jié)構(gòu)搭建
第3章-Report與Dns Client設(shè)計(jì)與實(shí)現(xiàn)
第4章-負(fù)載均衡模塊基礎(chǔ)設(shè)計(jì)
第5章-負(fù)載均衡獲取Host主機(jī)信息API
第6章-負(fù)載均衡上報Host主機(jī)信息API
第7章-過期窗口清理與過載超時(V0.5)
第8章-定期拉取最新路由信息(V0.6)
第9章-負(fù)載均衡獲取Route信息API(0.7)
第10章-API初始化接口(V0.8)
第11章-Lars Agent性能測試工具
第12章- Lars啟動工具腳本


8) 過期窗口清理與過載超時(V0.5)

? 本節(jié)為idle過期窗口清理與overload過載超時機(jī)制。

? 假設(shè)節(jié)點(diǎn)h長期處于idle,已經(jīng)累計(jì)vsucc = 100000, err = 0;此時突然h過載,API調(diào)用產(chǎn)生了大量的錯誤,假設(shè)匯報了500個失敗,于是verr = 500,此時節(jié)點(diǎn)的失敗率0.5%,尚未被判定為過載;且因?yàn)橹伴L期運(yùn)行的成功個數(shù)太多,使得需要更多的錯誤匯報才會讓LB感知到h過載

將idle節(jié)點(diǎn)每隔一定時間(默認(rèn)15s)重置為idle初始狀態(tài)(vsucc = 270, verr = 0
于是將節(jié)點(diǎn)的運(yùn)行情況按照15s分隔,我們永遠(yuǎn)只關(guān)注當(dāng)前15s內(nèi)此節(jié)點(diǎn)的狀態(tài),于是過載的節(jié)點(diǎn)將會被更快感知.

? 首先,我們在配置文件中加入一些參數(shù)。

lars_loadbalance_agent/conf/lars_lb_agent.conf

;整個窗口的真實(shí)失敗率閾值
window_err_rate=0.7

;對于某個modid/cmdid下的某個idle狀態(tài)的host,需要清理一次負(fù)載信息的周期
idle_timeout=15

;對于某個modid/cmdid/下的某個overload狀態(tài)的host,在過載隊(duì)列等待的最大時間
overload_timeout=15

? 我們在配置文件加載的時候,將這幾個參數(shù)一并加載。

lars_loadbalance_agent/include/main_server.h

#pragma once
#include "lars_reactor.h"
#include "lars.pb.h"
#include "route_lb.h"

struct load_balance_config
{
    //經(jīng)過若干次獲取請求host節(jié)點(diǎn)后,試探選擇一次overload過載節(jié)點(diǎn)
    int probe_num; 

    //初始化host_info主機(jī)信息訪問成功的個數(shù),防止剛啟動時少量失敗就認(rèn)為過載
    int init_succ_cnt;

    //當(dāng)idle節(jié)點(diǎn)切換至over_load時的初始化失敗次數(shù),主要為了累計(jì)一定成功次數(shù)才能切換會idle
    int init_err_cnt;

    //當(dāng)idle節(jié)點(diǎn)失敗率高于此值,節(jié)點(diǎn)變overload狀態(tài)
    float err_rate;

    //當(dāng)overload節(jié)點(diǎn)成功率高于此值,節(jié)點(diǎn)變成idle狀態(tài)
    float succ_rate;

    //當(dāng)idle節(jié)點(diǎn)連續(xù)失敗次數(shù)超過此值,節(jié)點(diǎn)變成overload狀態(tài)
    int contin_err_limit;

    //當(dāng)overload節(jié)點(diǎn)連續(xù)成功次數(shù)超過此值, 節(jié)點(diǎn)變成idle狀態(tài)
    int contin_succ_limit;

    //當(dāng)前agent本地ip地址(用于上報 填充caller字段)
    uint32_t local_ip;

// *************************************
    //整個窗口的真實(shí)失敗率閾值
    float window_err_rate;

    //對于某個modid/cmdid下的某個idle狀態(tài)的host,需要清理一次負(fù)載信息的周期
    int idle_timeout;

    //對于某個modid/cmdid/下的某個overload狀態(tài)的host,在過載隊(duì)列等待的最大時間
    int overload_timeout;
};
// *************************************

lars_loadbalance_agent/src/main_server.cpp

static void init_lb_agent()
{
    //1. 加載配置文件
    config_file::setPath("./conf/lars_lb_agent.conf");
    lb_config.probe_num = config_file::instance()->GetNumber("loadbalance", "probe_num", 10);
    lb_config.init_succ_cnt = config_file::instance()->GetNumber("loadbalance", "init_succ_cnt", 180);
    lb_config.init_err_cnt = config_file::instance()->GetNumber("loadbalance", "init_err_cnt", 5);
    lb_config.err_rate = config_file::instance()->GetFloat("loadbalance", "err_rate", 0.1);
    lb_config.succ_rate = config_file::instance()->GetFloat("loadbalance", "succ_rate", 0.92);
    lb_config.contin_succ_limit = config_file::instance()->GetNumber("loadbalance", "contin_succ_limit", 10);
    lb_config.contin_err_limit = config_file::instance()->GetNumber("loadbalance", "contin_err_limit", 10);
  //*******************************************
    lb_config.window_err_rate = config_file::instance()->GetFloat("loadbalance", "window_err_rate", 0.7);
    lb_config.idle_timeout = config_file::instance()->GetNumber("loadbalance", "idle_timeout", 15);
    lb_config.overload_timeout = config_file::instance()->GetNumber("loadbalance", "overload_timeout", 15);
  //*******************************************
    //2. 初始化3個route_lb模塊
    create_route_lb();

    //3. 加載本地ip
    char my_host_name[1024];
    if (gethostname(my_host_name, 1024) == 0) {
        struct hostent *hd = gethostbyname(my_host_name);

        if (hd)
        {
            struct sockaddr_in myaddr;
            myaddr.sin_addr = *(struct in_addr*)hd->h_addr;
            lb_config.local_ip = ntohl(myaddr.sin_addr.s_addr);
        }
    }

    if (!lb_config.local_ip)  {
        struct in_addr inaddr;
        inet_aton("127.0.0.1", &inaddr);
        lb_config.local_ip = ntohl(inaddr.s_addr);
    }
}

? 接下來我們要在load_balance進(jìn)行report()的時候,之后可以觸發(fā)判定

lars_loadbalance_agent/src/load_balance.cpp

//上報當(dāng)前host主機(jī)調(diào)用情況給遠(yuǎn)端repoter service
void load_balance::report(int ip, int port, int retcode)
{
    //定義當(dāng)前時間
    long current_time = time(NULL);
  
        //...
    //...
  
    // 窗口檢查和超時機(jī)制 
    if (hi->overload == false) {
        //節(jié)點(diǎn)是idle狀態(tài)
        if (current_time - hi->idle_ts >= lb_config.idle_timeout) {
            //時間窗口到達(dá),需要對idle節(jié)點(diǎn)清理負(fù)載均衡數(shù)據(jù)
            if (hi->check_window() == true)   {
                //將此節(jié)點(diǎn) 設(shè)置為過載
                struct in_addr saddr;
                saddr.s_addr = htonl(hi->ip);

                printf("[%d, %d] host %s:%d change to overload cause windows err rate too high, read succ %u, real err %u\n",
                        _modid, _cmdid, inet_ntoa(saddr), hi->port, hi->rsucc, hi->rerr);

                //設(shè)置為overload狀態(tài)
                hi->set_overload();
                //移出_idle_list,放入_overload_list
                _idle_list.remove(hi);
                _overload_list.push_back(hi);
            }
            else {
                //重置窗口,回復(fù)負(fù)載默認(rèn)信息
                hi->set_idle();
            }
        }
    }
    else {
        //節(jié)點(diǎn)為overload狀態(tài)
        //那么處于overload的狀態(tài)時間是否已經(jīng)超時
        if (current_time - hi->overload_ts >= lb_config.overload_timeout) {
            struct in_addr saddr;
            saddr.s_addr = htonl(hi->ip);
            printf("[%d, %d] host %s:%d reset to idle, vsucc %u,  verr %u\n",
                    _modid, _cmdid, inet_ntoa(saddr), hi->port, hi->vsucc, hi->verr);

            hi->set_idle();
            //移出overload_list, 放入_idle_list
            _overload_list.remove(hi);
            _idle_list.push_back(hi);
        }
    }
}

? 每次report之前都會記錄一個當(dāng)前時間,那么如果當(dāng)前時間超過一定時間,idleoverload節(jié)點(diǎn)都會進(jìn)行一次判定。

? idle

  1. 如果當(dāng)前時間超過idle的判定時間周期,需要堅(jiān)持是否觸發(fā)窗口條件check_windows()

    lars_loadbalance_agent/src/host_info.cpp

    #include "host_info.h"
    #include "main_server.h"
    
    void host_info::set_idle()
    {
        vsucc = lb_config.init_succ_cnt;
        verr = 0;
        rsucc = 0;
        rerr = 0;
        contin_succ = 0;
        contin_err = 0;
        overload = false;
      //*********************
        idle_ts = time(NULL);//設(shè)置判定為idle狀態(tài)的時刻,也是重置窗口時間
      //*********************
    }
    
    void host_info::set_overload()
    {
        vsucc = 0;
        verr = lb_config.init_err_cnt;//overload的初試虛擬err錯誤次數(shù)
        rsucc = 0;
        rerr = 0;
        contin_err = 0;
        contin_succ = 0;
        overload = true;
      //*********************
        overload_ts = time(NULL);//設(shè)置判定為overload的時刻
      //*********************
    }
    //*********************
    //計(jì)算整個窗口內(nèi)的真實(shí)失敗率,如果達(dá)到連續(xù)失敗窗口值則返回true,代表需要調(diào)整狀態(tài)
    bool host_info::check_window() {
        if (rsucc + rerr == 0) {
            return false; //分母不能為0
        }
    
        if (rerr * 1.0 / (rsucc + rerr) >= lb_config.window_err_rate) {
            return true;
        }
    
        return false;
    }
    //*********************
    
  1. 如果idle節(jié)點(diǎn)超過窗口的錯誤率判斷,那么需要更改idle狀態(tài)為overload

  2. 將idle從idle_list摘掉,放在overload_list中。

overload

如果overload節(jié)點(diǎn)超過指定時間,那么需要將overload節(jié)點(diǎn)切換為idle,重新放回idle_list中。


關(guān)于作者:

作者:Aceld(劉丹冰)

mail: danbing.at@gmail.com
github: https://github.com/aceld
原創(chuàng)書籍gitbook: http://legacy.gitbook.com/@aceld

原創(chuàng)聲明:未經(jīng)作者允許請勿轉(zhuǎn)載, 如果轉(zhuǎn)載請注明出處

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容