Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 375 lines (262 sloc) 8.688 kB
afe7fd5 @tj rename to axon
authored
1 # Axon
5c2217f @tj Initial commit
authored
2
4777ca2 @tj Update Readme.md
authored
3 Axon is a message-oriented socket library for node.js heavily inspired by zeromq.
5c2217f @tj Initial commit
authored
4
00b5dcc @tj add some docs
authored
5 ## Installation
6
afe7fd5 @tj rename to axon
authored
7 $ npm install axon
00b5dcc @tj add some docs
authored
8
5c2217f @tj Initial commit
authored
9 ## Features
10
11 - message oriented
12 - automated reconnection
13 - light-weight wire protocol
14 - supports arbitrary binary message (msgpack, json, BLOBS, etc)
3613011 @tj docs
authored
15 - supports JSON messages out of the box
05a777b @tj docs
authored
16 - fast (~800 mb/s ~500,000 messages/s)
23b783e document new sockets
Garrett Johnson authored
17
f6ca78d @tj add events to readme
authored
18 ## Events
19
20 - `close` when server or connection is closed
21 - `error` (err) when an-handled socket error occurs
22 - `ignored error` (err) when an axon-handled socket error occurs, but is ignored
23 - `socket error` (err) emitted regardless of handling, for logging purposes
24 - `reconnect attempt` when a reconnection attempt is made
25 - `connect` when connected to the peer, or a peer connection is accepted
26 - `disconnect` when an accepted peer disconnects
27 - `bind` when the server is bound
7829221 @tj add HWM support. Closes #19
authored
28 - `drop` (msg) when a message is dropped due to the HWM
29 - `flush` (msgs) queued when messages are flushed on connection
f6ca78d @tj add events to readme
authored
30
23b783e document new sockets
Garrett Johnson authored
31 ## Patterns
32
33 - push / pull
34 - pub / sub
35 - req / rep
779e21d @tj docs
authored
36 - pub-emitter / sub-emitter
5c2217f @tj Initial commit
authored
37
38 ## Push / Pull
39
0e7ade0 @tj tweak docs
authored
40 `PushSocket`s distribute messages round-robin:
5c2217f @tj Initial commit
authored
41
42 ```js
afe7fd5 @tj rename to axon
authored
43 var axon = require('axon')
44 , sock = axon.socket('push');
5c2217f @tj Initial commit
authored
45
46 sock.bind(3000);
47 console.log('push server started');
48
49 setInterval(function(){
50 sock.send('hello');
51 }, 150);
52 ```
53
0e7ade0 @tj tweak docs
authored
54 Receiver of `PushSocket` messages:
5c2217f @tj Initial commit
authored
55
56 ```js
afe7fd5 @tj rename to axon
authored
57 var axon = require('axon')
58 , sock = axon.socket('pull');
5c2217f @tj Initial commit
authored
59
b3cabbb @tj fix readme example
authored
60 sock.connect(3000);
5c2217f @tj Initial commit
authored
61
b3cabbb @tj fix readme example
authored
62 sock.on('message', function(msg){
63 console.log(msg.toString());
64 });
5c2217f @tj Initial commit
authored
65 ```
66
23b783e document new sockets
Garrett Johnson authored
67 Both `PushSocket`s and `PullSocket`s may `.bind()` or `.connect()`. In the
561889c @tj add more docs
authored
68 following configuration the push socket is bound and pull "workers" connect
69 to it to receive work:
7449cfb @tj add more docs for push/pull
authored
70
71 ![push bind](http://f.cl.ly/items/473u3m1a0k1i0J0I3s04/ss-push.png)
561889c @tj add more docs
authored
72
73 This configuration shows the inverse, where workers connect to a "sink"
74 to push results:
75
7449cfb @tj add more docs for push/pull
authored
76 ![pull bind](http://f.cl.ly/items/3Y0j2v153Q0l1r373i0H/ss-pull.png)
77
5c2217f @tj Initial commit
authored
78 ## Pub / Sub
79
23b783e document new sockets
Garrett Johnson authored
80 `PubSocket`s send messages to all subscribers without queueing. This is an
81 important difference when compared to a `PushSocket`, where the delivery of
82 messages will be queued during disconnects and sent again upon the next connection.
5c2217f @tj Initial commit
authored
83
84 ```js
afe7fd5 @tj rename to axon
authored
85 var axon = require('axon')
86 , sock = axon.socket('pub');
5c2217f @tj Initial commit
authored
87
88 sock.bind(3000);
89 console.log('pub server started');
90
91 setInterval(function(){
92 sock.send('hello');
93 }, 500);
94 ```
95
c5d571e @tj add some docs
authored
96 `SubSocket` simply receives any messages from a `PubSocket`:
5c2217f @tj Initial commit
authored
97
98 ```js
afe7fd5 @tj rename to axon
authored
99 var axon = require('axon')
100 , sock = axon.socket('sub');
5c2217f @tj Initial commit
authored
101
102 sock.connect(3000);
103
104 sock.on('message', function(msg){
105 console.log(msg.toString());
106 });
107 ```
108
c5d571e @tj add some docs
authored
109 `SubSocket`s may optionally `.subscribe()` to one or more "topics" (the first multipart value),
110 using string patterns or regular expressions:
111
112 ```js
113 var axon = require('axon')
114 , sock = axon.socket('sub');
115
116 sock.connect(3000);
853c449 @tj add more docs
authored
117 sock.subscribe('user:login');
118 sock.subscribe('upload:*:progress');
c5d571e @tj add some docs
authored
119
120 sock.on('message', function(topic, msg){
121
122 });
123 ```
124
6792e01 @tj add req/rep docs
authored
125 ## Req / Rep
126
127 `ReqSocket` is similar to a `PushSocket` in that it round-robins messages
128 to connected `RepSocket`s, however it differs in that this communication is
129 bi-directional, every `req.send()` _must_ provide a callback which is invoked
130 when the `RepSocket` replies.
131
132 ```js
133 var axon = require('axon')
134 , sock = axon.socket('req');
135
93ec430 @tj fix req/rep docs. Closes #59
authored
136 sock.bind(3000);
6792e01 @tj add req/rep docs
authored
137
93ec430 @tj fix req/rep docs. Closes #59
authored
138 sock.send(img, function(res){
2464ae5 @tj update benchmarks. Closes #72
authored
139
6792e01 @tj add req/rep docs
authored
140 });
141 ```
142
143 `RepSocket`s receive a `reply` callback that is used to respond to the request,
144 you may have several of these nodes.
145
146 ```js
147 var axon = require('axon')
148 , sock = axon.socket('rep');
149
150 sock.connect(3000);
151
152 sock.on('message', function(img, reply){
153 // resize the image
154 reply(img);
155 });
156 ```
157
158 Like other sockets you may provide multiple arguments or an array of arguments,
159 followed by the callbacks. For example here we provide a task name of "resize"
160 to facilitate multiple tasks over a single socket:
161
162 ```js
163 var axon = require('axon')
164 , sock = axon.socket('req');
165
93ec430 @tj fix req/rep docs. Closes #59
authored
166 sock.bind(3000);
6792e01 @tj add req/rep docs
authored
167
93ec430 @tj fix req/rep docs. Closes #59
authored
168 sock.send('resize', img, function(res){
2464ae5 @tj update benchmarks. Closes #72
authored
169
6792e01 @tj add req/rep docs
authored
170 });
171 ```
172
93ec430 @tj fix req/rep docs. Closes #59
authored
173 Respond to the "resize" task:
6792e01 @tj add req/rep docs
authored
174
175 ```js
176 var axon = require('axon')
177 , sock = axon.socket('rep');
178
179 sock.connect(3000);
180
181 sock.on('message', function(task, img, reply){
182 switch (task.toString()) {
183 case 'resize':
184 // resize the image
185 reply(img);
186 break;
187 }
188 });
189 ```
190
779e21d @tj docs
authored
191 ## PubEmitter / SubEmitter
5c2217f @tj Initial commit
authored
192
8bb5ddd @tj docs
authored
193 `PubEmitter` and `SubEmitter` are higher-level `Pub` / `Sub` sockets, using the "json" codec to behave much like node's `EventEmitter`. When a `SubEmitter`'s `.on()` method is invoked, the event name is `.subscribe()`d for you. Each wildcard (`*`) or regexp capture group is passed to the callback along with regular message arguments.
5c2217f @tj Initial commit
authored
194
779e21d @tj docs
authored
195 app.js:
5c2217f @tj Initial commit
authored
196
197 ```js
afe7fd5 @tj rename to axon
authored
198 var axon = require('axon')
779e21d @tj docs
authored
199 , sock = axon.socket('pub-emitter');
5c2217f @tj Initial commit
authored
200
779e21d @tj docs
authored
201 sock.connect(3000);
5c2217f @tj Initial commit
authored
202
203 setInterval(function(){
204 sock.emit('login', { name: 'tobi' });
205 }, 500);
206 ```
207
779e21d @tj docs
authored
208 logger.js:
5c2217f @tj Initial commit
authored
209
210 ```js
afe7fd5 @tj rename to axon
authored
211 var axon = require('axon')
779e21d @tj docs
authored
212 , sock = axon.socket('sub-emitter');
5c2217f @tj Initial commit
authored
213
779e21d @tj docs
authored
214 sock.bind(3000);
5c2217f @tj Initial commit
authored
215
853c449 @tj add more docs
authored
216 sock.on('user:login', function(user){
5c2217f @tj Initial commit
authored
217 console.log('%s signed in', user.name);
218 });
853c449 @tj add more docs
authored
219
220 sock.on('user:*', function(action, user){
221 console.log('%s %s', user.name, action);
222 });
223
224 sock.on('*', function(event){
225 console.log(arguments);
226 });
5c2217f @tj Initial commit
authored
227 ```
228
23b783e document new sockets
Garrett Johnson authored
229 ## Socket Options
230
231 Every socket has associated options that can be configured via `get/set`.
232
2d2e77d @tj Release 0.4.5
authored
233 - `identity` - the "name" of the socket that uniqued identifies it.
234 - `retry timeout` - connection retry timeout in milliseconds [100]
235 - `retry max timeout` - the cap for retry timeout length in milliseconds [5000]
7829221 @tj add HWM support. Closes #19
authored
236 - `hwm` - the high water mark threshold for queues [Infinity]
23b783e document new sockets
Garrett Johnson authored
237
2153413 @tj add some docs for the previous commit
authored
238 ## Binding / Connecting
239
23b783e document new sockets
Garrett Johnson authored
240 In addition to passing a portno, binding to INADDR_ANY by default, you
241 may also specify the hostname via `.bind(port, host)`, another alternative
242 is to specify the url much like zmq via `tcp://<hostname>:<portno>`, thus
243 the following are equivalent:
2153413 @tj add some docs for the previous commit
authored
244
245 ```
246 sock.bind(3000)
247 sock.bind(3000, '0.0.0.0')
248 sock.bind('tcp://0.0.0.0:3000')
249
250 sock.connect(3000)
251 sock.connect(3000, '0.0.0.0')
252 sock.connect('tcp://0.0.0.0:3000')
253 ```
254
5c2217f @tj Initial commit
authored
255 ## Protocol
256
23b783e document new sockets
Garrett Johnson authored
257 The wire protocol is simple and very much zeromq-like, where `<length>` is
258 a BE 24 bit unsigned integer representing a maximum length of roughly ~16mb. The `<meta>`
259 data byte is currently only used to store the codec, for example "json" is simply `1`,
260 in turn JSON messages received on the client end will then be automatically decoded for
261 you by selecting this same codec.
5c2217f @tj Initial commit
authored
262
263 ```
264 octet: 0 1 2 3 <length>
265 +------+------+------+------+------------------...
266 | meta | <length> | data ...
267 +------+------+------+------+------------------...
268 ```
269
23b783e document new sockets
Garrett Johnson authored
270 Thus 5 bytes is the smallest message axon supports at the moment. Later if
271 necessary we can use the meta to indicate a small message and ditch octet 2 and 3
272 allowing for 3 byte messages.
05fbb1f @tj refactor framing
authored
273
43fbdf1 @tj add ss.codec.define() docs
authored
274 ## Codecs
275
23b783e document new sockets
Garrett Johnson authored
276 To define a codec simply invoke the `axon.codec.define()` method, for example
277 here is the JSON codec:
43fbdf1 @tj add ss.codec.define() docs
authored
278
279 ```js
23b783e document new sockets
Garrett Johnson authored
280 var axon = require('axon');
43fbdf1 @tj add ss.codec.define() docs
authored
281
23b783e document new sockets
Garrett Johnson authored
282 axon.codec.define('json', {
43fbdf1 @tj add ss.codec.define() docs
authored
283 encode: JSON.stringify,
284 decode: JSON.parse
285 });
286 ```
287
23b783e document new sockets
Garrett Johnson authored
288 __Note:__ codecs must be defined on both the sending and receiving ends, otherwise
289 axon cannot properly decode the messages. You may of course ignore this
065e458 @tj fix readme typos
authored
290 feature all together and simply pass encoded data to `.send()`.
43fbdf1 @tj add ss.codec.define() docs
authored
291
91f026a @tj add benchmarks to readme
authored
292 ## Performance
293
7f75c26 @tj remove batching
authored
294 Preliminary benchmarks on my Macbook Pro based on 10 messages
295 per tick as a realistic production application would likely have
296 even less than this. "better" numbers may be acheived with batching
297 and a larger messages/tick count however this is not realistic.
8a27a53 @tj add more bm results to readme
authored
298
2464ae5 @tj update benchmarks. Closes #72
authored
299 64 byte messages:
8a27a53 @tj add more bm results to readme
authored
300
301 ```
302
2464ae5 @tj update benchmarks. Closes #72
authored
303 min: 47,169 ops/s
304 mean: 465,127 ops/s
305 median: 500,000 ops/s
306 total: 2,325,636 ops in 5s
307 through: 28.39 mb/s
8a27a53 @tj add more bm results to readme
authored
308
309 ```
310
311 1k messages:
312
313 ```
314
7f75c26 @tj remove batching
authored
315 min: 48,076 ops/s
316 mean: 120,253 ops/s
317 median: 121,951 ops/s
318 total: 601,386 ops in 5.001s
319 through: 117.43 mb/s
5fb13be @tj add redis comparison
authored
320
321 ```
322
a127f73 @tj docs
authored
323 8k messages:
324
325 ```
afdf60e @tj docs
authored
326
7f75c26 @tj remove batching
authored
327 min: 36,496 ops/s
328 mean: 53,194 ops/s
329 median: 50,505 ops/s
330 total: 266,506 ops in 5.01s
331 through: 405.84 mb/s
afdf60e @tj docs
authored
332
a127f73 @tj docs
authored
333 ````
334
7f75c26 @tj remove batching
authored
335 32k messages:
336
337 ```
338
339 min: 12,077 ops/s
340 mean: 14,792 ops/s
341 median: 16,233 ops/s
342 total: 74,186 ops in 5.015s
343 through: 462.28 mb/s
344
345 ```
346
00b5dcc @tj add some docs
authored
347 ## What's it good for?
348
56d87b6 @tj docs
authored
349 Axon are not meant to combat zeromq nor provide feature parity,
00b5dcc @tj add some docs
authored
350 but provide a nice solution when you don't need the insane
351 nanosecond latency or language interoperability that zeromq provides
afe7fd5 @tj rename to axon
authored
352 as axon do not rely on any third-party compiled libraries.
00b5dcc @tj add some docs
authored
353
5c2217f @tj Initial commit
authored
354 ## Running tests
355
356 ```
357 $ npm install
358 $ make test
359 ```
360
a3db9ac @tj authors
authored
361 ## Authors
362
363 - [visionmedia](http://github.com/visionmedia)
364 - [gjohnson](https://github.com/gjohnson)
365
18f2621 @tj Update master
authored
366 ## Links
367
368 - [Screencast](https://vimeo.com/45818408)
989b8c0 @tj add axon-rpc link
authored
369 - [Axon RPC](https://github.com/visionmedia/axon-rpc)
18f2621 @tj Update master
authored
370
23b783e document new sockets
Garrett Johnson authored
371 ## License
5c2217f @tj Initial commit
authored
372
7829221 @tj add HWM support. Closes #19
authored
373 MIT
5c2217f @tj Initial commit
authored
374
Something went wrong with that request. Please try again.