Golang is perfect for DNS: its concurrency model matches that of DNS extremely well, its standard library is heavily informed both by Unix and by Internet protocols, and its fast and simple. That's unsurprising, since Golang's charter was to modernize C/C++, and DNS is essentially an expression of 1980's C code style.
Though handling DNS requests over UDP is pretty easy and fast in almost any language. TCP connections are much more pleasant to handle by spawning a goroutine per connection. I do assume using goroutines is slower than multiplexing though, but still plenty fast.
CloudFlare is awesome. They're living out one of my fantasies of productizing really well done front-end web serving infrastructure, which I love to see. They appear to have gathered solid team. And they're doing it with Go!
I'd love to see those libraries (sans proprietary modules) show up on GitHub!
I wonder how Lua fits into the picture at CloudFlare with this Go infrastructure, since CloudFlare is also a heavy user of Lua [1] as well and key financial sponsor of LuaJIT [2].
Every request that passes through CloudFlare goes through Lua. It has how we look up and apply a customer rules to a recess. We just recently realized a non-blocking logger option for Nginx [2] using Lua and are in the process of developing a new KT library [3] in Lua.
I would say that C, Lua, and Go are our three primary systems languages. We also use PHP for some of our frontend UI. Dabble in Python in places it makes sense, but usually not in the critical path.
Nice writeup. Especially interesting to see that CloudFlare is using Go for its DNS service. I run a DNS hosting service (https://www.SlickDNS.com) and currently use tinydns from the djbdns suite in my name servers, but I'm writing a drop-in replacement in Go. The goal is to make it much higher performance by using multiple goroutines (tinydns is a single process).
Have you done any analysis to see if tinydns was actually a bottleneck? The work of an authoritative DNS server is extraordinarily simple, and tinydns capitalizes on that.
I'm not an expert, so take this speculation with a grain of salt, but I'd guess this is how it encrypts something in such a way as to require two people:
1. Generate a key, and use it to encrypt and sign your payload. Nothing fancy here; just plain old symmetric encryption and authentication.
2. Use Shamir's Secret Sharing to split the key into pieces. You need any two pieces to reconstruct the key. This is where the magic happens:
The "seamless binary upgrade" part is intriguing (unless it's just a reference to the fact that binaries are self-contained (which is indeed wonderful)).
"The guarantees needed to avoid leaving the server in a bad state when handling panics would be impossible without the defer mechanism Go provides."
I'm only passingly familiar with defer, but I understand it to be equivalent to RAII in C++, Python's with statement, Common Lisp's unwind-protect, and others - does is actually provide something more, and if so, what?
Go's "defer" is not equivalent to RAII. It is function-scoped rather than block-scoped and has semantics based on mutating hidden per-function mutable state at runtime. For example:
func Foo() {
for i := 0; i < 5; i++ {
if Something() {
defer Whatever()
}
}
// ... the compiler can't tell how many
// Whatever()s run here ...
}
Compared to RAII as implemented in for example D with its "scope" statement, "defer" has much more complex semantics, inhibits refactoring since moving things to function bodies or inlining function bodies silently changes semantics, and cannot be optimized as easily, because of the dynamic aspects. IMHO, it has essentially no advantages over RAII and many disadvantages.
It's not at all equivalent to RAII, or really any of those other examples; it's a way of clearing up the control flow of a function that needs cleanup work before it returns, but it is a fussy and error-prone way of expressing scoped resource access.
"Defer" is nice to have, and because it does less than scoped acquisition, it's easier to repurpose for other jobs; that's kind of thematic of Golang --- simple, orthogonal advances over C/Java/C++; a distinct lack of "theoretical" ambition.
I do part time IT and I have repeatedly wanted a more programatically friendly DNS and DHCP solution for our small network. dnsmasq doesn't have a great high-availability story, and BIND+ISCDHCP can be quite complicated to configure for high-availability (plus BIND doesn't seem to have convenient options such as expand-hosts from dnsmasq).
Does this mean Go is ready to use to make a 'simple' forwarding/caching DNS server with the ability to have DHCP update local hostnames? How about DNSSEC validation?
[+] [-] tptacek|12 years ago|reply
[+] [-] staunch|12 years ago|reply
Though handling DNS requests over UDP is pretty easy and fast in almost any language. TCP connections are much more pleasant to handle by spawning a goroutine per connection. I do assume using goroutines is slower than multiplexing though, but still plenty fast.
[+] [-] staunch|12 years ago|reply
I'd love to see those libraries (sans proprietary modules) show up on GitHub!
[+] [-] cloudflare|12 years ago|reply
[+] [-] billmalarky|12 years ago|reply
Seconded, I'll throw my website's name into the hat of "websites saved by cloudflare."
I was really skeptical of them at first but I'm really glad I decided to give them a try.
[+] [-] alberth|12 years ago|reply
[1] http://blog.cloudflare.com/pushing-nginx-to-its-limit-with-l...
[2] http://luajit.org/sponsors.html#sponsorship_perf
[+] [-] dknecht|12 years ago|reply
Here are the most recent lua libraries we have open sourced... [1] https://github.com/agentzh/lua-resty-lock [2] http://github.com/cloudflare/lua-resty-logger-socket [3] http://github.com/cloudflare/lua-resty-kyototycoon
[+] [-] eastdakota|12 years ago|reply
[+] [-] jbarham|12 years ago|reply
[+] [-] tptacek|12 years ago|reply
[+] [-] halayli|12 years ago|reply
https://github.com/halayli/lthread
[+] [-] fizx|12 years ago|reply
[+] [-] pjscott|12 years ago|reply
1. Generate a key, and use it to encrypt and sign your payload. Nothing fancy here; just plain old symmetric encryption and authentication.
2. Use Shamir's Secret Sharing to split the key into pieces. You need any two pieces to reconstruct the key. This is where the magic happens:
http://en.wikipedia.org/wiki/Shamir's_Secret_Sharing
3. Encrypt-and-sign each piece with a secret key derived from its owner's password/passphrase using a secure KDF like scrypt.
4. Throw away the keys, and put those encrypted pieces on disk.
Now you need passwords from any two people to decrypt the secret payload. Cool, right?
[+] [-] camus2|12 years ago|reply
[+] [-] pstuart|12 years ago|reply
[+] [-] free652|12 years ago|reply
[+] [-] jorgem|12 years ago|reply
[+] [-] alec|12 years ago|reply
I'm only passingly familiar with defer, but I understand it to be equivalent to RAII in C++, Python's with statement, Common Lisp's unwind-protect, and others - does is actually provide something more, and if so, what?
[+] [-] pcwalton|12 years ago|reply
[+] [-] tptacek|12 years ago|reply
"Defer" is nice to have, and because it does less than scoped acquisition, it's easier to repurpose for other jobs; that's kind of thematic of Golang --- simple, orthogonal advances over C/Java/C++; a distinct lack of "theoretical" ambition.
[+] [-] raybejjani|12 years ago|reply
[+] [-] craigyk|12 years ago|reply
Does this mean Go is ready to use to make a 'simple' forwarding/caching DNS server with the ability to have DHCP update local hostnames? How about DNSSEC validation?
[+] [-] tptacek|12 years ago|reply
[+] [-] amalag|12 years ago|reply
[+] [-] sard420|12 years ago|reply