LVS
lvs-devel
Google
 
Web LinuxVirtualServer.org

Least Connection Scheduler

To: lvs-devel@xxxxxxxxxxxxxxx
Subject: Least Connection Scheduler
From: Jason Stubbs <j.stubbs@xxxxxxxxxxxxxxx>
Date: Tue, 1 Apr 2008 13:36:08 +0900
Hi all,

This mail half belongs on -user, but there's a patch attached so I'm sending 
it here instead.

I'm wanting to use the LC scheduler with servers of different specs but the 
docs say that it doesn't perform well in this case due to TIME_WAIT 
connections. According to the HOWTO, everything that is not an ESTABLISHED 
connection is counted as inactive.  The current LC scheduler calculates each 
server with the formula of (activeconns<<8) + inactconns.

Now, the only reason I can see for activeconns to be offset by inactconns at 
all is so that round-robining happens when activeconns is equal among several 
servers. If that is in fact the only reason, how does the attached patch 
look? The resulting request distribution should match server resources fairly 
closely with sufficient load. The only downside that I can see is that slower 
servers would get priority when activeconns are equal, but is that really a 
problem?

-- 
Jason Stubbs <j.stubbs@xxxxxxxxxxxxxxx>
LINKTHINK INC.
東京都渋谷区桜ヶ丘町22-14 N.E.S S棟 3F
TEL 03-5728-4772  FAX 03-5728-4773
--- ip_vs_lc.c.orig     2008-04-01 11:35:37.518877853 +0900
+++ ip_vs_lc.c  2008-04-01 12:04:23.769147323 +0900
@@ -40,21 +40,6 @@
 }
 
 
-static inline unsigned int
-ip_vs_lc_dest_overhead(struct ip_vs_dest *dest)
-{
-       /*
-        * We think the overhead of processing active connections is 256
-        * times higher than that of inactive connections in average. (This
-        * 256 times might not be accurate, we will change it later) We
-        * use the following formula to estimate the overhead now:
-        *                dest->activeconns*256 + dest->inactconns
-        */
-       return (atomic_read(&dest->activeconns) << 8) +
-               atomic_read(&dest->inactconns);
-}
-
-
 /*
  *     Least Connection scheduling
  */
@@ -62,14 +47,16 @@
 ip_vs_lc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
 {
        struct ip_vs_dest *dest, *least = NULL;
-       unsigned int loh = 0, doh;
+       unsigned int least_activeconns = 0, least_inactconns = 0;
+       unsigned int dest_activeconns = 0, dest_inactconns = 0;
 
        IP_VS_DBG(6, "ip_vs_lc_schedule(): Scheduling...\n");
 
        /*
-        * Simply select the server with the least number of
-        *        (activeconns<<5) + inactconns
-        * Except whose weight is equal to zero.
+        * Simply select the server with the least number of active
+        * connections, or the least number of inactive connections
+        * where the number of active connections is equal, excluding
+        * servers whose weight is equal to zero.
         * If the weight is equal to zero, it means that the server is
         * quiesced, the existing connections to the server still get
         * served, but no new connection is assigned to the server.
@@ -79,18 +66,23 @@
                if ((dest->flags & IP_VS_DEST_F_OVERLOAD) ||
                    atomic_read(&dest->weight) == 0)
                        continue;
-               doh = ip_vs_lc_dest_overhead(dest);
-               if (!least || doh < loh) {
+               dest_activeconns = atomic_read(&dest->activeconns);
+               dest_inactconns = atomic_read(&dest->inactconns);
+               if (!least || dest_activeconns < least_activeconns) {
+                       least = dest;
+                       least_activeconns = dest_activeconns;
+                       least_inactconns = dest_inactconns;
+               } else if (dest_activeconns == least_activeconns &&
+                       dest_inactconns < least_inactconns) {
                        least = dest;
-                       loh = doh;
+                       least_inactconns = dest_inactconns;
                }
        }
 
        if (least)
        IP_VS_DBG(6, "LC: server %u.%u.%u.%u:%u activeconns %d inactconns %d\n",
                  NIPQUAD(least->addr), ntohs(least->port),
-                 atomic_read(&least->activeconns),
-                 atomic_read(&least->inactconns));
+                 least_activeconns, least_inactconns);
 
        return least;
 }
<Prev in Thread] Current Thread [Next in Thread>