IPVS调度算法Round-Robin

函数register_ip_vs_scheduler将RR调度器链接到全局链表ip_vs_schedulers上。具体内容请参见:https://blog.csdn.net/sinat_20184565/article/details/100126417。

static struct ip_vs_scheduler ip_vs_rr_scheduler = {
    .name =                 "rr",                   /* name */
    .n_list =               LIST_HEAD_INIT(ip_vs_rr_scheduler.n_list),
    .init_service =         ip_vs_rr_init_svc,
    .add_dest =             NULL,
    .del_dest =             ip_vs_rr_del_dest,
    .schedule =             ip_vs_rr_schedule,
};

static int __init ip_vs_rr_init(void)
{
    return register_ip_vs_scheduler(&ip_vs_rr_scheduler);
}

虚拟服务接口

在添加IPVS虚拟服务的流程中,绑定调度器函数ip_vs_bind_scheduler时,将首先执行调度器init_service函数指针,对于RR调度器,即函数ip_vs_rr_init_svc。之后执行到虚拟服务的绑定。

static int ip_vs_rr_init_svc(struct ip_vs_service *svc)
{
    svc->sched_data = &svc->destinations;
    return 0;
}

int ip_vs_bind_scheduler(struct ip_vs_service *svc, struct ip_vs_scheduler *scheduler)
{
    if (scheduler->init_service) {
        ret = scheduler->init_service(svc);
        if (ret) {
            pr_err("%s(): init error\n", __func__);
            return ret;
        }
    }
    rcu_assign_pointer(svc->scheduler, scheduler);
}

这里是将虚拟服务所对应的真实服务器链表赋予RR调度器结构的成员sched_data。

真实服务器

RR调度器结构没有实现添加真实服务器的操作指针add_dest,因为在上节的初始化服务指针init_service函数中,RR调度器结构的sched_data成员直接指向了虚拟服务的真实服务器链表。所以只要虚拟服务中的真实服务器链表改变,RR调度器结构就可使用更新后的真实服务器链表。

但是,对于真实服务器的删除操作,需要注意的是,如果删除的是真实服务器链表上的第一个元素,需要更新RR调度器结构的sched_data成员。参见以下的RR调度器函数指针del_dest,即函数ip_vs_rr_del_dest:

static int ip_vs_rr_del_dest(struct ip_vs_service *svc, struct ip_vs_dest *dest)
{
    struct list_head *p;

    spin_lock_bh(&svc->sched_lock);
    p = (struct list_head *) svc->sched_data;

    /* dest is already unlinked, so p->prev is not valid but p->next is valid, use it to reach previous entry.
     */
    if (p == &dest->n_list)
            svc->sched_data = p->next->prev;
    spin_unlock_bh(&svc->sched_lock);
    return 0;
}

调度处理

如下调度函数,虚拟服务svc结构成员sched_data保存有上一次调度的真实服务器结构的链表节点,此次调度将由链表中的下一个真实服务器开始遍历,下一个真实服务器要满足两个条件:

1)不能够是已经过载的服务器;
2)权重值大于零。

另外,遍历pass控制真实服务器链表的遍历次数,整个链表仅完整的遍历一次,因为链表元素由可能会发生改变。

static struct ip_vs_dest *ip_vs_rr_schedule(struct ip_vs_service *svc, const struct sk_buff *skb, struct ip_vs_iphdr *iph)
{
    struct list_head *p;
    struct ip_vs_dest *dest, *last;
    int pass = 0;

    p = (struct list_head *) svc->sched_data;
    last = dest = list_entry(p, struct ip_vs_dest, n_list);

    do {
        list_for_each_entry_continue_rcu(dest, &svc->destinations, n_list) {
            if (!(dest->flags & IP_VS_DEST_F_OVERLOAD) && atomic_read(&dest->weight) > 0)
                goto out;    /* HIT */
            if (dest == last)
                goto stop;
        }
        pass++;
        /* Previous dest could be unlinked, do not loop forever. If we stay at head there is no need for 2nd pass.
         */
    } while (pass < 2 && p != &svc->destinations);

out:
    svc->sched_data = &dest->n_list;

    return dest;
}

如下的添加真实服务器时,分别指定此服务器可接受的最高的连接数量(u-threshold)超过此值将不再接收新的连接;以及低连接阈值(l-threshold),当此真实服务器上的连接数量降低到此值以下后,重新开始接受新的连接。

# ipvsadm -A -t 207.175.44.110:80 -s rr
# ipvsadm -a -t 207.175.44.110:80 -r 192.168.10.1:80 -m --u-threshold 2000 --l-threshold  1000 --weight 200

参数u_threshold的判断逻辑参见以下函数ip_vs_bind_dest:

static inline void ip_vs_bind_dest(struct ip_vs_conn *cp, struct ip_vs_dest *dest)
{
    if (dest->u_threshold != 0 &&
        ip_vs_dest_totalconns(dest) >= dest->u_threshold)
        dest->flags |= IP_VS_DEST_F_OVERLOAD;
}

参数l-threshold的判断逻辑参见以下函数ip_vs_unbind_dest。如果设置l-threshold等于0,那么当连接数量降低到u_threshold值的四分之三以下后,清除IP_VS_DEST_F_OVERLOAD标志,开始接受新的连接。

static inline void ip_vs_unbind_dest(struct ip_vs_conn *cp)
{
    struct ip_vs_dest *dest = cp->dest; 

    if (dest->l_threshold != 0) {
        if (ip_vs_dest_totalconns(dest) < dest->l_threshold)
            dest->flags &= ~IP_VS_DEST_F_OVERLOAD;
    } else if (dest->u_threshold != 0) {
        if (ip_vs_dest_totalconns(dest) * 4 < dest->u_threshold * 3)
            dest->flags &= ~IP_VS_DEST_F_OVERLOAD;
    } else {
        if (dest->flags & IP_VS_DEST_F_OVERLOAD)
            dest->flags &= ~IP_VS_DEST_F_OVERLOAD;
    }
}

内核版本 4.15

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页