I'm writing a DNS server in Go to learn how DNS works and how to write a real, potentially useful program in Go.
One of the reasons I chose Go was for its Go routines instead of threads.
Currently, my DNS server doesn't really do much, it sends the same response for every query it receives.
One thing that confuses me is that my DNS server, even with its Go routines and even though it's small and doesn't do much is 10x slower than BIND.
I ran a program called dnsblast
to send lots of DNS queries at once and these are my results:
BIND
Sending 10,000 queries = 39,000 pps
My server
Sending 10,000 queries = 3,000 pps
Also, as I increase the number of packets I send per second, the server responds to less and less of the queries.
For example: When sending 1,000 queries, the server responds to 100%, but when sending 10,000 queries the server responds to just 66%.
Is there anything to do with networking in Go that could be limiting the performance of my DNS server? Are there settings in Go I can configure?
Currently, the main program looks like this:
func main() {
serv, err := net.ListenPacket("udp", ":53")
if err != nil {
panic(err)
}
defer serv.Close()
for {
tmp := make([]byte, 512)
num_bytes, addr, _ := serv.ReadFrom(tmp)
go handleQuery(serv, bytes.NewBuffer(tmp[:num_bytes]), addr)
}
}
This seems to be a pretty standard way of creating a server in Go from what I've read online.
- Listen for packets
- Save packet data in a buffer
- Process each packet using a separate Go routine.
Are there any best practices to improve my server's throughput or does the server look okay and it's just my partial DNS implementation is slow?
Thanks!