• Stars
    star
    125
  • Rank 286,335 (Top 6 %)
  • Language
    C
  • License
    MIT License
  • Created about 13 years ago
  • Updated about 3 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Ruby extension that wraps the official high level ZeroMQ C API ( http://czmq.zeromq.org/ )

rbczmq - binding for the high level ZeroMQ C API <img src=“https://secure.travis-ci.org/methodmissing/rbczmq.png” alt=“Build Status” />

© 2011-2014 Lourens Naudé (methodmissing), James Tucker (raggi), Matt Connolly (mattconnolly) with API guidance from the czmq (czmq.zeromq.org/) project.

http://github.com/methodmissing/rbczmq

About ZeroMQ

In a nutshell, ZeroMQ is a hybrid networking library / concurrency framework. I quote the ØMQ Guide (zguide.zeromq.org/page:all) :

“ØMQ (ZeroMQ, 0MQ, zmq) looks like an embeddable networking library but acts like a concurrency framework. It gives you sockets that carry whole messages across various transports like in-process, inter-process, TCP, and multicast. You can connect sockets N-to-N with patterns like fanout, pub-sub, task distribution, and request-reply. It’s fast enough to be the fabric for clustered products. Its asynchronous I/O model gives you scalable multicore applications, built as asynchronous message-processing tasks. It has a score of language APIs and runs on most operating systems. ØMQ is from iMatix and is LGPL open source.”

Another ZeroMQ extension ?

This extension bundles both ZeroMQ (libzmq, www.zeromq.org/) and CZMQ (libczmq, czmq.zeromq.org/) and as such have no third party dependencies other than a Ruby distribution and a C compiler. My goals for this project were :

  • Access to a powerful messaging technology without having to install a bunch of dependencies

  • A stable and mostly version agnostic (2.x and 3.x series) API

  • Leverage and build upon a mature and maintained client (CZMQ)

  • Target Ruby distributions with a stable and comprehensive C API (MRI, Rubinius, JRuby is work in progress)

  • Support for running sockets in Threads - both green and native threads should be supported and preempt properly with edge-triggered multiplexing from libzmq.

  • Integrate with the Garbage Collector in a predictable way. CZMQ and the ZeroMQ framework is very fast and can allocate an enormous amount of objects in no time when using the Frame, Message and String wrappers. Resources such as socket connections should be cleaned up when objects are finalized as well.

  • Expose Message envelopes and Frames to developers as well to allow for higher level protocols and constructs.

  • Enforce well known best practices such as restricting socket interactions to within the thread the socket was created in etc.

Performance

ZeroMQ can have higher throughput than TCP in most cases by using a message batching technique. Please have a look through the Performance section in the ZeroMQ FAQ (www.zeromq.org/area:faq#toc2) for further implementation details.

Some notes about these benchmarks :

  • Messages go through the full network stack on localhost (TCP/IP transport)

  • The sender and receiver endpoints are Ruby processes which coerce transferred data to native String objects on both ends.

  • There’s thus a definite method dispatch cost in addition to intermittent pauses from the Garbage Collector

  • It’s still plenty fast for most soft real-time applications and we’re able to push in excess of 1 gigabits/s with the 1024 byte payloads. A language with automatic memory management cannot easily comply to hard real-time guarantees anyways.

TCP/IP loopback, 100k messages, 100 byte payloads

Lourenss-MacBook-Air:rbczmq lourens$ MSG_COUNT=100000 MSG_SIZE=100 ruby perf/pair.rb
Local pids: 2042
Remote pid: 2043
Sent 100000 messages in 0.3933s ...
[2043] Memory used before: 1128kb
[2043] Memory used after: 3012kb
[2042] Memory used before: 1120kb
====== [2042] transfer stats ======
message encoding: string
message size: 100 [B]
message count: 100000
mean throughput: 227978 [msg/s]
mean throughput: 182.383 [Mb/s]
[2042] Memory used after: 22432kb

TCP/IP loopback, 100k messages, 1024 byte payloads

Lourenss-MacBook-Air:rbczmq lourens$ MSG_COUNT=100000 MSG_SIZE=1024 ruby perf/pair.rb
Local pids: 2027
Remote pid: 2028
Sent 100000 messages in 0.641198s ...
[2028] Memory used before: 1120kb
[2028] Memory used after: 12776kb
[2027] Memory used before: 1144kb
====== [2027] transfer stats ======
message encoding: string
message size: 1024 [B]
message count: 100000
mean throughput: 160756 [msg/s]
mean throughput: 1316.919 [Mb/s]
[2027] Memory used after: 189004kb

TCP/IP loopback, 100k messages, 2048 byte payloads

Lourenss-MacBook-Air:rbczmq lourens$ MSG_COUNT=100000 MSG_SIZE=2048 ruby perf/pair.rb
Local pids: 2034
Remote pid: 2035
Sent 100000 messages in 0.94703s ...
[2035] Memory used before: 1140kb
[2035] Memory used after: 7212kb
[2034] Memory used before: 1128kb
====== [2034] transfer stats ======
message encoding: string
message size: 2048 [B]
message count: 100000
mean throughput: 123506 [msg/s]
mean throughput: 2023.528 [Mb/s]
[2034] Memory used after: 277712kb

Have a play around with the performance runner and other socket pairs as well - github.com/methodmissing/rbczmq/tree/master/perf

Usage

As a first step I’d highly recommend you read (and reread) through the zguide (zguide.zeromq.org/page:all) as understanding the supported messaging patterns and topologies is fundamental to getting the most from this binding. Here’s a few basic examples. Please refer to documentation (methodmissing.github.com/rbczmq/) and test cases (github.com/methodmissing/rbczmq/tree/master/test) for detailed usage information.

Basic send / receive, in process transport

ctx = ZMQ::Context.new
rep = ctx.socket(:PAIR)
port = rep.bind("inproc://send.receive")
req = ctx.socket(:PAIR)
req.connect("inproc://send.receive")
req.send("ping") # true
rep.recv # "ping"

ctx.destroy

Fair-queued work distribution to a set of worker threads

ctx = ZMQ::Context.new
push = ctx.bind(:PUSH, "inproc://push-pull-distribution.test")
threads = []
5.times do
  threads << Thread.new do
    pull = ctx.connect(:PULL, "inproc://push-pull-distribution.test")
    msg = pull.recv
    pull.close
    msg
  end
end

sleep 0.5 # avoid "slow joiner" syndrome
messages = %w(a b c d e f)
messages.each do |m|
  push.send m
end

threads.each{|t| t.join }
threads.all?{|t| messages.include?(t.value) } # true

ctx.destroy

Async request / reply routing

ctx = ZMQ::Context.new
router = ctx.bind(:ROUTER, "inproc://routing-flow.test")
dealer = ctx.socket(:DEALER)
dealer.identity = "xyz"
dealer.connect("inproc://routing-flow.test")

router.sendm("xyz")
router.send("request")
dealer.recv # "request"

dealer.send("reply")
router.recv # "xyz"
router.recv # "reply"

ctx.destroy

Send / receive frames

ctx = ZMQ::Context.new
rep = ctx.socket(:PAIR)
rep.bind("inproc://frames.test")
req = ctx.socket(:PAIR)
req.connect("inproc://frames.test")
ping = ZMQ::Frame("ping")
req.send_frame(ping) # true
rep.recv_frame # ZMQ::Frame("ping")
rep.send_frame(ZMQ::Frame("pong")) # true
req.recv_frame # ZMQ::Frame("pong")
rep.send_frame(ZMQ::Frame("pong")) # true
req.recv_frame_nonblock # nil
sleep 0.3
req.recv_frame_nonblock # ZMQ::Frame("pong")

ctx.destroy

Send / receive messages

ctx = ZMQ::Context.new
rep = ctx.socket(:PAIR)
rep.bind("inproc://messages.test")
req = ctx.socket(:PAIR)
req.connect("inproc://messages.test")

msg = ZMQ::Message.new
msg.push ZMQ::Frame("header")
msg.push ZMQ::Frame("body")

req.send_message(msg) # nil

recvd_msg = rep.recv_message
recvd_msg.class # ZMQ::Message
recvd_msg.pop # ZMQ::Frame("header")
recvd_msg.pop # ZMQ::Frame("body")

ctx.destroy

Resources

Requirements

  • A POSIX compliant OS, known to work well on Linux, BSD variants, Mac OS X and SmartOS.

  • Ruby MRI 1.9, 2.0 or Rubinius (JRuby capi support forthcoming)

  • A C compiler

  • This is a “fat” gem, including its own source code for both ZeroMQ and CZMQ libraries. No system installation of either library is required.

Installation

Rubygems installation

gem install rbczmq

Building from source

git clone https://github.com/methodmissing/rbczmq.git
cd rbczmq
git submodule init
git submodule update
rake

Running all tests

rake test

Running a single test file:

ruby -Ilib test/test_context.rb

OS X notes:

If you are installing the package on a new Mac ensure you have libtool and autoconf installed. You can get those with brew packaging system:

brew install libtool autoconf automake

LICENSE

The rbczmq gem is licensed under the MIT license. See the file “MIT-LICENSE” for details. This gem uses the “zmq” and “czmq” libraries, both of which are licensed under the LGPL license.

TODO

  • ZMQ::Message#save && ZMQ::Message.load

  • Optimize zloop handler callbacks (perftools)

  • Handle GC issue with timers in loop callbacks

  • czmq send methods aren’t non-blocking by default

  • Revisit the ZMQ::Loop API

  • RDOC fail on mixed C and Ruby source files that document that same constants

  • GC guards to prevent recycling objects being sent / received.

  • Watch out for further cases where REQ / REP pairs could raise EFSM

  • Do not clobber local scope from macros (James’s commit in master)

  • Incorporate examples into CI as well

  • Zero-copy semantics for frames

  • Enable use of a system installed ZeroMQ/CZMQ libraries.

Contact, feedback and bugs

This project is still work in progress and I’m looking for guidance on API design, use cases and any outlier experiences. Please log bugs and suggestions at github.com/methodmissing/rbczmq/issues

More Repositories

1

scrooge

Fetch exactly what you need
Ruby
322
star
2

mysqlplus_adapter

Ruby
59
star
3

mri_instrumentation

dtrace pid provider hooks for mri
Ruby
43
star
4

hwia

Native MRI HashWithIndifferentAccess implementation
Ruby
37
star
5

eio

A libeio (http://software.schmorp.de/pkg/libeio.html) wrapper for Ruby
Shell
29
star
6

aftermath

An example CQRS implementation in the Ruby language
Ruby
27
star
7

aio

POSIX realtime bindings for Ruby
C
25
star
8

cb

Native MRI callback
Ruby
19
star
9

jio

jio - transactional, journaled file I/O for Ruby
C
18
star
10

io-trace

IO tracing framework for Ruby MRI
C
15
star
11

type_array

A Ruby TypeArray implementation based off the strawman ECMAScript spec ( http://wiki.ecmascript.org/doku.php?id=strawman:typed_arrays )
C
14
star
12

promise

Lightweight Ruby MRI promise extension
Ruby
14
star
13

vio

Ruby Vectored I/O
C
11
star
14

routing_with_optional_formats

Selectively enable or disable formatted named routes being generated
Ruby
11
star
15

memcached_store

ActiveSupport Cache Store for http://github.com/fauna/memcached/tree/master
Ruby
10
star
16

callsite

Native MRI Kernel#callsite implementation ( JRuby pending )
C
10
star
17

channel

Native MRI channel like object to complement github.com/methodmissing/callback/tree
C
9
star
18

rehash

Simple by key / value rehashing for Ruby MRI
C
9
star
19

erubis_template_handler

Rails 2.3 / Edge template handler for erubis ( http://www.kuwata-lab.com/erubis/ )
Ruby
7
star
20

railswaycon_imr_shorttalk

Inside Matz Ruby lightning type talk
Ruby
6
star
21

rb_io_perf

Posix AIO, mmap &amp;&amp; BSD scatter && gather experiments
C
6
star
22

relp

Ruby wrapper for the RELP (Reliable Event Logging Protocol) protocol
C
6
star
23

railswaycon_events

Embracing Events
Ruby
4
star
24

rb_darkstar_server

JRuby wrapper for the Project Darkstar Server component
Ruby
4
star
25

euruko2011

Euruko 2011 - In the Loop
D
4
star
26

stable_session_id

Stable Session Identifier support for Cookie Session Store
Ruby
3
star
27

cord

WIP implementation of a Concat Tree / Rope / Cord for Ruby MRI.
C
3
star
28

model_struct

Dump an ActiveRecord instance and related associations to Struct instances that can easily be pushed down the wire, sans dependencies, in conjunction with an EventMachine Marshal protocol.
3
star
29

cast

Fork of cast.rubyforge.org - current pending tracker items
Ruby
2
star
30

gap_buffer

WIP implementation of a Gap Buffer for Ruby MRI.
C++
1
star
31

methodmissing.github.com

1
star
32

blog

Code snippets referenced from my blog @ http://www.methodmissing.com
1
star
33

string_internals

A look into MRI Ruby's COW and buffer semantics for Strings
Ruby
1
star
34

librelp

Fork of librelp ( http://www.librelp.com/ ) with some cross platform fixes
Shell
1
star