[nanomsg] AW: Re: RPC using nng, difficulties

  • From: Sierwald, Jörn <Joern.Sierwald@xxxxxxxxxxxxx>
  • To: "nanomsg@xxxxxxxxxxxxx" <nanomsg@xxxxxxxxxxxxx>
  • Date: Mon, 19 Feb 2018 09:34:52 +0000

Thank you for the detailed answer.

I have a mixture of trivial and time-consuming RPC calls, and the trivial ones 
must execute quickly while a slow one is running.

I understand your remarks about threads, but the applications here are heavily 
Windows-flavored, meaning there are no dedicated threads but completion ports, 
tasks in the thread pool etc. I’d need to create a cache of sockets and that 
seems to be more work than raw sockets. So, raw sockets it is.

I have browsed through rep.c (nng) and from what I can see the “cooked” mode 
removes the header for incoming data, stores it in the member “btrace” and puts 
it back into the reply. It also implements the lock that serializes the server 
side. I assume here that rep0_sock_send and rep0_sock_recv are the highest 
layer.
Can I make assumptions about the header content at the REP side? Is it always 
just 4 bytes of pipe id? Or are the last 4 bytes the pipe id? I’d expect the 
request ID from the client somewhere (see below).

Then I had a look at req.c. You use a request ID and I’ll need one too. You 
append it to the header when sending and expect it the start of the header when 
receiving. I’ll try that as well.

Jörn

Von: nanomsg-bounce@xxxxxxxxxxxxx [mailto:nanomsg-bounce@xxxxxxxxxxxxx] Im ;
Auftrag von Garrett D'Amore
Gesendet: Freitag, 16. Februar 2018 20:43
An: nanomsg@xxxxxxxxxxxxx
Betreff: [nanomsg] Re: RPC using nng, difficulties

Actually, REQ/REP is the right pattern, but because you need to handle multiple 
outstanding requests at a time, you’ll have to do some more work in your 
application code.

The easiest thing for your REQ application would be to open dedicated sockets 
for each request (or concurrent request).  You can reuse those sockets as you 
like, but only one request can be outstanding on a time if you’re using the 
default cooked mode.  (If you’re using synchronous behavior, but using multiple 
threads, then a socket per thread would do the trick.)

Somewhat more challenging would be to use raw mode (see the NNG_OPT_RAW socket 
option for nng, or the AF_SP_RAW if you’re using legacy nanomsg).  In this case 
you have to examine headers, and match requests to responses.  In order to get 
the synchronous behavior you’ll have to add some kind of controls in your own 
code — probably a condition variable, with suitable timeouts, etc.  This can be 
a fair bit of work, which is why if you can get by with multiple threads and 
dedicated sockets I’d recommend doing so.

On the server side, you need to understand whether your request processing 
truly needs to be asynchronous or not.  Unfortunately I’ve not yet supplied a 
demo for doing this with nng (I will do so soon), but there are demos for 
threaded and asynchronous handling on the server side for libnanomsg.  Again 
this requires raw mode; I’d recommend the threaded model if you can use it — 
this will automatically “limit” the amount of concurrent processing by the 
number of active threads.  Of course, if your requests are light weight (e.g. 
returning a constant value, doing some cheap math, or something that doesn’t 
require long running code) then you can just run a single threaded “recv/send” 
loop on the server.  This is the default, and by far the simplest.

Don’t mess with polyamorous mode — that’s not the behavior you want.

On Fri, Feb 16, 2018 at 2:57 AM Sierwald, Jörn 
<Joern.Sierwald@xxxxxxxxxxxxx<mailto:Joern.Sierwald@xxxxxxxxxxxxx>> wrote:
G’day,

I’m trying to use nanomsg to do some remote procedure calls (replacing CORBA) 
and I found that this is more painful than I expected.
The rep/req protocol cannot be used, as it serializes the calls at the server 
and overwrites outstanding calls at the client end.
A client process must be able to call a remote function several times, 
concurrently. Also, there will be several clients.
At the client the call should look synchronous.

I suspect the pair1 with “Polyamorous Mode” would be the correct basis. But 
then I’d need to add wrappers at both end with some message counters, I guess.

Is this assumption correct?
Has it been done?
Is this even included in the distribution?
Would nng_device help in some way that I do not understand?
Would I have to write an entire protocol?
Should I abandon this and use a library that actually does RPC? (I am familiar 
with native Microsoft-RPC)

BTW, I need other messaging than RPC, too, therefore the attempt to use a 
generic messaging library.

Jörn

Other related posts: