[nanomsg] Re: Planning nanomsg on multithreaded and distributed applications

  • From: "Garrett D'Amore" <garrett@xxxxxxxxxx>
  • To: "nanomsg@xxxxxxxxxxxxx" <nanomsg@xxxxxxxxxxxxx>
  • Date: Thu, 5 Jan 2017 02:39:40 -0800

nanomsg works quite well for many use cases, and lots of people are using
it.  (I think mangos works even better, but it is only applicable for folks
using Go.  It is wire compatible with nanomsg, so you can mix and match the
two easily.  Mangos does have some extra capabilities though — especially
for websocket and TLS based security.)

There are things zmq does better.  For example, zmq has builtin crypto.
It’s inproc mode *might* be more robust.  It *may* be faster than nanomsg
in circumstances where event notification is not required.  (The hack to
use notification file descriptors with pipes is horrible for performance.
I think ZMQ uses it as well as nanomsg.)  ZMQ is older, and has probably
had more work done on the code to make it production-grade — nanomsg has
had fewer people working on it, and its frankly a pain to work inside the
code base.  (This is one of the main reasons I’m redesigning the guts
around the same architecture I used for mangos.)

In my opinion, the POSIX API is more trouble than its worth, and gravely
limiting.  There are a bunch of exceptions to it even in nanomsg (e.g.
NN_MSG allocations), and there are things that you’d like to do that are
well nigh impossible under the nanomsg API, but which can be done with a
more flexible API.  I’m doing that for libnng.  (I’ll have a nanomsg
compatible API shim.)  A rich API doesn’t have to be any harder to use, but
having additional capabilities is really worthwhile.  The POSIX cmsg API is
an abomination caused by the POSIX committee trying to figure out how abuse
the legacy sockets API to pass just a bit more information across a
user/kernel boundary without upsetting dozens of UNIX vendors.  It isn’t
pleasant for anyone to use, ever.

One of the worst things, from a performance perspective, is the use of
separate pipes to support async notification (and integration with
poll/select/epoll/kqueue).  While this makes integrating nanomsg into
runtimes designed around a single event loop that monitors for events on
descriptors really easy, this comes at a serious performance cost.  In
libnng I’ll have the same ability, but it won’t be enabled unless you ask
for it.  We certainly won’t be using this to drive our own internal
processing.  (And if you can get by with a callback instead of a pollable
file descriptor, you will get a nicer performance boost.)

The things that nanomsg shines at are:

a) Simple RFCs (wire protocol implementations are easy to write, unlike
ZeroMQ)
b) Thread-safe from the get go, just like UNIX file descriptors.  (Sadly,
with the same intrinsic race challenges with close though..)
c) C code, so no C++ nonsense.
d) Liberal licensing

I’m not that passionate about this, even though I’ve written one of the
only wire protocol implementations of the SP protocols (mangos) and am the
current nanomsg maintainer/BDFL.  For me, ZeroMQ’s heavy weight approach to
everything, and its reliance on C++, made it unpleasant for me to work
with, which is what drew me to nanomsg originally.  I like the protocols,
and I am super proud of Mangos which I think is a very robust messaging
framework that I’ve used in a variety of commercial settings (and I know
others have too).  But my feelings won’t be hurt if you choose ZeroMQ.  I
do hope in a couple of weeks, if you have time, you’ll come back and have a
look at libnng.  I think by then it will really be worth looking at.  (nng
stands for nanomsg next-gen.)

Best of luck to you!


On Thu, Jan 5, 2017 at 1:36 AM, Roberto Fichera <kernel@xxxxxxxxxxxxx>
wrote:

On 01/05/2017 09:55 AM, Carlos Tangerino wrote:

Have your tried to do this

*Yes, nn_device needs its own thread.  It blocks forever, until one of the
two sockets is closed or nn_term is called*

It seems it does not work, calling nn_term will block the caller as well,
closing the sockets from the external world, it crashes, a hell

I’m seriously thinking to go back to ZMQ


Maybe would be better to implement a "more controlled" msg
dispatcher/router between
sockets instead to use nn_device(). This was my first idea for publish msg
from internal
to external transports.

However, I'm debated since few weeks between ZMQ and nanomsg. I'm almost
attracted
by nanomsg because it is "POSIX-compliant", uses a much better threading
model and
implement a kind of "zero-copy" msg approach, scalability on sub/pub
patterns as well which
is almost the model I need.

Would be also nice to have some comments regarding how it works in real
use cases and
what are the most common drawbacks on using it.



Carlos

On Jan 4, 2017, 19:49 +0100, Garrett D'Amore <garrett@xxxxxxxxxx>
<garrett@xxxxxxxxxx>, wrote:

Yes, nn_device needs its own thread.  It blocks forever, until one of the
two sockets is closed or nn_term is called.

libnng is C.

I don’t think I’m ready to accept new contributions on libnng yet, as I’m
still in the midst of writing it.  libnng is basically a rewrite of nanomsg
using the lessons learned in mangos, so its a completely different approach
internally (e.g. uses threads internally, and completely does away with the
state machine craziness in libnanomsg) — it’s also going to support further
development efforts including new patterns and new transports *far* more
easily than is possible with legacy libnanomsg.  Finally, it will probably
also be quite a bit faster as I’m reducing quite a few system calls.  At
any rate, its likely going to be a couple of weeks before I’m ready to
start inviting co-contributors, though you are welcome to start looking at
the code — the API details, while subject to change, are available in the
nng.h header file . The repo is at github.com/nanomsg/nng

On Wed, Jan 4, 2017 at 10:10 AM, Roberto Fichera <kernel@xxxxxxxxxxxxx>
wrote:

On 01/04/2017 06:53 PM, Garrett D'Amore wrote:

You can make a device to route automatically between transports like this
… see nn_device().


Ah! Good! I guess it has to run within a separated thread, right?

Note however that if you are updating extremely frequently, you might
find that you lose messages as the PUB/SUB pattern drops messages when
queues get full.  As TCP generally is slower than inproc, its easy to
overwhelm it.  nanomsg has some concerns at present around inproc as well,
and I’d be somewhat cautious of using it in production (test it yourself).
  (TCP and IPC are fine though.)


This is already taken in account. Distributed application knows they
might be lossy, so no problem.

However, if you are able to, you can use mangos (which is a rewrite of
nanomsg in Go), as it does not suffer any of the same concerns.


Constraint is C or C++ interface.

Very soon I think you’ll also have libnng as an option, which I think
won’t have any of the same considerations either.  However, libnng is
probably a couple of weeks away from being ready for use in production apps.


Ok! Timespan could be ok. I could start with libnanomsg and move
afterwards to libnng


Current PUB/SUB in nanomsg is handled by subscriber filtering, so the
publisher knows nothing about it.  I have a plan to create a new version of
this pattern that actually does publisher side filtering, but that will
also be several weeks away I think.  (And its likely that this new pattern
will only be available in libnng and mangos.)


I could also help you on implementing this, I would need to know better
the inside of the library ;-)


  - Garrett

On Wed, Jan 4, 2017 at 9:42 AM, Roberto Fichera <kernel@xxxxxxxxxxxxx>
wrote:

Hi There.

I'm evaluating to introduce nanomsg as common communication library for
my
multithreaded and distributed applications. I would like to know what is
the best
approach to use for my specific use case.

My application updates thousands of separated data from many different
threads.
For every data I would like to notify the changes to external
subscribers.

So my idea is to have a PUB nn_socket using a TCP transport for the
whole app.
Within the app, I could have a SUB nn_socket using a inproc transport
collecting all
subscribers one for each single data (topic) to PUB. Every inproc PUB
data might
wait a new data in a thread and publish the data as soon as it's
available.
Finally the SUB nn_socket collecting all the data published could route
the data up
to the PUB nn_socket for delivering outside the data. What is the best
way to
"route" messages between TCP PUB (external) and INPROC SUB (internal)?

If this is ok I would like to allocate inproc publishing threads only
for topics (data) that external
subscribers have subscribed, so having real demand, in order to optimize
the performances.
Then this trigger another question: is there anyway to know the topic
subscribed by a subscriber?

Any suggestion?

Thanks in advance,
Roberto Fichera.







Other related posts: