all: add configuration to limit max concurrent requests

Currently, there's no upper bound for how many requests that ctrld will
handle at a time. This could be problem on some low capacity routers,
where CPU/RAM is very limited.

This commit adds a configuration to limit how many requests that will be
handled concurrently. The default is 256, which should works well for
most routers (the default concurrent requests of dnsmasq is 150).
This commit is contained in:
Cuong Manh Le
2023-06-16 19:04:30 +07:00
committed by Cuong Manh Le
parent d5e6c7b13f
commit 41139b3343
6 changed files with 63 additions and 9 deletions
+2 -1
View File
@@ -47,6 +47,8 @@ func (p *prog) serveDNS(listenerNum string) error {
failoverRcodes = listenerConfig.Policy.FailoverRcodeNumbers
}
handler := dns.HandlerFunc(func(w dns.ResponseWriter, m *dns.Msg) {
p.sema.acquire()
defer p.sema.release()
q := m.Question[0]
domain := canonicalName(q.Name)
reqId := requestID()
@@ -60,7 +62,6 @@ func (p *prog) serveDNS(listenerNum string) error {
if !matched && listenerConfig.Restricted {
answer = new(dns.Msg)
answer.SetRcode(m, dns.RcodeRefused)
} else {
answer = p.proxy(ctx, upstreams, failoverRcodes, m)
rtt := time.Since(t)
+12
View File
@@ -17,6 +17,8 @@ import (
"github.com/Control-D-Inc/ctrld/internal/router"
)
const defaultSemaphoreCap = 256
var logf = func(format string, args ...any) {
mainLog.Debug().Msgf(format, args...)
}
@@ -36,6 +38,7 @@ type prog struct {
cfg *ctrld.Config
cache dnscache.Cacher
sema semaphore
}
func (p *prog) Start(s service.Service) error {
@@ -56,6 +59,15 @@ func (p *prog) run() {
p.cache = cacher
}
}
p.sema = &chanSemaphore{ready: make(chan struct{}, defaultSemaphoreCap)}
if mcr := p.cfg.Service.MaxConcurrentRequests; mcr != nil {
n := *mcr
if n == 0 {
p.sema = &noopSemaphore{}
} else {
p.sema = &chanSemaphore{ready: make(chan struct{}, n)}
}
}
var wg sync.WaitGroup
wg.Add(len(p.cfg.Listener))
+24
View File
@@ -0,0 +1,24 @@
package main
type semaphore interface {
acquire()
release()
}
type noopSemaphore struct{}
func (n noopSemaphore) acquire() {}
func (n noopSemaphore) release() {}
type chanSemaphore struct {
ready chan struct{}
}
func (c *chanSemaphore) acquire() {
c.ready <- struct{}{}
}
func (c *chanSemaphore) release() {
<-c.ready
}