Performance
Tuning dnsmonster — afpacket, worker counts, sampling, BPF-based traffic splitting, and CPU/memory profiling.
Use afpacket
If you are using dnsmonster as a sniffer and not keeping up with incoming packets, switch on
afpacket with --useAfpacket. Afpacket tends to drastically improve ingestion rate. If you still see
packet drops, raise --afpacketBuffersizeMb. A larger buffer takes more memory at startup and
increases startup time proportionally.
In testing, values above 4096 MB tend to hurt overall daemon performance. If you are at 4096 MB and still seeing problems, the bottleneck is probably not capture — look at the process and output side instead.
Match output capacity to packet rate
If your output accepts 1,000 inserts per second and packets arrive at 10,000 per second, you will drop packets, and the drop rate will get worse over time. When picking an output, consider the capacity of the technology behind it against what you expect to ingest.
To isolate whether the output is the problem, test with --stdoutOutputType=1, drop your real
output, and redirect to /dev/null:
dnsmonster --devName=lo --packetHandlerCount=16 --stdoutOutputType=1 --useAfpacket | pv --rate --line-mode > /dev/null
That gives you output lines per second while keeping metrics and packet loss visible. By default
--stdoutOutputWorkerCount is 8; on a strong CPU you can raise it to find your ceiling. On a small
server you should have no trouble ingesting 500k packets per second.
--packetHandlerCount is set to 16 above to make sure enough workers are consuming incoming
packets. It is an important parameter to tune — the default of 2 is likely too low if you have
hundreds of thousands of packets per second on an interface.
Sampling and BPF-based traffic splitting
Sometimes there are simply too many packets. --sampleRatio ignores packets by ratio. The default
is 1:1, meaning every incoming packet is processed. Setting 2:7 means that for every 7 packets
that arrive, only the first two get processed.
If you conclude that a single dnsmonster cannot handle your load, please raise an issue — and in
the meantime, run multiple instances against the same traffic, split by BPF:
dnsmonster --devName=lo --stdoutOutputType=1 --filter="src portrange 1024-32000"
dnsmonster --devName=lo --stdoutOutputType=1 --filter="src portrange 32001-65535"
These two processes split traffic by port range. Only high ports are included, since the majority of clients use ports above 1024 for DNS queries. Adapt the filter to whatever BPF makes sense in your environment.
Profile CPU and memory
To see exactly what is using CPU and RAM, use the Go profiler hooks behind the --cpuprofile and
--memprofile flags:
# profile CPU
dnsmonster --devName=lo --stdoutOutputType=1 --cpuprofile=1
# you'll see something like this at the beginning of your logs
# 2022/04/11 19:13:51 profile: cpu profiling enabled, /tmp/profile452510705/cpu.pprof
# profile RAM
dnsmonster --devName=lo --stdoutOutputType=1 --memprofile=1
# you'll see something like this at the beginning of your logs
# 2022/04/11 19:15:00 profile: memory profiling enabled (rate 4096), /tmp/profile1290716652/mem.pprof
After dnsmonster exits gracefully, open the generated pprof file in a browser with Go’s perf
tooling and dig into the functions that are bottlenecking:
~/go/bin/pprof -http 127.0.0.1:8882 /tmp/profile2392236212/mem.pprof
A browser session opens automatically with the performance metrics for that run.