0

In order to learn the library, I've been translating the examples from the ZeroMQ guide to NetMQ. I've gone through a third of the book, and the main sticking point that I have with the library is the way it deviates from ZeroMQ in how it does polling.

At first glance, NetMQ seems better as you can just add callbacks to the sockets and call the poller.Run, but the reality is that the NetMQ approach is significantly less expressive ZeroMQ one and I outright cannot translate the load balancing pattern to NetMQ directly.

Yes, there are alternatives: here it alternates between polling the frontend and the backend 0.5s each. Here is a straightforward implementation which does what the book does without the intermediate queue.

In addition to the above, I tried several schemes such as using two queues (the additional one for the requests), or adding and removing frontend sockets, and all of them have issues. Having two queues fails in the simple pirate example as it leads to stale requests being in the queues and I can't just remove them if the other side times out. Adding and removing sockets fails because callbacks for a socket can be called even after it is removed from the poller leading to dequeue from empty queue exceptions.

To my mind none of this is good enough, and as a matter of principle I should be doing it how the book does it. The approach closest to the one in the book which does not use any queues would be useless if I wanted to use a load balancing approach which is not LRU or needed to poll from multiple backends in the router.

I see all this poller hassle as a red mark against the NetMQ library. Are there any better approaches to the load balancing pattern that I am not aware of?

Marko Grdinić
  • 3,798
  • 3
  • 18
  • 21
  • 1
    NetMQPoller can give you same capabilities of zmq_poll, zmq_poll is low level and zeromq binding usually wrap it with an API similar to NetMQPoller. Also, zeromq API now has zmq_poller, which is very similar to NetMQPoller. If you can give an example of what you try to achieve with NetMQPoller I will be able to help. – somdoron Jun 02 '20 at 11:15
  • 1
    Anyway, if you want the zmq_poll low level NetMQ equivalent, check NetMQSelector. – somdoron Jun 02 '20 at 11:16
  • That sounds interesting. Are there any example of it in use? I can't find any in `NetMQ.Tests`, though I see it being used internally in the `NetMQ` project. Basically, the great advantage of the ZeroMQ polling style is that it implements the MVU pattern. The items to be polled are strictly a function of the state, which makes it really easy, for example, to do things like poll the frontend only if there are workers in the queue. This is very difficult with the high level poller right now. – Marko Grdinić Jun 02 '20 at 12:53
  • Ok, I think I [get it](https://github.com/mrakgr/Lithe-POC/blob/e81a57db24db1dbb2c13cf35149e55ec5ad6abb8/Lithe%20Avalonia%20Examples/05_NetMQ.fs#L129). I'll try reimplementing the load balancing example using this. – Marko Grdinić Jun 02 '20 at 13:27
  • As a way of feedback, the first bit of awkwardness is that select returns a boolean whether an event has triggered for one of the items. Right now I am looking at the source, and it would really have been a lot better if it simply returned the index of the item that hit. In order to do anything useful with that information I'd have to do a search over the items which would not be necessary if it returned an index. – Marko Grdinić Jun 02 '20 at 13:40
  • Sorry, it is not documented. Although a pull request for the docs is welcome. It is a port of zmq_poll, so API is same. – somdoron Jun 02 '20 at 14:24
  • zmq_poll has same API, you have to check the array for the results. It is to allow multiple results on same call. – somdoron Jun 02 '20 at 14:26
  • It is okay. I finally got the load balancing to work correctly. First I defined [some helpers](https://github.com/mrakgr/Lithe-POC/blob/5a83e46362c8f669ec54ebb794ee68bfce76aa90/Lithe%20Avalonia%20Examples/05_NetMQ.fs#L29). Then I implemented the scheme from the guide exactly as it was [here](https://github.com/mrakgr/Lithe-POC/blob/5a83e46362c8f669ec54ebb794ee68bfce76aa90/Lithe%20Avalonia%20Examples/05_NetMQ.fs#L655). This is similar how the F# examples from the guide do it. Too bad you can't use the NetMQ timers with this. – Marko Grdinić Jun 02 '20 at 15:09
  • Because of the way it is written, the efficiency of this code highly depends on how much optimization the JIT does. But even if it is suboptimal, it is both stylistically and semantically a better way of implementing load balancing than any of the alternatives. – Marko Grdinić Jun 02 '20 at 15:09
  • As it turns out, the ZeroMQ style pooling for load balancing is not much better than the two queue solution. I thought that Req to Router sends were async because the receives were being read prematurely into the intermediate buffer, but that was not the case. – Marko Grdinić Jun 03 '20 at 07:47
  • You could provide your C # code for Load Balancing Pattern? I have a common situation. I study NetMQ according to ZeroMQ guide, but the different implementation of the poller in NetMQ makes me have a problem. – Clyde Oct 20 '20 at 06:29
  • Sorry, it would be too time intensive for me to do it. But both F# and C# are .NET languages, so it would be good homework for you to study and do it yourself. In a [later commit](https://github.com/mrakgr/Lithe-POC/blob/f34d9c91c9e5966208c1099fe05779cc9516e80f/Lithe%20Avalonia%20Examples/05_NetMQ.fs) there are examples of such polling in action. Just clone the repo and try running the examples. If you make it your mission to pare a single example to a command line one, you should not have too much of a difficult time. And going from that to a C# version should be easy after that. – Marko Grdinić Oct 21 '20 at 07:58

0 Answers0