From: Remi Gacogne Date: Wed, 20 Feb 2019 16:47:30 +0000 (+0100) Subject: rec: Use a bounded load-balancing algo to distribute queries X-Git-Tag: dnsdist-1.4.0-alpha1~38^2~4 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=144040bef0b1f65abfb4634f65b1445a84393a1b;p=thirdparty%2Fpdns.git rec: Use a bounded load-balancing algo to distribute queries --- diff --git a/pdns/pdns_recursor.cc b/pdns/pdns_recursor.cc index b8d1f8ade5..7437e71852 100644 --- a/pdns/pdns_recursor.cc +++ b/pdns/pdns_recursor.cc @@ -161,6 +161,8 @@ struct RecThreadInfo deferredAdd_t deferredAdds; struct ThreadPipeSet pipes; std::thread thread; + MT_t* mt{nullptr}; + uint64_t numberOfDistributedQueries{0}; /* handle the web server, carbon, statistics and the control channel */ bool isHandler{false}; /* accept incoming queries (and distributes them to the workers if pdns-distributes-queries is set) */ @@ -226,6 +228,7 @@ static std::set s_avoidUdpSourcePorts; #endif static uint16_t s_minUdpSourcePort; static uint16_t s_maxUdpSourcePort; +static double s_balancingFactor; RecursorControlChannel s_rcc; // only active in the handler thread RecursorStats g_stats; @@ -2385,6 +2388,7 @@ static void handleNewUDPQuestion(int fd, FDMultiplexer::funcparam_t& var) distributeAsyncFunction(data, boost::bind(doProcessUDPQuestion, data, fromaddr, dest, tv, fd)); } else { + ++s_threadInfos[t_id].numberOfDistributedQueries; doProcessUDPQuestion(data, fromaddr, dest, tv, fd); } } @@ -2633,6 +2637,14 @@ static void doStats(void) g_log<(pleaseGetPacketCacheSize) << " packet cache entries, "<<(int)(100.0*broadcastAccFunction(pleaseGetPacketCacheHits)/SyncRes::s_queries) << "% packet cache hits"<numProcesses(); + } + return 0; +} + +static unsigned int selectWorker(unsigned int hash) +{ + if (s_balancingFactor == 0) { + return /* skip handler */ 1 + g_numDistributorThreads + (hash % g_numWorkerThreads); + } + + /* we start with one, representing the query we are currently handling */ + double currentLoad = 1; + std::vector load(g_numWorkerThreads); + for (size_t idx = 0; idx < g_numWorkerThreads; idx++) { + load[idx] = getWorkerLoad(idx); + currentLoad += load[idx]; + // cerr<<"load for worker "< targetLoad) { + // cerr<<"worker "<func = func; @@ -3718,6 +3769,8 @@ static int serviceMain(int argc, char*argv[]) g_statisticsInterval = ::arg().asNum("statistics-interval"); + s_balancingFactor = ::arg().asDouble("distribution-load-factor"); + #ifdef SO_REUSEPORT g_reusePort = ::arg().mustDo("reuseport"); #endif @@ -4017,6 +4070,7 @@ try } MT=std::unique_ptr >(new MTasker(::arg().asNum("stack-size"))); + threadInfo.mt = MT.get(); #ifdef HAVE_PROTOBUF /* start protobuf export threads if needed */ @@ -4316,6 +4370,7 @@ int main(int argc, char **argv) ::arg().set("udp-source-port-avoid", "List of comma separated UDP port number to avoid")="11211"; ::arg().set("rng", "Specify random number generator to use. Valid values are auto,sodium,openssl,getrandom,arc4random,urandom.")="auto"; ::arg().set("public-suffix-list-file", "Path to the Public Suffix List file, if any")=""; + ::arg().set("distribution-load-factor", "The load factor used when PowerDNS is distributing queries to worker threads")="0.0"; #ifdef NOD_ENABLED ::arg().set("new-domain-tracking", "Track newly observed domains (i.e. never seen before).")="no"; ::arg().set("new-domain-log", "Log newly observed domains.")="yes"; diff --git a/pdns/recursordist/docs/settings.rst b/pdns/recursordist/docs/settings.rst index 5d9b529bfb..431d7aa1d5 100644 --- a/pdns/recursordist/docs/settings.rst +++ b/pdns/recursordist/docs/settings.rst @@ -278,6 +278,25 @@ Do not log to syslog, only to stdout. Use this setting when running inside a supervisor that handles logging (like systemd). **Note**: do not use this setting in combination with `daemon`_ as all logging will disappear. +.. _setting-distribution-load-factor: + +``distribution-load-factor`` +---------------------------- +.. versionadded:: 4.1.12 + +- Double +- Default: 0.0 + +If `pdns-distributes-queries`_ is set and this setting is set to another value +than 0, the distributor thread will use a bounded load-balancing algorithm while +distributing queries to worker threads, making sure that no thread is assigned +more queries than distribution-load-factor times the average number of queries +currently processed by all the workers. +For example, with a value of 1.25, no server should get more than 125 % of the +average load. This helps making sure that all the workers have roughly the same +share of queries, even if the incoming traffic is very skewed, with a larger +number of requests asking for the same qname. + .. _setting-distributor-threads: ``distributor-threads``