OKWS, the Ok Web Server (behind OK Cupid)
okws.org
okws.org
One of the coolest parts of the stack was that every function call you made was non-blocking unless you wrapped it with BLOCK{...}, and within a BLOCK code that was written sequentially got turned into callback-based async calls behind the scenes.
The other cool part of the stack was getting core dumps on segfaults. Heh.
But what I don't see is how this applies to OkCupid and web servers. To me, their website looks 99% static, with a web form that sends messages. The "secret sauce" is all offline background processes that builds recommendations, sends email, etc.; certainly nothing to do with HTTP. And once your website is nearly static, you stick a cache like Varnish in front of it, and you can serve pages as fast as your system bus can stream from memory to the network card. All without writing your own web server, and without using C++.
That said, it is the nicest C++ app I have ever used.
have you used okcupid?
Or their technology is poorly documented and basically an oral tradition. God help them if their lead developers get hit by a bus.
I think that they're implementing a lot of stuff in client side javascript because of that. A few days ago a redditor discovered that there're a lot of parameters of each profile right there on the page source, like the number of messages received today, last week and some attractiveness scale.
(My company sells high performance C++ post-modern databases and we've been able to pivot really quickly)
An application server for C++. Well, this makes it kinda interesting. Although lines like
okclnt_t *make_newclnt (ptr<ahttpcon> x);
okclnt_simple_t (ptr<ahttpcon> x, oksrvc_simple_t *o) : okclnt2_t (x, o), ok_simple (o) {}
do not look especially appealing. okclnt_t *make_newclnt (ptr<ahttpcon> x);
This declares a function that makes a new client from an http connection. It returns a raw pointer, so I presume the caller is responsible for the client lifetime. Whereas the connection argument is some ptr template, which I expect is a ref-counted or otherwise managed pointer, which suggests the client will keep the connection object alive. This is copying the ptr value, which if this is a ref-counting ptr would do an unnecessary extra ref-count during the function call, so they might want to pass it as a const-ref instead. okclnt_simple_t (ptr<ahttpcon> x, oksrvc_simple_t *o) : okclnt2_t (x, o), ok_simple (o) {}
This is a constructor to make a simple client from an http connection and a simple service. The only thing unusual is that a _t suffix usually suggests a typedef, and I don't think you can use a type alias to define a constructor.I haven't looked at the API or done any web programming; I thought it was interesting what I could tell from this snippet regardless.
(1) I've recently made a few updates to the wiki, adding a pointer to the new subversion repository: svn://svn3.okws.org/okws2/devel/3.1. I'm still actively checking in fixes and smallish new features, but there won't be any big changes over the next few months.
(2) OKWS and all services written for OKWS are single-threaded, non-blocking asynchronous processes. All database calls still go through RPC-to-SQL translators, as mentioned in the paper. File system I/O goes through libasync's aiod system: a small blocking helper process does the file I/O, and the main process communicates with the helper over asynchronous RPC.
(3) The documentation is horrible, I realize. I never quite find the time to do a good job of updating the wiki, or fully documenting what's there. If anyone wants to help me on that, please contact me! Variable names often truncate vowels, true. I'm stuck on 80-column mode and hate line wraps. If you write OKWS subclasses (as you do when you make new OKWS services), you can add vowels to taste.
(4) We actually think that given the size of our team (~10 engineers), we get features out pretty quickly. When things take a while, it's not that we use C++, it's that either the feature is a challenging technical problem that's deeper than language choice, or there's a ton of front-end work required (i.e., compatibility with two mobile apps and two HTML versions of the site).
As for why we wrote OKWS, and was that a good idea, one important thing to realize is that the landscape was quite different back in 2003 when we started OkCupid. Since then, threading on Linux has improved, and multicore is where the performance gains are. Also, we've seen RoR and Django get big.
So a good question is: if we were starting OkCupid again now, and if OKWS existed as is, would we chose it over RoR, Django, PHP, etc? Maybe. OKWS has some really nice features now that make is worth considering, such as: (a) the tame source-to-source C++ translation system mentioned by aston below. It's a great way to manage server-side concurrency, and I prefer it over threads. It's most similar to twisted in Python, but I prefer tame's syntax (perhaps I am biased). (b) The "pub" templating system. There are of course many HTML templating systems out there today, but the "pub" system built into OKWS gives a natural split between front-end and back-end programming tasks; (c) Performance --- we're still serving tens of thousands of pages a second from a few dinky web servers. These pages are 99% dynamic! We draw every page from scratch, more or less. If we wrote OkCupid in Python, we'd need about 10x the number of machines, and our serving bills would increase. (d) Caching -- the OKWS architecture allows simple single-process caches, which are really fast compared to going to memcache or shared memory systems. (e) Security and robustness --- we're still able to separate code so that one service can crash, while everything else runs without a problem.
If you're considering using OKWS, I offer these suggestions: (i) build a good build system, because it's true, C++ is a slow dog when it comes to big recompiles; (ii) never hand-manage memory (i.e., don't use new/delete), but rather, always use reference-counted auto pointers and safe C++ string/buffer classes; (iii) make sure you can find good C++ developers, they are hard to find!
http://www.okws.org/doku.php?id=okws:releaseplan isn't very reassuring
Neither is `svn co svn://svn2.okws.org/ok/okws2/devel/3.0 okws-3.0; cd okws-3.0; svn log | less`...
That's why.