LabVIEW Craft
  • Blog
  • About
  • Contact
  • Tools
  • Resources

ØMQ Extension for Stream

3/5/2017

9 Comments

 
Jon McBee
I've been wanting to write a network extension for Stream for about a year now, adding the ability to extend the mediator to the network and allow pub/sub between actors on different machines.  I finally got the motivation to do it after starting to collaborate with Jarobit Peña Saez at Bits 2 Byte on the Stream project.  This extension is a result of our collaboration efforts and the sharing of ideas.
Picture
​​I decided to use ØMQ (pronounced zero-em-queue) as it is a free messaging library for use in distributed applications that handles the TCP socket layer for you.  The base implementation is done in C++ but there are bindings for most popular languages including this binding for LabVIEW, which I used.  A cool aspect of the many bindings available is that ØMQ makes it easy to setup messaging not only between machines on network but between machines running different operating systems and using different programming languages.  As you saw in the demo above it was pretty trivial to connect Stream in LabVIEW to a simple Python script using ØMQ.  ØMQ has great documentation, I recommend that you read more here.
​Let's establish a little vocabulary so we can discuss the design.  The ØMQ Network Extension for Stream is meant to allow Stream actors to communicate across a network without the need to write any TCP/IP level code.  Let's refer to a system of actors on a machine as a microsystem, and the system comprised of many machines as a system.  We can now say that our system is comprised of many microsystems where each microsystem is comprised of many actors.  In the current implementation of the ØMQ Network Extension for Stream there must only be one server per system, and it is up to the developer to make this so.  I don't love the fact that we need a server and think that the design can be improved, but as it stands today there must be one server to rule them all, one server to find them, one server to bring them all and in the darkness bind them (as the saying goes).
​Within each microsystem there can be one or more mediators, this is really a design decision left to the architect.  I typically only have one mediator per microsystem but I know others like to spin up one global mediator per microsystem and one private mediator for each actor in the microsystem.  One thing to keep in mind with this implementation is that every mediator creates its own ØMQ context, and then using the context to create sockets.  The context is the container for all sockets in a single process and the ØMQ guide recommends "Do one create context at the start of your main line code, and one destroy context at the end."
​So how does the ØMQ Network Extension for Stream work?  At a high level the extension is a message broker that uses the ØMQ Publish/Subscribe pattern as the transport, and serialized JSON data packets as the data message.  The system level server maintains a list clients and spins up LabVIEW Topic Actor for each unique topic in the system.  The Topic Actors are assigned an available port and the server handles distributing the updated ports to all known clients as they come in.  The Topic Actors then each subscribe to the appropriate ØMQ endpoint and register as publishers on the appropriate local Stream topics.  For this to work each message object must override the Pack.vi and Unpack.vi methods, these methods handle serialization and deserialization of the message objects.
One nice thing about using ØMQ is that it handles a lot of the hard stuff for you.  ØMQ doesn't care if the server or the clients spin up first, it handles reconnecting after network dropouts, and makes it easy to bring the clients or the server down and back up again without the entire system going down.  I did add a client heartbeat message to the server so that when clients go down the server recognizes it and broadcasts the change to the other clients.  Likewise, if I bring the server down it will alert the clients, allowing each microsystem to run isolated until a new server spins up, at which point the mediator stitches the topics back together.
As it stands right now the ØMQ Network Extension for Stream works as designed, but there are a handful of design decisions that I would like to change.  If you would like to contribute or collaborate on this project please let us know!  The code for this project has been open sourced under an MIT license and can be found at this Composed Systems Bitbucket page.

Jon McBee is the Founder and Managing Partner at Composed Systems and is a Certified LabVIEW Architect, Certified LabVIEW Embedded Developer, Certified TestStand Developer, an NI Certified Professional Instructor, a LabVIEW Champion, and a Certified ScrumMaster
9 Comments
Dan
3/7/2017 09:35:55 am

This looks similar to accessing NI network published shared variables via OPC. What are the pros and cons of each method?

Reply
Jon McBee
3/7/2017 10:07:08 am

Hi Dan,

That is a good question, I'll be honest and say that I have never used NI's shared variables and OPC solution before. Here are a few links for anyone interested in learning more:

http://www.ni.com/tutorial/3742/en/

http://www.ni.com/white-paper/7451/en/

Reading through the white-paper linked above I see that one technical difference is that OPC enables inter-process communication in a variety of programming languages for the Windows operating system, where as ØMQ has bindings for different languages on different OS's.

Aside from that (short list mainly attributed to my ignorance on NI's solution), I don't have any benchmarking data to compare the two. I am looking for collaborators interested in helping to make the Stream ØMQ extension better through coding, testing, documenting, benchmarking...

On a personal level, the Stream implementation works nicely for me because I am already using Stream. This isn't a good argument for anyone else in the world :) but it works for me. The ability to easily enable/disable distributed microsystems of actors capable of communicating with other languages is important for the applications that I write, but my use case is most likely not typical.

Thanks for reading!

Reply
Pat Dunbeck
3/8/2017 08:25:13 pm

Where is the Bitbucket repo?

Reply
Jon McBee
3/16/2017 08:05:52 am

Had an issue with the repository when I went to push the code and I haven't looped back around to fix it yet (guessing SSH related from the error message). I will put it on my list of things to look at tomorrow.

Reply
Cyril
3/28/2017 11:14:30 am

Is it based on 0MQ LV driver listed on 0MQ web page ?
Does it support several 0MQ patterns ?

Reply
Jon McBee
3/28/2017 01:07:28 pm

Hi Cyril,

It is based on the ØMQ LabVIEW binding, I linked it up at the top of this article. Right now my use of the ØMQ LabVIEW binding only supports Pub/Sub but it's all open source so you or someone else could extend it further. I don't presently have plans to improve it, mainly because I have another backburner project that I need to get to for NI Week.

Regards,
Jon

Reply
Dawid Wozny
7/12/2017 11:27:36 am

Hi Jon,

I have to say that looks really impressive. I will soon remember every word on your blog ;)

I have a quick question, have you tried to run 0MQ on cRIO? I have managed to compile the library and send some data through 0MQ (not stream + 0MQ) but it is still far to use it at some real project. Ideally I would like to use your approach to connect for example multiple cRIO and C# web based application. I wonder what is your experience.

Reply
Jon McBee
7/12/2017 02:37:36 pm

Hi Dawid,

I'm glad you find the blog interesting. I haven't had a chance to try Stream + 0MQ out between a cRIO and a host PC. If you have already compiled the 0MQ library for the cRIO then I think you have done the hard part. I would be willing to help you get this going using Stream, if you are interested send me a message on LinkedIn.

Thanks,
Jon

Reply
Trevor
4/1/2020 02:43:48 pm

Hi Jon,

Love the work you guys do, the MVA framework is a piece of art.

If you do want to try and move the pub/sub to be serverless, you may want to look into DDS. RTI has a toolkit to implement DDS in LabVIEW, and I've been using it successfully in projects.

Reply



Leave a Reply.

    RSS Feed

    Tags

    All
    Abstract Messaging
    Actor Framework
    Agile
    AI
    Asynchronous Programming
    Best Practices
    C#
    Complexity
    Continuations
    Control Values By Index
    Craftsmanship
    Dependency Inversion
    Dependency Viewer
    Futures/Promises
    Genetic Algorithm
    Liskov Substitution
    Malleable VIs
    Mediator Pattern
    .NET
    Object Oriented
    Object-Oriented
    Packed Project Library
    Parallelism
    Polymorphism
    Pub/Sub
    RawCap
    Root Loop
    Scrum
    Task Parallel Library
    TCP/IP
    TDD
    Test Engineering
    UML
    Unit Test
    VI Scripting
    VI Server
    WireShark

    Archives

    April 2019
    July 2018
    October 2017
    March 2017
    February 2017
    January 2017
    December 2016
    July 2016
    June 2016
    May 2016
    April 2016
    March 2016
    February 2016
    January 2016
    December 2015
    November 2015
    October 2015
    August 2015
    February 2015
    January 2015

    LabVIEW Blogs

    Eyes on VIs
    LabVIEW Hacker
    VI Shots
    LabVIEW Artisan
    Software Engineering for LabVIEW
    ​Wiresmith Techology
Picture
Powered by the Panda Ant

  • Blog
  • About
  • Contact
  • Tools
  • Resources