[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

[Nbd] ANN: Haskell NBD server/client library



All,

Some time ago I wanted to experiment with implementing block devices,
preferably in userspace (for prototyping purposes). NBD provides a nice
framework for this, since it can be used on any Linux host (kernel
module), as well as thanks to the native Qemu/KVM support for the
protocol (to back virtual machines).

Since the existing C NBD server isn't really modular/reusable, and I
tend to do most prototyping using Haskell lately, after going through
the docs and deciphering the protocol I created a Haskell library which
eases implementing an NBD server (or client) in Haskell, using the
Conduit library.

You can find it at [1]. More information at [2], and API docs at [3].

The library only supports the 'modern' protocol, but should support all
its features. There's a low-level API in Network.NBD.Server, and a
high-level one in Network.NBD.Server.Simple.

The protocol implementation is not tied to any transport protocol (and
neither is any 'server' implementation), and has been tested using
TCP/IP (using the Linux kernel module as well as Qemu/KVM) as well as
Unix domain sockets (with Qemu/KVM) and in-memory queues in the
testsuite.

At [4] you can find a demo server (using the 'Simple' API) which exports
all files provided on command line (using the filename as export name).
It's very basic, but does support all protocol features
(read/write/flush/trim/FUA). The server is fully multi-threaded, using
GHC's threaded RTS (non-blocking IO, microthreads mapped to N
OS-threads, the lot). As-is, the server listens on a Unix socket called
'nbdsock', but changing line 84 into TCPServerSettings (and providing
host/port/... constructor arguments) turns it into a TCP/IP server in a
snap.

Even though some of you might think using Haskell for this is a very bad
choice performance-wise, some very unscientific 'benchmarking' shows the
demo server is slightly quicker than the default C server. Usage of
pread/pwrite instead of seek+read/write, and the fact less recv calls
are required to read commands from the client socket (larger blocks are
read at once, then buffered), might explain this, as well as the fact
there are no 'COW' or 'multi-file volume' execution paths. In the end it
should at least be on par.
But, as said before, this is very unscientific and without any serious
profiling. Feel free to prove me wrong ;-)

Thought this might be useful one day for some...

Regards,

Nicolas

[1] https://github.com/NicolasT/nbd/
[2] http://nicolast.github.com/nbd/
[3] http://nicolast.github.com/nbd/doc/index.html
[4] https://github.com/NicolasT/nbd/blob/master/bin/server.hs




Reply to: