PHP
首页 | 下载 | 博客 | 链接

区域

工具

查看代码的工具推荐用Eclipse Platform,将includes文件路径设置好以后,查找原型/函数/结构相当方便,如果怕麻烦,lxr也是个不错的选择,比如lxr.linux.no


相关链接

启动中的ipvs
运行中的ipvs
ipvs的调度
ipvs的数据报转送

ipvs的hash算法
数据包结构/操作分析
[转]ipvs基本原理/框架


资源链接

netfilter官方指南(中文)
ipvs官方网站(中文)
developerWorks-cluster(中文)


说明

文章中出现的内核代码版本是linux-2.6.26,为了保证行号的一致性,中文的注释没有插入回车/换行符.可能会显得有些紧巴巴的.
由于个人能力有限,网站内容存在许多错误和不足,希望读者能踊跃给予批评指正或建议. 本人联系方式:yubo@yubo.org

ipvs的调度

每当有新的数据报(skb)访问vs的时候,首先ip_vs_in()会在skb中提出与之对应的协议,并在ip_vs_proto_table[]里找出该协议的变量pp; 然后根据skb里的目标协议/地址/端口或者防火墙标记,在ip_vs_svc_table[]或者ip_vs_svc_fwm_table[]里找出虚拟服务的变量svc;最后调用svc->scheduler->schedule()得到dest(真实服务器),该函数是在添加虚拟服务的时候由ip_vs_add_service()定义的.

先来看看svc和rs
svc->destinations和rs->nlist构成一个双向循环链表结构

.
   +----------------------------<----------------------->--------------------------+
   |     +------------------+      +---------------+         +---------------+     |
   |     |svc(ip_vs_service)|      |rs1(ip_vs_dest)|         |rs2(ip_vs_dest)|     |
   +<------> destinations <----------> nlist <-----------------> nlist <---------->+
         |   *scheduler     |      |   addr        |         |   addr        |
         |   *sched_data    |      |   port        |         |   port        |
         |   sched_lock     |      |   flags       |         |   flags       |
         |   addr           |      |   weight      |         |   weight      |
   +---> |   port           |      |   *svc --------->-+     |   *svc --------->---+
   |     |   fwmark         |      |   protocol    |   |     |   protocol    |     |
   |     |   protocol       |      |   vaddr       |   |     |   vaddr       |     |
   |     |   ~              |      |   vport       |   |     |   vport       |     |
   |     |   ~              |      |   vfwmark     |   V     |   vfwmark     |     V
   |     |   ~              |      |   ~           |   |     |   ~           |     |
   |     +------------------+      +---------------+   |     +---------------+     |
   +--<------------------------<-----------------------+-<-------------------------+

svc->scheduler可能会指向的结构有ip_vs_dh_scheduler, ip_vs_lblc_scheduler, ip_vs_lblcr_scheduler, ip_vs_lc_scheduler, ip_vs_nq_scheduler, ip_vs_rr_scheduler, ip_vs_sed_scheduler, ip_vs_sh_scheduler, ip_vs_wlc_scheduler, ip_vs_wrr_scheduler这10种.代表了10种不同的调度方法


轮叫调度
Round-Robin Scheduling

我们先来看看rr

net/ipv4/ipvs/ip_vs_rr.c

  1.  static struct ip_vs_scheduler ip_vs_rr_scheduler = {
  2.   .name = "rr", /* name */
  3.   .refcnt = ATOMIC_INIT(0), //引用计数器
  4.   .module = THIS_MODULE, //模块名
  5.   .init_service = ip_vs_rr_init_svc, //svc初始化时调用的函数
  6.   .done_service = ip_vs_rr_done_svc, //svc注销时ubind用的函数
  7.   .update_service = ip_vs_rr_update_svc, //有新rs加入到svc中时调用的函数
  8.   .schedule = ip_vs_rr_schedule, //选择rs的调度函数
  9.  };

可以看出,核心的调度算法就是ip_vs_rr_schedule()

net/ipv4/ipvs/ip_vs_rr.c

  1.  /*
  2.   * Round-Robin Scheduling
  3.   */
  4.  static struct ip_vs_dest *
  5.  ip_vs_rr_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
  6.  {
  7.   struct list_head *p, *q;
  8.   struct ip_vs_dest *dest;
  9.  
  10.   IP_VS_DBG(6, "ip_vs_rr_schedule(): Scheduling...\n");
  11.  
  12.   write_lock(&svc->sched_lock); //得到写锁
  13.   p = (struct list_head *)svc->sched_data; //将p指向svc->sched_data指向的地址
  14.   p = p->next; //p指向链表下一个节点
  15.   q = p; //将q也指向p指向的位置,p为起始点,q为活动点,开始顺序选取rs地址
  16.   do {
  17.   /* skip list head */
  18.   if (q == &svc->destinations) {
  19.   q = q->next;
  20.   continue;
  21.   }
  22.  
  23.   dest = list_entry(q, struct ip_vs_dest, n_list); //得到dest
  24.   if (!(dest->flags & IP_VS_DEST_F_OVERLOAD) &&
  25.   atomic_read(&dest->weight) > 0)
  26.   /* HIT */
  27.   goto out;
  28.   q = q->next;
  29.   } while (q != p); //如果p==q时,说明q已经在链表中遍历了一圈了,还没有得到dest,则返回NULL
  30.   write_unlock(&svc->sched_lock); //释放锁
  31.   return NULL;
  32.  
  33.   out:
  34.   svc->sched_data = q; //将选取的dest指针q保存起来,作为下一次调度将从这里开始
  35.   write_unlock(&svc->sched_lock); //解锁
  36.   IP_VS_DBG(6, "RR: server %u.%u.%u.%u:%u "
  37.   "activeconns %d refcnt %d weight %d\n",
  38.   NIPQUAD(dest->addr), ntohs(dest->port),
  39.   atomic_read(&dest->activeconns),
  40.   atomic_read(&dest->refcnt), atomic_read(&dest->weight));
  41.  
  42.   return dest; //返回dest
  43.  }

其他调度结构都是大同小异,后面就只分析核心算法了


加权轮叫调度
Weighted Round-Robin Scheduling

net/ipv4/ipvs/ip_vs_wrr.c

  1.  /*
  2.   * Weighted Round-Robin Scheduling
  3.   */
  4.  static struct ip_vs_dest *
  5.  ip_vs_wrr_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
  6.  {
  7.   struct ip_vs_dest *dest;
  8.   struct ip_vs_wrr_mark *mark = svc->sched_data;
  9.   struct list_head *p;
  10.  
  11.   IP_VS_DBG(6, "ip_vs_wrr_schedule(): Scheduling...\n");
  12.  
  13.   /*
  14.   * This loop will always terminate, because mark->cw in (0, max_weight]
  15.   * and at least one server has its weight equal to max_weight.
  16.   */
  17.   write_lock(&svc->sched_lock); //上锁
  18.   p = mark->cl; //p = svc->sched_data->cl
  19.   while (1) {
  20.   if (mark->cl == &svc->destinations) { //如果在起始点上
  21.   /* it is at the head of the destination list */
  22.  
  23.   if (mark->cl == mark->cl->next) { //如果起始点destinations的双向链为空,直接跳出到out
  24.   /* no dest entry */
  25.   dest = NULL;
  26.   goto out;
  27.   }
  28.  
  29.   mark->cl = svc->destinations.next;
  30.   mark->cw -= mark->di;
  31.   if (mark->cw <= 0) {
  32.   mark->cw = mark->mw;
  33.   /*
  34.   * Still zero, which means no available servers.
  35.   */
  36.   if (mark->cw == 0) {
  37.   mark->cl = &svc->destinations;
  38.   IP_VS_ERR_RL("ip_vs_wrr_schedule(): "
  39.   "no available servers\n");
  40.   dest = NULL;
  41.   goto out;
  42.   }
  43.   }
  44.   } else //如果mark->cl不再起始点上,则直接取下一个节点
  45.   mark->cl = mark->cl->next;
  46.  
  47.   if (mark->cl != &svc->destinations) {
  48.   /* not at the head of the list */
  49.   dest = list_entry(mark->cl, struct ip_vs_dest, n_list);
  50.   if (!(dest->flags & IP_VS_DEST_F_OVERLOAD) &&
  51.   atomic_read(&dest->weight) >= mark->cw) {
  52.   /* got it */
  53.   break;
  54.   }
  55.   }
  56.  
  57.   if (mark->cl == p && mark->cw == mark->di) {
  58.   /* back to the start, and no dest is found.
  59.   It is only possible when all dests are OVERLOADED */
  60.   dest = NULL;
  61.   goto out;
  62.   }
  63.   }
  64.  
  65.   IP_VS_DBG(6, "WRR: server %u.%u.%u.%u:%u "
  66.   "activeconns %d refcnt %d weight %d\n",
  67.   NIPQUAD(dest->addr), ntohs(dest->port),
  68.   atomic_read(&dest->activeconns),
  69.   atomic_read(&dest->refcnt),
  70.   atomic_read(&dest->weight));
  71.  
  72.   out:
  73.   write_unlock(&svc->sched_lock);
  74.   return dest;
  75.  }


最小连接调度
Least-Connection Scheduling

net/ipv4/ipvs/ip_vs_lc.c

  1.  /*
  2.   * Least Connection scheduling
  3.   */
  4.  static struct ip_vs_dest *
  5.  ip_vs_lc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
  6.  {
  7.   struct ip_vs_dest *dest, *least = NULL;
  8.   unsigned int loh = 0, doh;
  9.  
  10.   IP_VS_DBG(6, "ip_vs_lc_schedule(): Scheduling...\n");
  11.  
  12.   /*
  13.   * Simply select the server with the least number of
  14.   * (activeconns<<5) + inactconns
  15.   * Except whose weight is equal to zero.
  16.   * If the weight is equal to zero, it means that the server is
  17.   * quiesced, the existing connections to the server still get
  18.   * served, but no new connection is assigned to the server.
  19.   */
  20.  
  21.   list_for_each_entry(dest, &svc->destinations, n_list) {
  22.   if ((dest->flags & IP_VS_DEST_F_OVERLOAD) ||
  23.   atomic_read(&dest->weight) == 0)
  24.   continue;
  25.   doh = ip_vs_lc_dest_overhead(dest);
  26.   if (!least || doh < loh) {
  27.   least = dest;
  28.   loh = doh;
  29.   }
  30.   }
  31.  
  32.   if (least)
  33.   IP_VS_DBG(6, "LC: server %u.%u.%u.%u:%u activeconns %d inactconns %d\n",
  34.   NIPQUAD(least->addr), ntohs(least->port),
  35.   atomic_read(&least->activeconns),
  36.   atomic_read(&least->inactconns));
  37.  
  38.   return least;
  39.  }


加权最小连接调度
Weighted Least-Connection Scheduling

net/ipv4/ipvs/ip_vs_wlc.c

  1.  /*
  2.   * Weighted Least Connection scheduling
  3.   */
  4.  static struct ip_vs_dest *
  5.  ip_vs_wlc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
  6.  {
  7.   struct ip_vs_dest *dest, *least;
  8.   unsigned int loh, doh;
  9.  
  10.   IP_VS_DBG(6, "ip_vs_wlc_schedule(): Scheduling...\n");
  11.  
  12.   /*
  13.   * We calculate the load of each dest server as follows:
  14.   * (dest overhead) / dest->weight
  15.   *
  16.   * Remember -- no floats in kernel mode!!!
  17.   * The comparison of h1*w2 > h2*w1 is equivalent to that of
  18.   * h1/w1 > h2/w2
  19.   * if every weight is larger than zero.
  20.   *
  21.   * The server with weight=0 is quiesced and will not receive any
  22.   * new connections.
  23.   */
  24.  
  25.   list_for_each_entry(dest, &svc->destinations, n_list) {
  26.   if (!(dest->flags & IP_VS_DEST_F_OVERLOAD) &&
  27.   atomic_read(&dest->weight) > 0) {
  28.   least = dest;
  29.   loh = ip_vs_wlc_dest_overhead(least);
  30.   goto nextstage;
  31.   }
  32.   }
  33.   return NULL;
  34.  
  35.   /*
  36.   * Find the destination with the least load.
  37.   */
  38.   nextstage:
  39.   list_for_each_entry_continue(dest, &svc->destinations, n_list) {
  40.   if (dest->flags & IP_VS_DEST_F_OVERLOAD)
  41.   continue;
  42.   doh = ip_vs_wlc_dest_overhead(dest);
  43.   if (loh * atomic_read(&dest->weight) >
  44.   doh * atomic_read(&least->weight)) {
  45.   least = dest;
  46.   loh = doh;
  47.   }
  48.   }
  49.  
  50.   IP_VS_DBG(6, "WLC: server %u.%u.%u.%u:%u "
  51.   "activeconns %d refcnt %d weight %d overhead %d\n",
  52.   NIPQUAD(least->addr), ntohs(least->port),
  53.   atomic_read(&least->activeconns),
  54.   atomic_read(&least->refcnt),
  55.   atomic_read(&least->weight), loh);
  56.  
  57.   return least;
  58.  }


基于局部性的最少链接
Locality-Based Least Connections Scheduling

net/ipv4/ipvs/ip_vs_lblc.c

  1.  static inline struct ip_vs_dest *
  2.  __ip_vs_wlc_schedule(struct ip_vs_service *svc, struct iphdr *iph)
  3.  {
  4.   struct ip_vs_dest *dest, *least;
  5.   int loh, doh;
  6.  
  7.   /*
  8.   * We think the overhead of processing active connections is fifty
  9.   * times higher than that of inactive connections in average. (This
  10.   * fifty times might not be accurate, we will change it later.) We
  11.   * use the following formula to estimate the overhead:
  12.   * dest->activeconns*50 + dest->inactconns
  13.   * and the load:
  14.   * (dest overhead) / dest->weight
  15.   *
  16.   * Remember -- no floats in kernel mode!!!
  17.   * The comparison of h1*w2 > h2*w1 is equivalent to that of
  18.   * h1/w1 > h2/w2
  19.   * if every weight is larger than zero.
  20.   *
  21.   * The server with weight=0 is quiesced and will not receive any
  22.   * new connection.
  23.   */
  24.   list_for_each_entry(dest, &svc->destinations, n_list) {
  25.   if (dest->flags & IP_VS_DEST_F_OVERLOAD)
  26.   continue;
  27.   if (atomic_read(&dest->weight) > 0) {
  28.   least = dest;
  29.   loh = atomic_read(&least->activeconns) * 50
  30.   + atomic_read(&least->inactconns);
  31.   goto nextstage;
  32.   }
  33.   }
  34.   return NULL;
  35.  
  36.   /*
  37.   * Find the destination with the least load.
  38.   */
  39.   nextstage:
  40.   list_for_each_entry_continue(dest, &svc->destinations, n_list) {
  41.   if (dest->flags & IP_VS_DEST_F_OVERLOAD)
  42.   continue;
  43.  
  44.   doh = atomic_read(&dest->activeconns) * 50
  45.   + atomic_read(&dest->inactconns);
  46.   if (loh * atomic_read(&dest->weight) >
  47.   doh * atomic_read(&least->weight)) {
  48.   least = dest;
  49.   loh = doh;
  50.   }
  51.   }
  52.  
  53.   IP_VS_DBG(6, "LBLC: server %d.%d.%d.%d:%d "
  54.   "activeconns %d refcnt %d weight %d overhead %d\n",
  55.   NIPQUAD(least->addr), ntohs(least->port),
  56.   atomic_read(&least->activeconns),
  57.   atomic_read(&least->refcnt),
  58.   atomic_read(&least->weight), loh);
  59.  
  60.   return least;
  61.  }


带复制的基于局部性最少链接
Locality-Based Least Connections with Replication Scheduling

net/ipv4/ipvs/ip_vs_lblcr.c

  1.  static inline struct ip_vs_dest *
  2.  __ip_vs_wlc_schedule(struct ip_vs_service *svc, struct iphdr *iph)
  3.  {
  4.   struct ip_vs_dest *dest, *least;
  5.   int loh, doh;
  6.  
  7.   /*
  8.   * We think the overhead of processing active connections is fifty
  9.   * times higher than that of inactive connections in average. (This
  10.   * fifty times might not be accurate, we will change it later.) We
  11.   * use the following formula to estimate the overhead:
  12.   * dest->activeconns*50 + dest->inactconns
  13.   * and the load:
  14.   * (dest overhead) / dest->weight
  15.   *
  16.   * Remember -- no floats in kernel mode!!!
  17.   * The comparison of h1*w2 > h2*w1 is equivalent to that of
  18.   * h1/w1 > h2/w2
  19.   * if every weight is larger than zero.
  20.   *
  21.   * The server with weight=0 is quiesced and will not receive any
  22.   * new connection.
  23.   */
  24.   list_for_each_entry(dest, &svc->destinations, n_list) {
  25.   if (dest->flags & IP_VS_DEST_F_OVERLOAD)
  26.   continue;
  27.  
  28.   if (atomic_read(&dest->weight) > 0) {
  29.   least = dest;
  30.   loh = atomic_read(&least->activeconns) * 50
  31.   + atomic_read(&least->inactconns);
  32.   goto nextstage;
  33.   }
  34.   }
  35.   return NULL;
  36.  
  37.   /*
  38.   * Find the destination with the least load.
  39.   */
  40.   nextstage:
  41.   list_for_each_entry_continue(dest, &svc->destinations, n_list) {
  42.   if (dest->flags & IP_VS_DEST_F_OVERLOAD)
  43.   continue;
  44.  
  45.   doh = atomic_read(&dest->activeconns) * 50
  46.   + atomic_read(&dest->inactconns);
  47.   if (loh * atomic_read(&dest->weight) >
  48.   doh * atomic_read(&least->weight)) {
  49.   least = dest;
  50.   loh = doh;
  51.   }
  52.   }
  53.  
  54.   IP_VS_DBG(6, "LBLCR: server %d.%d.%d.%d:%d "
  55.   "activeconns %d refcnt %d weight %d overhead %d\n",
  56.   NIPQUAD(least->addr), ntohs(least->port),
  57.   atomic_read(&least->activeconns),
  58.   atomic_read(&least->refcnt),
  59.   atomic_read(&least->weight), loh);
  60.  
  61.   return least;
  62.  }
  63.  
  64.  
  65.  /*
  66.   * If this destination server is overloaded and there is a less loaded
  67.   * server, then return true.
  68.   */
  69.  static inline int
  70.  is_overloaded(struct ip_vs_dest *dest, struct ip_vs_service *svc)
  71.  {
  72.   if (atomic_read(&dest->activeconns) > atomic_read(&dest->weight)) {
  73.   struct ip_vs_dest *d;
  74.  
  75.   list_for_each_entry(d, &svc->destinations, n_list) {
  76.   if (atomic_read(&d->activeconns)*2
  77.   < atomic_read(&d->weight)) {
  78.   return 1;
  79.   }
  80.   }
  81.   }
  82.   return 0;
  83.  }


目标地址散列调度
Destination Hashing Scheduling

net/ipv4/ipvs/ip_vs_dh.c

  1.   */
  2.  static void ip_vs_dh_flush(struct ip_vs_dh_bucket *tbl)
  3.  {
  4.   int i;
  5.   struct ip_vs_dh_bucket *b;
  6.  
  7.   b = tbl;
  8.   for (i=0; i<IP_VS_DH_TAB_SIZE; i++) {
  9.   if (b->dest) {
  10.   atomic_dec(&b->dest->refcnt);
  11.   b->dest = NULL;
  12.   }
  13.   b++;
  14.   }
  15.  }
  16.  
  17.  
  18.  static int ip_vs_dh_init_svc(struct ip_vs_service *svc)
  19.  {
  20.   struct ip_vs_dh_bucket *tbl;
  21.  
  22.   /* allocate the DH table for this service */
  23.   tbl = kmalloc(sizeof(struct ip_vs_dh_bucket)*IP_VS_DH_TAB_SIZE,
  24.   GFP_ATOMIC);
  25.   if (tbl == NULL) {
  26.   IP_VS_ERR("ip_vs_dh_init_svc(): no memory\n");
  27.   return -ENOMEM;
  28.   }
  29.   svc->sched_data = tbl;
  30.   IP_VS_DBG(6, "DH hash table (memory=%Zdbytes) allocated for "
  31.   "current service\n",
  32.   sizeof(struct ip_vs_dh_bucket)*IP_VS_DH_TAB_SIZE);
  33.  
  34.   /* assign the hash buckets with the updated service */
  35.   ip_vs_dh_assign(tbl, svc);
  36.  
  37.   return 0;
  38.  }
  39.  
  40.  
  41.  static int ip_vs_dh_done_svc(struct ip_vs_service *svc)
  42.  {
  43.   struct ip_vs_dh_bucket *tbl = svc->sched_data;
  44.  
  45.   /* got to clean up hash buckets here */
  46.   ip_vs_dh_flush(tbl);
  47.  
  48.   /* release the table itself */
  49.   kfree(svc->sched_data);
  50.   IP_VS_DBG(6, "DH hash table (memory=%Zdbytes) released\n",
  51.   sizeof(struct ip_vs_dh_bucket)*IP_VS_DH_TAB_SIZE);
  52.  
  53.   return 0;
  54.  }
  55.  
  56.  
  57.  static int ip_vs_dh_update_svc(struct ip_vs_service *svc)
  58.  {
  59.   struct ip_vs_dh_bucket *tbl = svc->sched_data;
  60.  
  61.   /* got to clean up hash buckets here */
  62.   ip_vs_dh_flush(tbl);
  63.  
  64.   /* assign the hash buckets with the updated service */
  65.   ip_vs_dh_assign(tbl, svc);
  66.  
  67.   return 0;
  68.  }
  69.  
  70.  
  71.  /*
  72.   * If the dest flags is set with IP_VS_DEST_F_OVERLOAD,
  73.   * consider that the server is overloaded here.
  74.   */
  75.  static inline int is_overloaded(struct ip_vs_dest *dest)
  76.  {
  77.   return dest->flags & IP_VS_DEST_F_OVERLOAD;
  78.  }
  79.  
  80.  
  81.  /*
  82.   * Destination hashing scheduling
  83.   */
  84.  static struct ip_vs_dest *
  85.  ip_vs_dh_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
  86.  {
  87.   struct ip_vs_dest *dest;
  88.   struct ip_vs_dh_bucket *tbl;
  89.   struct iphdr *iph = ip_hdr(skb);
  90.  
  91.   IP_VS_DBG(6, "ip_vs_dh_schedule(): Scheduling...\n");
  92.  
  93.   tbl = (struct ip_vs_dh_bucket *)svc->sched_data;
  94.   dest = ip_vs_dh_get(tbl, iph->daddr);
  95.   if (!dest
  96.   || !(dest->flags & IP_VS_DEST_F_AVAILABLE)
  97.   || atomic_read(&dest->weight) <= 0
  98.   || is_overloaded(dest)) {
  99.   return NULL;
  100.   }
  101.  
  102.   IP_VS_DBG(6, "DH: destination IP address %u.%u.%u.%u "
  103.   "--> server %u.%u.%u.%u:%d\n",
  104.   NIPQUAD(iph->daddr),
  105.   NIPQUAD(dest->addr),
  106.   ntohs(dest->port));
  107.  
  108.   return dest;
  109.  }


源地址散列调度
Source Hashing Scheduling

net/ipv4/ipvs/ip_vs_sh.c

  1.  /*
  2.   * Source Hashing scheduling
  3.   */
  4.  static struct ip_vs_dest *
  5.  ip_vs_sh_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
  6.  {
  7.   struct ip_vs_dest *dest;
  8.   struct ip_vs_sh_bucket *tbl;
  9.   struct iphdr *iph = ip_hdr(skb);
  10.  
  11.   IP_VS_DBG(6, "ip_vs_sh_schedule(): Scheduling...\n");
  12.  
  13.   tbl = (struct ip_vs_sh_bucket *)svc->sched_data;
  14.   dest = ip_vs_sh_get(tbl, iph->saddr);
  15.   if (!dest
  16.   || !(dest->flags & IP_VS_DEST_F_AVAILABLE)
  17.   || atomic_read(&dest->weight) <= 0
  18.   || is_overloaded(dest)) {
  19.   return NULL;
  20.   }
  21.  
  22.   IP_VS_DBG(6, "SH: source IP address %u.%u.%u.%u "
  23.   "--> server %u.%u.%u.%u:%d\n",
  24.   NIPQUAD(iph->saddr),
  25.   NIPQUAD(dest->addr),
  26.   ntohs(dest->port));
  27.  
  28.   return dest;
  29.  }


最短预期延时调度
Shortest Expected Delay Scheduling

net/ipv4/ipvs/ip_vs_sed.c

  1.  /*
  2.   * Weighted Least Connection scheduling
  3.   */
  4.  static struct ip_vs_dest *
  5.  ip_vs_sed_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
  6.  {
  7.   struct ip_vs_dest *dest, *least;
  8.   unsigned int loh, doh;
  9.  
  10.   IP_VS_DBG(6, "ip_vs_sed_schedule(): Scheduling...\n");
  11.  
  12.   /*
  13.   * We calculate the load of each dest server as follows:
  14.   * (server expected overhead) / dest->weight
  15.   *
  16.   * Remember -- no floats in kernel mode!!!
  17.   * The comparison of h1*w2 > h2*w1 is equivalent to that of
  18.   * h1/w1 > h2/w2
  19.   * if every weight is larger than zero.
  20.   *
  21.   * The server with weight=0 is quiesced and will not receive any
  22.   * new connections.
  23.   */
  24.  
  25.   list_for_each_entry(dest, &svc->destinations, n_list) {
  26.   if (!(dest->flags & IP_VS_DEST_F_OVERLOAD) &&
  27.   atomic_read(&dest->weight) > 0) {
  28.   least = dest;
  29.   loh = ip_vs_sed_dest_overhead(least);
  30.   goto nextstage;
  31.   }
  32.   }
  33.   return NULL;
  34.  
  35.   /*
  36.   * Find the destination with the least load.
  37.   */
  38.   nextstage:
  39.   list_for_each_entry_continue(dest, &svc->destinations, n_list) {
  40.   if (dest->flags & IP_VS_DEST_F_OVERLOAD)
  41.   continue;
  42.   doh = ip_vs_sed_dest_overhead(dest);
  43.   if (loh * atomic_read(&dest->weight) >
  44.   doh * atomic_read(&least->weight)) {
  45.   least = dest;
  46.   loh = doh;
  47.   }
  48.   }
  49.  
  50.   IP_VS_DBG(6, "SED: server %u.%u.%u.%u:%u "
  51.   "activeconns %d refcnt %d weight %d overhead %d\n",
  52.   NIPQUAD(least->addr), ntohs(least->port),
  53.   atomic_read(&least->activeconns),
  54.   atomic_read(&least->refcnt),
  55.   atomic_read(&least->weight), loh);
  56.  
  57.   return least;
  58.  }


不排队调度
Never Queue Scheduling

net/ipv4/ipvs/ip_vs_nq.c

  1.  /*
  2.   * Weighted Least Connection scheduling
  3.   */
  4.  static struct ip_vs_dest *
  5.  ip_vs_nq_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
  6.  {
  7.   struct ip_vs_dest *dest, *least = NULL;
  8.   unsigned int loh = 0, doh;
  9.  
  10.   IP_VS_DBG(6, "ip_vs_nq_schedule(): Scheduling...\n");
  11.  
  12.   /*
  13.   * We calculate the load of each dest server as follows:
  14.   * (server expected overhead) / dest->weight
  15.   *
  16.   * Remember -- no floats in kernel mode!!!
  17.   * The comparison of h1*w2 > h2*w1 is equivalent to that of
  18.   * h1/w1 > h2/w2
  19.   * if every weight is larger than zero.
  20.   *
  21.   * The server with weight=0 is quiesced and will not receive any
  22.   * new connections.
  23.   */
  24.  
  25.   list_for_each_entry(dest, &svc->destinations, n_list) {
  26.  
  27.   if (dest->flags & IP_VS_DEST_F_OVERLOAD ||
  28.   !atomic_read(&dest->weight))
  29.   continue;
  30.  
  31.   doh = ip_vs_nq_dest_overhead(dest);
  32.  
  33.   /* return the server directly if it is idle */
  34.   if (atomic_read(&dest->activeconns) == 0) {
  35.   least = dest;
  36.   loh = doh;
  37.   goto out;
  38.   }
  39.  
  40.   if (!least ||
  41.   (loh * atomic_read(&dest->weight) >
  42.   doh * atomic_read(&least->weight))) {
  43.   least = dest;
  44.   loh = doh;
  45.   }
  46.   }
  47.  
  48.   if (!least)
  49.   return NULL;
  50.  
  51.   out:
  52.   IP_VS_DBG(6, "NQ: server %u.%u.%u.%u:%u "
  53.   "activeconns %d refcnt %d weight %d overhead %d\n",
  54.   NIPQUAD(least->addr), ntohs(least->port),
  55.   atomic_read(&least->activeconns),
  56.   atomic_read(&least->refcnt),
  57.   atomic_read(&least->weight), loh);
  58.  
  59.   return least;
  60.  }
 
Done in 0.466256141663 seconds