NQ(Never Queue)调度算法,即当真实服务器中有空闲的时,先调度到空闲服务器,否则依据SED算法调度。
调度器注册
NQ调度器的定义结构为ip_vs_nq_scheduler,使用函数register_ip_vs_scheduler注册到IPVS的调度器系统中。
static struct ip_vs_scheduler ip_vs_nq_scheduler =
{
.name = "nq",
.refcnt = ATOMIC_INIT(0),
.module = THIS_MODULE,
.n_list = LIST_HEAD_INIT(ip_vs_nq_scheduler.n_list),
.schedule = ip_vs_nq_schedule,
};
static int __init ip_vs_nq_init(void)
{
return register_ip_vs_scheduler(&ip_vs_nq_scheduler);
}
调度处理
首先看一下NQ算法中真实服务器的Overhead的计算函数,可见,其与调度器SED(Shortest Expected Delay)中的Overhead计算一致。
static inline int ip_vs_nq_dest_overhead(struct ip_vs_dest *dest)
{
/* We only use the active connection number in the cost calculation here.
*/
return atomic_read(&dest->activeconns) + 1;
}
以下为NQ调度算法处理函数ip_vs_nq_schedule,在遍历虚拟服务所关联的真实服务器链表时,首先选择还没有任何活动连接的真实服务器。否则,选择负荷最小的真实服务器,每个真实服务器负荷的计算与SED调度器相同。
static struct ip_vs_dest *ip_vs_nq_schedule(struct ip_vs_service *svc, const struct sk_buff *skb, struct ip_vs_iphdr *iph)
{
struct ip_vs_dest *dest, *least = NULL;
int loh = 0, doh;
list_for_each_entry_rcu(dest, &svc->destinations, n_list) {
if (dest->flags & IP_VS_DEST_F_OVERLOAD || !atomic_read(&dest->weight))
continue;
doh = ip_vs_nq_dest_overhead(dest);
/* return the server directly if it is idle */
if (atomic_read(&dest->activeconns) == 0) {
least = dest;
loh = doh;
goto out;
}
if (!least ||
((__s64)loh * atomic_read(&dest->weight) > (__s64)doh * atomic_read(&least->weight))) {
least = dest;
loh = doh;
}
}
真实服务器负荷等于其overHead除以其权重Weight,以下为比较两个真实服务器负荷的公式:
h1/w1 > h2/w2
如果以上条件语句成立,表明真实服务器h1的负荷大于h2的负荷。将以上等式变换为乘法操作,如下:
h1*w2 > h2*w1
内核版本 4.15