Many people seems to have taken interest into my weird idea to write a PHP DNS daemon in PHP, so I decided to run some experiments. The first one was to setup ~200 domains to this dns server (including my blog’s one), the second one is to run queryperf against it, and against bind9 running on the same host, with the same configuration (ie. same domain list, no recursion, etc).
First, the host:
- CPU: 2x Intel Xeon E5405 (2GHz) ; a total of 8 cores
- RAM: 8GB RAM (4x 2GB DDR2 @667Mhz)
- Hard Disk: 2x1TB HDD (RAID 1, 3ware Inc 7xxx/8xxx-series PATA/SATA-RAID) ; total of 1TB usable
- OS: Linux Gentoo 64bits 2008.0 (multilib) with Linux Kernel 2.6.27-gentoo-r2
The test itself will be a 1 million random queries generated by gen-data-queryperf.py with 40% of random domains.
Some words on results
First, I’d like to say that pinetd2 is still under development, some parts are still not implemented (the DNS server is able to act as a DNS server, that’s the important part for me), and also some optimizations weren’t done yet (for example a query will always cause the same SQL statements to be run, I could prepare those).
The fact I’m running SQLite means the SQL server isn’t able to cache results (the db file might be modified by anyone, anytime, however I don’t know the exact internals of SQLite), and I don’t cache anything either.
When I started writing DNSd, I didn’t especially try to go on performances, features were importants, and realtime was too. Many improvements to speed can still be done (I’m thinking “prepared statments” right now, but also caching domains list, etc) and would help to get those numbers closer to ISC BIND.
The fact DNSd is 1/4 the speed of BIND (2531.89 queries/sec instead of 10071.2 queries/seq, my dns server is runnnin at 25.14% the speed of bind) is impressive. I guess we’ll need more tests, with different backends (MySQL is also supported, in theory) and different hosts, but I was supposing the database overhead would be bigger than that (well, SQLite is fast, but I wasn’t expecting that fast).
To tell you the truth, I am surprised by those results, however these are results on a real host, really running domains (like my blog’s domain), which makes me believe those results are the closest I could get from DNSd performances on a real host.
Now, the raw test results with both bind and PHP DNSd, running from the same host (to avoid network latency, and since I got 8 cores with almost no CPU usage as it’s morning in France, it shouldn’t make a big difference).
Other test results with other hardwares are welcome. I’ll try running the same kind of tests on less powerful hardware too, just to see what I get.
ISC BIND 9.6.0-P1
DNS Query Performance Testing Tool Version: $Id: queryperf.c,v 1.12 2007/09/05 07:36:04 marka Exp $
[Status] Processing input data [Status] Sending queries (beginning with 91.121.45.45) [Status] Testing complete
Statistics:
Parse input file: once Ended due to: reaching end of file
Queries sent: 1000000 queries Queries completed: 1000000 queries Queries lost: 0 queries Queries delayed(?): 0 queries
RTT max: 0.605333 sec RTT min: 0.000035 sec RTT average: 0.001974 sec RTT std deviation: 0.002666 sec RTT out of range: 0 queries
Percentage completed: 100.00% Percentage lost: 0.00%
Started at: Wed Feb 18 06:36:21 2009 Finished at: Wed Feb 18 06:38:00 2009 Ran for: 99.293069 seconds
Queries per second: 10071.196409 qps
PHP DNSd (revision 301) with PHP 5.3.0beta1 and SQLite3 (bundled libsqlite)
DNS Query Performance Testing Tool Version: $Id: queryperf.c,v 1.12 2007/09/05 07:36:04 marka Exp $
[Status] Processing input data [Status] Sending queries (beginning with 87.98.170.177) [Status] Testing complete
Statistics:
Parse input file: once Ended due to: reaching end of file
Queries sent: 1000000 queries Queries completed: 1000000 queries Queries lost: 0 queries Queries delayed(?): 0 queries
RTT max: 0.645355 sec RTT min: 0.000036 sec RTT average: 0.007884 sec RTT std deviation: 0.004824 sec RTT out of range: 0 queries
Percentage completed: 100.00% Percentage lost: 0.00%
Started at: Wed Feb 18 06:38:41 2009 Finished at: Wed Feb 18 06:45:16 2009 Ran for: 394.961920 seconds
Queries per second: 2531.889657 qps
One (or more) last word(s)
The test method is inspired from a link given by James Collins: “the choices for a nameserver“. While comparison can’t be done between the results there and mine (bind’s result are similar, but as said, there were problems with PowerDNS and anyway we are not running in the same conditions) it still looks like I got some chances into getting closer to be a “real” dns server, with PHP code!
Anyway, remember that “there are two sort of lies, lies and benchmarks.” (source: the previous document).
Now, I guess I have no other choice than writing documentation about “how to install DNSd” and “how to setup a DNSd slave”, that’s going to be fun (if anyone can help, I’d be happy, got a public wiki where the doc can be publied).

#1 by MagicalTux on 2009/02/18 - 14:17
Quote
With prepared statements, I reached 3110 qps with same settings. Not bad
#2 by Wim Godden on 2009/02/18 - 17:53
Quote
If you cache the data in APC, it should speed things up quite a bit too.
Even better : to avoid having to cache data on both master and slave, you could just use Memcache. That would also allow you to deploy across multiple servers
#3 by MagicalTux on 2009/02/18 - 20:23
Quote
Caching data in APC wouldn’t be easy, as APC has no interest anyway as an opcode cache (the code is loaded only once). Using APC only for its cache abilities wouldn’t make much sense.
Memcache looks like a better option, but I’ll need to check the caching overhead (is it really better?).
Anyway thanks for your comment.
#4 by Robert on 2009/02/18 - 20:31
Quote
I’m excited to see this if only because it’s refreshing to see someone else who ignored the crowd who say that PHP can only do certain things. I think its good to push a language into areas that others say it shouldn’t, because I think more often than not, the surprises will be pleasant as opposed to disheartening
#5 by Aleksandar on 2009/02/18 - 21:40
Quote
I think that the main reason for DNSd popularity is BIND DNS database format unpopularity
Also, you should consider DNSSEC (RFC4033) as an option.
#6 by MagicalTux on 2009/02/18 - 21:48
Quote
Yep, DNSSEC support is planned, that’s why I implemented RFC 2671 (EDNS0) which is required for DNSSEC.
DNS is made of over 100 RFCs (something around 114, I believe), and has a *lot* of features.
#7 by Yvan on 2009/02/19 - 08:44
Quote
Hello,
I think Win Godden means using caching in memory using new functions in APC:
http://php.net/manual/en/function.apc-fetch.php
This is *really* faster than memcache, as it’s not over a network. Using memcache here would be dangerous, as DNS need really fast answers, so reading a data stored over a network is not recommended.
See http://www.mysqlperformanceblog.com/2006/08/09/cache-performance-comparison/ for a benchmark on APC cache.
#8 by MagicalTux on 2009/02/19 - 08:52
Quote
In this case we got better than APC: array cache. According to the document you posted, it’s at least 4 times faster than APC cache.
The only problem is cache expiration. APC won’t work as expected (expunge is done at query start or end, in a daemon we don’t have that), so if using array cache I’ll have to manage that manually.
The other problem is the goal of this DNS daemon: dynamic content.
Anyway I’ll dig more in this direction to see if a cache is really meaningful in this context.
Pingback: Your own PHP DNS daemon « A Wonderful Life in a Magical Tux
Pingback: DNS-Server auf der Basis von PHP im Leben des wolf-u.li
#9 by Yvan on 2009/02/20 - 12:07
Quote
Array cache is caching in the current script, I was thinking about a single script call, so indeed as it’s a daemon, it can be much easier.
Expiration should be triggered in your daemon, by a specific call (same as «rndc reload» for bind), when you know the database is changed.
So, yes, you should not use APC and use array caching. Are you running an SQL query on each DNS request? If so, cache will be a huge benefit, even if you have very few entries in your cache.