Hi David,
Thanks for your insightful and quick reply... I'm very optimistic about
Thrift's healthy development community!
The fact that last.fm have chosen Thrift for infrastructure puts it
firmly in the Venn set of 'cool kids'.
Bit of a long one. Fairly in depth technical analysis, and offer of
support, follows...
David Reiss wrote:
First, a quick note about the non-blocking server. It uses nonblocking
I/O, but the actual application callback is called synchronously
(either in the main thread or in a worker thread), so it has to be
synchronous (put another way, the return value for the RPC must be
built before the handler function returns).
Yep, saw *some* of that, but not the critical observation that the
return value must be synchronous. Thanks for pointing that one out right
off.
We'd have to fork TNonblockingServer anyway to integrate it into the
XORP EventLoop. So 'some assembly required'.
That's fine -- XRL has been enough of a sticking point anyway that
radical change is still needed.
We don't use libevent, but rather our own stuff. Some background to why
we do that:
I was funded to port XORP to Microsoft Windows a few years ago, and
this was mostly a success, in that we demonstrated Windows Server 2003
in Redmond handling a full BGP routing table. Sadly this is now
bitrotting due to a lack of further interest and attention from them...
integrating with their IP forwarding requires all sorts of shim DLLs and
service magick.
And imagine my surprise and dismay when I learn that their augmented
POSIX stuff, Subsystem for UNIX Applications (SUA), is about to be axed.
The lack of attention to tools is a Development Limiting Move, to my mind.
EventLoop is a critical path in the XORP framework. It was possible
to leverage the existing design (tied to non-blocking BSD socket I/O)
with a number of stealthy workarounds, without threading the entire code
base, as we rely on the OS's socket buffer behaviour for serialization.
Really, ioctlsocket() with FIONREAD -- and some knowledge about how
Winsock operates in terms of helper thread context switch, which only
became visible under careful observation with Mark Russinovich's Process
Explorer. They don't tell you any of this in the docs -- they expect you
to use Win32 threads.
I daresay I need to go off and look at Boost ASIO now to see if someone
else has done similar.
There is currently no explicit support for doing non-blocking RPC
in Thrift (at least from C++. I'm not sure how the Twisted stuff
works). Someone at Facebook is working on support for this, and
we should be able to release it soonish.
Fingers crossed! Rough guesstimates on timescale would be great.
I do most of my development on FreeBSD-STABLE. If there's anything I
can do to help, please do let me know.
I know for a fact that the FreeBSD port is bitrotted -- it is still
shipping the code with 'facebook::' namespace prior to Apache
Incubation, so that is definitely something I can look at in the meantime.
My understanding is that the Thrift code still uses Boost. If that
is still the case, great. There are things we need to do there anyway --
there are a whole bunch of places where XORP's idioms could be
refactored to use Boost.
XORP has been going as a project for so long (2002), that it's worth
remembering we had to invent a lot of our own stuff, which is probably
better supported now by infrastructure such as Boost and Thrift, which
have more flexible and community-supported idioms. Also, thread
libraries weren't as mature then as they are now.
It is also encouraging that Boost, or parts of it, are making their way
into the ISO C++0x specification. That's what we like -- development
must be sustainable.
In the mean time, one thing
you can do is send your message to a TMemoryBuffer, transport that
to the backend using whatever system you want, then receive the
result from another TMemoryBuffer.
OK. I'll transliterate into XORP-speak here for adaptation (mostly for
my own reference, but, it may interest people...)
looking at
http://cvsweb.xorp.org/cgi-bin/cvsweb.cgi/xorp/ospf/xrl_io.cc?rev=1.54
For example, if you have a function
called "foo":
shared_ptr<TMemoryBuffer> buf(new TMemoryBuffer);
Analogous (without transport hooks) to re-using existing XrlRouter
reference when instantiating Xrl client stub.
e.g. _xrl_router.
(An XrlRouter is an object used to connect to the Finder, XORP XRL's
request broker.)
shared_ptr<MyClient> cl(new MyClient(shared_ptr<TProtocol>(new
TBinaryProtocol(buf)));
Analogous to instantiating Xrl generated client stub e.g.
XrlRawPacket4V0p1Client fea_client(&_xrl_router);
cl->send_foo(args);
Analogous to calling fea_client.send_foo(...), although, WITHOUT the
callback binding.
We use member function pointers a lot.
uint8_t* bytes;
uint32_t nbytes;
buf->getBuffer(&bytes, &nbytes);
// stash buf and cl somewhere.
This is what the XrlRawPacket4V0p1Client._sender instance of XrlSender
is going to be doing.
It binds the callback passed in -- and invokes it when the EventLoop
(Reactor pattern) gets activity on the socket(s) used for XRL transport.
// ship nbytes of bytes off to the server
OK. Understand we need to do our own transport stuff here;
understand that TNonblockingServer comes with limitations for transport
used anyway.
// get the server's response
buf->resetBuffer(response, response_len);
int ret = cl->recv_foo();
This is surprisingly similar to what the XRL client glue does for
marshaling the reply and then dispatching the callback.
I still have some unanswered questions about what we'd do about
replacing the Finder. As I see it, Thrift in its default incarnation
leaves the specifics of transport endpoint up to each application (based
on my reading the simple C++ client/service example in the Thrift SVN
tree), and does not present an ORB as such.
This is analogous to XRL's STCP (*not* SCTP) without service
registration/advertisement. AMQP would most likely deal with some of
that for us -- but in the absence of such integration, we'd need a
lightweight broker mechanism which would work with our chosen
transports. I do wonder if someone has already solved that problem
in/around Thrift.
I noticed that there's a patch for dealing with multiple Thrift servers
here (may be bit-rotted, looks as though it's for the pre-Apache tree):-
http://publists.facebook.com/pipermail/thrift/2007-October/000134.html
We'd probably need something like this. At the moment, the XRL framework
takes multiple XIF definitions and spits out bindings coalesced into one
'target' containing every XIF interface implemented for the software
component in a single C++ class. The methods are abstract virtual so the
class needs to be derived from in order to make sure all the bindings
are implemented for each XRL target (analogy: collection of thrift
services).
Obviously Thrift doesn't do this -- C++ bindings are generated for each
server component -- so -- we would need to be able to tie in multiple
Thrift server-side stubs into the same component. But this is something
we can revisit as we figure out the integration.
One of the questions I can see people will have is: will the Thrift
solution perform slower than the XRL solution? At the moment my gut
feeling is that Thrift is going to be faster at binary marshaling, and
there are problems in XORP's scalability which are better solved using
alternate mechanisms i.e. shared memory arenas and/or batch-mode
messaging for virtualized clusters (AMQP beckons...).
Anyway, more points about where I'm coming from:
I'll keep my ears to the ground meanwhile with AMQP. It shouldn't be
too much hassle to adapt what the txAMQP dude has done for Twisted
Python -- although they have the benefit of fantastic language support
for continuations (yield).
Running Thrift RPC as an AMQP application strikes me as a major step
forward for clustering and virtualization.
We have been looking at stuff like Concurrent C++, but it requires
very ambitious tweaks, essentially it ships its own userland scheduler
-- and that is still subject to stuff like timer aliasing between
userland and kernel. It also isn't sufficiently mature in terms of user
base at the moment.
FreeBSD's KSE M:N threading support would be fantastic here, but
it's currently in a questionable state -- development inertia has set
in, and folk have focused on 1:1 threading as that's what has taken hold.
More as it happens...
thanks muchly,
BMS
P.S. Thanks to Esteve for his reply on current developments in Boost.
ASIO isn't covered in my current Boost book which is most likely in need
of an update. ASIO probably captures some of what's already in libxorp,
open to new ways and improvement.
P.P.S. Thank you for kicking CORBA in the crotch. Much love.