keepalived track script introduce

前面简单的介绍了一下keepalived track script | interface weight & instance priority & election的关系, 

http://blog.163.com/digoal@126/blog/static/163877040201471992259474/

本文将重点介绍一下keepalived跟踪脚本的配置用法以及参数的解释 : 

keepalived VRRP配置中有一个配置项, vrrp_script : 

截取自 : keepalived.conf.SYNOPSIS

        2.1. VRRP scripts

        The configuration block looks like :

vrrp_script <STRING> {          # VRRP script declaration
    script <QUOTED_STRING>      # script to run periodically
    interval <INTEGER>          # run the script this every seconds
    weight <INTEGER:-254..254>  # adjust priority by this weight  , 用于动态变更vrrp_instance优先级(by vrrp_update_priority). 或者路由器状态(当weight=0)
    fall <INTEGER>              # required number of failures for KO switch ,
    rise <INTEGER>              # required number of successes for OK switch
}

The script will be executed periodically, every <interval> seconds. Its exit
code will be recorded for all VRRP instances which will want to monitor it.
Note that the script will only be executed if at least one VRRP instance
monitors it with a non-zero weight. Thus, any number of scripts may be
declared without taking the system down.

If unspecified, the weight equals 2, which means that a success will add +2
to the priority of all VRRP instances which monitor it. On the opposite, a
negative weight will be subtracted from the initial priority in case of
failure.

以上是对脚本的配置, 是否在实例中使用(监控), 需要在相应的vrrp_instance 配置 : 

这里的weight配置将覆盖vrrp_script中weight的配置.

vrrp_instance <STRING> {                # VRRP instance declaration
    track_script {                     # Scripts state we monitor
      <STRING>
      <STRING> weight <INTEGER:-254..254>
      ...
    }
}

脚本对应的数据结构 :

/* external script we call to track local processes */
typedef struct _vrrp_script {
	char			*sname;		/* instance name */
	char			*script;	/* the command to be called */
	long			interval;	/* interval between script calls */
	long			timeout;	/* seconds before script timeout */
	int			weight;		/* weight associated to this script */
	int			result;		/* result of last call to this script: 0..R-1 = KO, R..R+F-1 = OK */
	int			inuse;		/* how many users have weight>0 ? */
	int			rise;		/* R: how many successes before OK */
	int			fall;		/* F: how many failures before KO */
} vrrp_script_t;

注意当配置的weight不等于0时, 用于动态调整vrrp instance的优先级. 并不会直接的改变vrrp的状态.

当weight=0时, 用于变更vrrp_instance的状态例如脚本检测失败, 则vrrp的状态直接变为FAULT. (不管有没有其他节点存在来接管MASTER)

只有脚本的weight配置不等于0时才需要被跟踪(用于跟踪result, 判断ko和ok状态).  跟踪脚本对应的数据结构 :

/* Tracked script structure definition */
typedef struct _tracked_sc {
	int			weight;		/* tracking weight when non-zero */
	vrrp_script_t		*scr;		/* script pointer, cannot be NULL */
} tracked_sc_t;

脚本一旦配置在vrrp instance中启用, 

在调用过程中, 就会动态的改变对应的instance的优先级. (when weight<>0)

或者变更vrrp instance的状态 (when weight=0)

vrrp_script <STRING> {          # VRRP script declaration
    script <QUOTED_STRING>      # script to run periodically
    interval <INTEGER>          # run the script this every seconds
    weight <INTEGER:-254..254>  # adjust priority by this weight  , 不等于0时用于动态变更vrrp_instance优先级(by vrrp_update_priority).
    fall <INTEGER>              # required number of failures for KO switch ,
    rise <INTEGER>              # required number of successes for OK switch
}

当脚本为OK状态时, 并且最终weight(以track_script中的weight覆盖值为准)>0, 则优先级可以加上weight.

当脚本为KO状态时, 并且终止的weight(以track_script中的weight覆盖值为准)<0, 则优先级可以减去weight.

优先级最终的范围是(1到254)

OK和KO和fall, rise的配置有关. 不要关注状态, 就关注这两个值, 因为没有地方标记状态.

通过标记与变更脚本的result值, 通过result值和fall, rise来比较, 判断OK还是KO.

脚本状态的转换过程详细参考 :

vrrp_script_child_thread 函数
        if (WIFEXITED(wait_status)) {
                int status;
                status = WEXITSTATUS(wait_status);  // 脚本返回值为0, 表示执行成功, 非0表示失败.
                if (status == 0) {
                        /* success */
                        if (vscript->result < vscript->rise - 1) {  // result < rise-1, 表示当前还是KO状态
                                vscript->result++;   // KO状态下, 调用成功则result+1.
                        } else {
                                if (vscript->result < vscript->rise)  // result = rise 表示当前是KO状态转变成OK状态
                                        log_message(LOG_INFO, "VRRP_Script(%s) succeeded", vscript->sname);
                                vscript->result = vscript->rise + vscript->fall - 1;  // 脚本从failed状态转变到success状态后, 直接把result改成最大. 要变回KO的话, 还需要fall-1次failure.
                        }
                } else {
                        /* failure */
                        if (vscript->result > vscript->rise) {  // result > rise, 表示当前是OK状态
                                vscript->result--;  //OK状态下, 脚本调用失败的话, result-1.
                        } else {
                                if (vscript->result >= vscript->rise)  // result=rise, 表示当前是OK状态转变成KO状态
                                        log_message(LOG_INFO, "VRRP_Script(%s) failed", vscript->sname);
                                vscript->result = 0;  // 脚本从success状态转变到failed状态后, 直接把result改到最小. 要变回OK的话还需要rise次success
                        }
                }
        }

优先级的变动和脚本状态的关系参考 : 

注意一个脚本对全局weigh的影响只有一次, 例如多次OK状态也最大加一次正的weight.

或者多次KO状态下, 最多也只加一次负的weight.

vrrp_script_weight 函数
	for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) {
		tsc = ELEMENT_DATA(e);
		if (tsc->scr->result == VRRP_SCRIPT_STATUS_DISABLED)
			continue;
		if (tsc->scr->result >= tsc->scr->rise) {     // 当脚本的result>=配置的rise时(即OK态), 如果脚本配置的weight>0 , 那么全局weight累加脚本weight.
			if (tsc->weight > 0)
				weight += tsc->weight;
		} else if (tsc->scr->result < tsc->scr->rise) {  // 当脚本的result<配置的rise时(即KO态), 如果脚本配置的weight<0, 那么全局weight减去脚本的weight.  脚本的result在vrrp_script_child_thread中跟踪.
			if (tsc->weight < 0)
				weight += tsc->weight;
		}
	}

动态调整优先级的范围 : 

如果配置的instance的初始优先级是255的话, 则不受track weight的影响. 见vrrp_update_priority函数的内容.

	if (vrrp->base_priority == VRRP_PRIO_OWNER) {
		/* we will not run a PRIO_OWNER into a non-PRIO_OWNER */
		vrrp->effective_priority = VRRP_PRIO_OWNER;
	} else {
		/* WARNING! we must compute new_prio on a signed int in order
		   to detect overflows and avoid wrapping. */
		new_prio = vrrp->base_priority + prio_offset;
		if (new_prio < 1)
			new_prio = 1;
		else if (new_prio > 254)
			new_prio = 254;
		vrrp->effective_priority = new_prio;
	}

keepalived / include / vrrp.h
#define VRRP_PRIO_OWNER		255		/* priority of the ip owner -- rfc2338.5.3.4 */

换句话说, 只有初始优先级配置<255的instance, 才可以动态调整优先级. 并且动态调整后的优先级范围是1到254.

    priority <INTEGER-0..255>		# VRRP PRIO

[参考]

1. keepalived/vrrp/vrrp_scheduler.c

/* if run after vrrp_init_state(), it will be able to detect scripts that
 * have been disabled because of a sync group and will avoid to start them.
 */
static void
vrrp_init_script(list l)
{
        vrrp_script_t *vscript;
        element e;

        for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) {
                vscript = ELEMENT_DATA(e);
                if (vscript->inuse == 0)
                        vscript->result = VRRP_SCRIPT_STATUS_DISABLED;

                if (vscript->result == VRRP_SCRIPT_STATUS_INIT) {
                        vscript->result = vscript->rise - 1; /* one success is enough */  // 初始化过程中设置result=rise-1
                        thread_add_event(master, vrrp_script_thread, vscript, vscript->interval);
                } else if (vscript->result == VRRP_SCRIPT_STATUS_INIT_GOOD) {
                        vscript->result = vscript->rise; /* one failure is enough */   // 初始化成功, 设置result=rise
                        thread_add_event(master, vrrp_script_thread, vscript, vscript->interval);
                }
        }
}

static int
vrrp_script_child_thread(thread_t * thread)
{
        int wait_status;
        vrrp_script_t *vscript = THREAD_ARG(thread);

        if (thread->type == THREAD_CHILD_TIMEOUT) {
                pid_t pid;

                pid = THREAD_CHILD_PID(thread);

                /* The child hasn't responded. Kill it off. */
                if (vscript->result > vscript->rise) {
                        vscript->result--;
                } else {
                        if (vscript->result == vscript->rise)
                                log_message(LOG_INFO, "VRRP_Script(%s) timed out", vscript->sname);
                        vscript->result = 0;    // 初始化时, 脚本调用超时, 将result改成0(最小)
                }
                kill(pid, SIGTERM);
                thread_add_child(thread->master, vrrp_script_child_timeout_thread,
                                 vscript, pid, 2);
                return 0;
        }

        wait_status = THREAD_CHILD_STATUS(thread);

        if (WIFEXITED(wait_status)) {
                int status;
                status = WEXITSTATUS(wait_status);  // 脚本返回值为0, 表示执行成功, 非0表示失败.
                if (status == 0) {
                        /* success */
                        if (vscript->result < vscript->rise - 1) {  // result < rise-1, 表示当前还是KO状态
                                vscript->result++;   // KO状态下, 调用成功则result+1.
                        } else {
                                if (vscript->result < vscript->rise)  // result = rise 表示当前是KO状态转变成OK状态
                                        log_message(LOG_INFO, "VRRP_Script(%s) succeeded", vscript->sname);
                                vscript->result = vscript->rise + vscript->fall - 1;  // 脚本从failed状态转变到success状态后, 直接把result改成最大.
                        }
                } else {
                        /* failure */
                        if (vscript->result > vscript->rise) {  // result > rise, 表示当前是OK状态
                                vscript->result--;  //OK状态下, 脚本调用失败的话, result-1.
                        } else {
                                if (vscript->result >= vscript->rise)  // result=rise, 表示当前是OK状态转变成KO状态
                                        log_message(LOG_INFO, "VRRP_Script(%s) failed", vscript->sname);
                                vscript->result = 0;  // 脚本从success状态转变到failed状态后, 直接把result改到最小.
                        }
                }
        }

        return 0;
}

/* Update VRRP effective priority based on multiple checkers.
 * This is a thread which is executed every adver_int.
 */
static int
vrrp_update_priority(thread_t * thread)
{
        vrrp_t *vrrp = THREAD_ARG(thread);
        int prio_offset, new_prio;

        /* compute prio_offset right here */
        prio_offset = 0;

        /* Now we will sum the weights of all interfaces which are tracked. */
        if ((!vrrp->sync || vrrp->sync->global_tracking) && !LIST_ISEMPTY(vrrp->track_ifp))
                 prio_offset += vrrp_tracked_weight(vrrp->track_ifp);

        /* Now we will sum the weights of all scripts which are tracked. */
        if ((!vrrp->sync || vrrp->sync->global_tracking) && !LIST_ISEMPTY(vrrp->track_script))
                prio_offset += vrrp_script_weight(vrrp->track_script);

        if (vrrp->base_priority == VRRP_PRIO_OWNER) {
                /* we will not run a PRIO_OWNER into a non-PRIO_OWNER */
                vrrp->effective_priority = VRRP_PRIO_OWNER;
        } else {
                /* WARNING! we must compute new_prio on a signed int in order
                   to detect overflows and avoid wrapping. */
                new_prio = vrrp->base_priority + prio_offset;
                if (new_prio < 1)
                        new_prio = 1;
                else if (new_prio > 254)
                        new_prio = 254;
                vrrp->effective_priority = new_prio;
        }

        /* Register next priority update thread */
        thread_add_timer(master, vrrp_update_priority, vrrp, vrrp->adver_int);
        return 0;
}

2. keepalived/include/vrrp_track.h

/* VRRP script tracking results.
 * The result is an integer between 0 and rise-1 to indicate a DOWN state,
 * or between rise-1 and rise+fall-1 to indicate an UP state. Upon failure,
 * we decrease result and set it to zero when we pass below rise. Upon
 * success, we increase result and set it to rise+fall-1 when we pass above
 * rise-1.
 */
#define VRRP_SCRIPT_STATUS_DISABLED  -3
#define VRRP_SCRIPT_STATUS_INIT_GOOD -2
#define VRRP_SCRIPT_STATUS_INIT      -1

/* external script we call to track local processes */
typedef struct _vrrp_script {
	char			*sname;		/* instance name */
	char			*script;	/* the command to be called */
	long			interval;	/* interval between script calls */
	long			timeout;	/* seconds before script timeout */
	int			weight;		/* weight associated to this script */
	int			result;		/* result of last call to this script: 0..R-1 = KO, R..R+F-1 = OK */
	int			inuse;		/* how many users have weight>0 ? */
	int			rise;		/* R: how many successes before OK */
	int			fall;		/* F: how many failures before KO */
} vrrp_script_t;

/* Tracked script structure definition */
typedef struct _tracked_sc {
	int			weight;		/* tracking weight when non-zero */
	vrrp_script_t		*scr;		/* script pointer, cannot be NULL */
} tracked_sc_t;

[参考]

1. http://blog.163.com/digoal@126/blog/static/163877040201471992259474/

时间: 2024-10-29 16:32:33

keepalived track script introduce的相关文章

keepalived which time exec track script , notify script when vrrp transition

keepalived什么时候调用track script, track interface, notify_* script, notify; 搞清楚这些对设计HA很有必要. 以下这张图大概的画出了跟踪脚本, 跟踪接口, 状态转换, 以及notify脚本的先后关系 :  当然实际的程序设计和这个没有关系, keepalived是3个进程组成的, 主进程, vrrp进程和health_check进程. 这里不作体现.   keepalived.conf配置项 :  跟踪脚本或跟踪接口配置 : tr

keepalived vrrp script|interface weight when positive,nagtive,zero &amp; vrrp&#039;s status transition

本文以实例的形式来展示一下脚本的weight对vrrp的影响(状态或优先级). 注意优先级的变化可能导致vrrp master重新选举, 从而导致状态的变化. 而直接导致状态的变化则是当script weight=0时, 可以直接导致状态的变化.(当然最后还是选举产生的, 除非backup配置了不降级, 那么就不会主动让位.) 首先来看一张图 :  这张图表明了track interface或track script的weight在大于0, 小于0, 等于0这三种状态下, 对VRRP的影响. (

keepalived instance priority don&#039;t impact by track script|interface weight when 255

前面我在写keepalived优先级动态调整时, 写到关于初始优先级设置为255的instance不被动态调整的内容, 原因参考本文末尾部分. 因为 if (vrrp->base_priority == VRRP_PRIO_OWNER) { /* we will not run a PRIO_OWNER into a non-PRIO_OWNER */ vrrp->effective_priority = VRRP_PRIO_OWNER; 本文主要就是实际验证一下. 用的例子参考 http:/

keepalived Transition &amp; Entering {MASTER|BACKUP|FAULT} STATE &amp; first priority affect by track interface|script

本例主要说明1个问题, 当使用脚本或接口的动态优先级调整时, 什么时候优先级会生效. 路由器进入状态后, 动态优先级才会被调整, 没有进入状态前的track都不会影响优先级. 用两个例子来说明问题. 并且初始状态为MASTER和BACKUP, track的先后是有差别的. 如果初始状态时MASTER, 那么是先执行track(此时的脚本调用结果不影响路由器优先级), 然后Transition to MASTER STATE.  如果初始状态是BACKUP, 那么是先Entering to BAC

VBScript Enun Remote CMD Shell代码

Enun Remote CMDShell,喜欢玩cmdshell的朋友可以参考下   效果如图: 复制代码 代码如下: '============================ ' Enun Remote CMDShell v 1.0 '============================ Option Explicit CONST ACCOUNT_LOCK_TIME = 600000    '账户锁定时间,10分钟 CONST LOCKOUT_BAD_COUNT = 3     '密码失

VBScript Enun Remote CMD Shell代码_vbs

效果如图: 复制代码 代码如下: '============================' Enun Remote CMDShell v 1.0'============================ Option Explicit CONST ACCOUNT_LOCK_TIME = 600000    '账户锁定时间,10分钟CONST LOCKOUT_BAD_COUNT = 3     '密码失败次数CONST DEFAULT_WAIT_TIME = 1000     '默认延时,1秒

keepalived modify notify.c &amp; vrrp.c to enforce waiting notify script execute success

我们在设计数据库HA的时候, 为了防止主备同时读写一份数据, 或者主备同时对外提供服务. 备机在切换成主机前, 需要有一个fence操作, 需先将主节点fence掉, 然后再激活备库为主库. 例如我们这边用的一个HA脚本 :  https://raw.githubusercontent.com/digoal/sky_postgresql_cluster/master/INSTALL.txt 或者RHEL的HA套件, 都有类似的FENCE操作. 但是keepalived目前没有切换前的自定义脚本,

Lvs+keepalived 高可用性负载均衡自动化配置

原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://navyaijm.blog.51cto.com/4647068/809397 前言* 随着互联网的发展,提供用户访问的web服务器,必须要保证每天24不间断服务,访问量不断增加,有什么好的web架构既能实现高可用性负载均衡,而且价格又是免费的呢?答案有木有?有!lvs+keepalived 是不错的选择!   一.实验环境:4台centos 5.4 ,以及简单的拓扑图: LVS-

Keepalived双主模型中vrrp_script中的权重改变故障排查

故障重现 keepalived配置如下 # vi /etc/keepalived/keepalived.conf ! Configuration File for keepalived global_defs { notification_email { root@localhost } notification_email_from admin@lnmmp.com smtp_connect_timeout 3 smtp_server 127.0.0.1 router_id LVS_DEVEL