Linux menu

Tuesday, September 23, 2014

DNS Performance Tuning In Linux

Tweaking BIND
Let’s start with tweaking the BIND /etc/named.conf. Well, to my embarrassment I found that indeed there was an error in the forwarders for my name server – I’d been forwarding other queries to a DNS server that no longer exists on my local network. I had to wait for this to time out for every query. I removed it completly and Ah ha! Fixed, I thought... Sort of, now I’m 132% slower. A vast improvement but not really the result I was looking for.
Before I went plunging into named.conf tweaking I thought I should try one more quick thing. Google runs their own public DNS servers so I thought adding a forwarders line to :
forwarders{ 8.8.8.8; 8.8.4.4;}
I did, and I ran namebench again and the result was 150% slower than outside DNS. Alright, that does it, now I’m seriously interested in what is happening. I’ll come back to the forwarders later though.
Looking at the detailed namebench results, my laptop name server is actually the fastest at responding with minimum response time of 1.5ms or so. Unfortunately, it was also the slowest at 2.2 seconds which drags the mean up to close to half a second. This made me think that there is possibly an issue with concurrency – hmm, maybe Apple cobble their version of named – I installed the MacPorts version and lo and behold… No improvement. Next I’ll try djbdns (tinydns and dnscache) and see how it fairs.
Replacing BIND with tinydns and dnscache on OS X
I got my info on how to setup tinydns with launchd on OS X from here which helped me get it running in an OS X way. Otherwise I did a standard tinydns and dnscache install.
1. Install djbdns using MacPorts, I’ll assume you have MacPorts installed, if you don’t go here and install MacPorts before going further. Or if you’re using a Unix/Linux box you’ll need to do this the hard way and follow the daemontools/djbdns instructions you can find here.
Anyway, for my purposes, MacPorts gave me djbdns and the supporting ucspi-tcp package :
port install djbdns
port install ucspi-tcp
This installs the binaries under the /opt/local directory (/opt/local/sbin etc). You’ll need ucspi-tcp to make things easier later on.
2. Let’s create some users for the DNS servers to run as – this is not updated for OS X > 10.5 in the original instructions (nicl has been replaced by dscl) :
dscl . -create /groups/djbdns gid 88
dscl . -create /groups/djbdns passwd '*'
dscl . -create /users/dnsrun uid 88<br />dscl . -create /users/dnsrun gid 88
dscl . -create /users/dnsrun shell /bin/false
dscl . -create /users/dnsrun home /nohome
dscl . -create /users/dnsrun realname dnsrun
dscl . -create /users/dnsrun passwd '*'
dscl . -create/users/dnslog uid 89
dscl . -create /users/dnslog gid 88
dscl . -create /users/dnslog shell /bin/false
dscl . -create /users/dnslog home /nohome
dscl . -create /users/dnslog realname dnslog
dscl . -create /users/dnslog passwd '*'
3. Configure tinydns using tinydns-conf :
/opt/local/sbin/tinydns-conf dnsrun dnslog /etc/tinydns 1.2.3.4
where 1.2.3.4 is the IP address you want tinydns to listen on. We’re going to use 127.0.0.1 because we’ll have dnscache listen for queries and forward them locally.
4. Modify /etc/tinydns/run to point to the full pathnames of the binaries as follows :
exec /opt/local/sbin/envuidgid dnsrun /opt/local/sbin/envdir ./env /opt/local/sbin/softlimit -d300000 /opt/local/bin/tinydns
5. Create a configuration plist file for launchd :
cat > /System/Library/LaunchDaemons/to.yp.cr.tinydns.plist << EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>to.yp.cr.tinydns</string>
<key>ServiceDescription</key>
<string>tinydns</string>
<key>ProgramArguments</key>
<array>
<string>/private/etc/tinydns/run</string>
</array>
<key>OnDemand</key>
<false>
<key>WorkingDirectory</key>
<string>/etc/tinydns</string>
<key>StandardErrorPath</key>
<string>/Library/Logs/tinydns/error.log</string>
<key>StandardOutPath</key>
<string>/Library/Logs/tinydns/out.log</string>
</dict>
</plist>
EOF
6. Now I just needed to create some zone files from my existing named zone files. Fortunately there’s a script out there for that. It relies on allow-transfer being set in your BIND /etc/named.conf so that you can run a zone transfer to build your new tinydns zone file
7. Now start tinydns using launchctl – ensure that named is not still running.
launchctl stop org.isc.named
launchctl load /System/Library/LaunchDaemons/to.yp.cr.tinydns.plist
launchctl start to.yp.cr.tinydns
8. tinydns is made not to do recursive DNS so it will be listening on 127.0.0.1:53. For a recursive nameserver you’ll need to set up dnscache in a similar way to how we have just set up tinydns. I’ll leave this as an exercise for the reader but use the comments if you have difficulty. It should be running on your main IP address and setup so that your local domains are pointing to 127.0.0.1 for resolution.
Once we have both tinydns and dnscache up and running correctly we can run namebench against it again. The results for me? Well, the same, 266% slower than my closest ISP DNS server using the root servers and no forwarders.
What I will do now
What should I do now? Well, maybe I could use forwarders to those faster local DNS servers namebench has identified and make sure that I get the best of both worlds – a local cache populated by a fast localish server. This allows me to still have my own local servers for my development domains and get the speed of a fast DNS server feeding my cache. Turns out that I get within 3 to 5% of the speed of the fast DNS servers close to me on the internet.
Will I change to tinydns/dnscache? I might, but on my laptop I find that both seem to perform at about the same speed with the forwarders set correctly. It’s a bit of a palava to setup tinydns and dnscache on an OSX box that moves around so I’m probably going to stick with the default BIND nameserver on my laptop for the moment – but with some fast forwarders. The forwarders line in my named.conf now looks like this :
forwarders { 68.4.16.30;    // ns1.oc.cox.net
             68.105.28.11;  // cdns1.cox.net
             8.8.8.8;       // google dns
             8.8.4.4;       // google dns
} ;
I left the Google DNS forwarders in there for the moment, I may take them out again later.
What have I learned from this? Speeding up DNS has significant effect on my browser – my original numbers from namebench showed I was waiting around for a couple of seconds for name resolution sometimes.
namebench is well worth a serious exploration in any environment. It can easily show any weaknesses and misconfigurations in your DNS infrastructure and displays the results in a very readable and user friendly way. It turns out that I’d not revisited my named.conf on this laptop since I retired one of my external servers. Other tuning was fine. Revisiting your DNS configuration once in a while is definitely worth it.

No comments: