Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 386 lines (272 sloc) 9.323 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
23b783e document new sockets
Garrett Johnson authored
16
17 ## Patterns
18
19 - push / pull
20 - pub / sub
21 - req / rep
6792e01 @tj add req/rep docs
authored
22 - emitter
5c2217f @tj Initial commit
authored
23
24 ## Push / Pull
25
0e7ade0 @tj tweak docs
authored
26 `PushSocket`s distribute messages round-robin:
5c2217f @tj Initial commit
authored
27
28 ```js
afe7fd5 @tj rename to axon
authored
29 var axon = require('axon')
30 , sock = axon.socket('push');
5c2217f @tj Initial commit
authored
31
32 sock.bind(3000);
33 console.log('push server started');
34
35 setInterval(function(){
36 sock.send('hello');
37 }, 150);
38 ```
39
0e7ade0 @tj tweak docs
authored
40 Receiver of `PushSocket` messages:
5c2217f @tj Initial commit
authored
41
42 ```js
afe7fd5 @tj rename to axon
authored
43 var axon = require('axon')
44 , sock = axon.socket('pull');
5c2217f @tj Initial commit
authored
45
b3cabbb @tj fix readme example
authored
46 sock.connect(3000);
5c2217f @tj Initial commit
authored
47
b3cabbb @tj fix readme example
authored
48 sock.on('message', function(msg){
49 console.log(msg.toString());
50 });
5c2217f @tj Initial commit
authored
51 ```
52
23b783e document new sockets
Garrett Johnson authored
53 Both `PushSocket`s and `PullSocket`s may `.bind()` or `.connect()`. In the
561889c @tj add more docs
authored
54 following configuration the push socket is bound and pull "workers" connect
55 to it to receive work:
7449cfb @tj add more docs for push/pull
authored
56
57 ![push bind](http://f.cl.ly/items/473u3m1a0k1i0J0I3s04/ss-push.png)
561889c @tj add more docs
authored
58
59 This configuration shows the inverse, where workers connect to a "sink"
60 to push results:
61
7449cfb @tj add more docs for push/pull
authored
62 ![pull bind](http://f.cl.ly/items/3Y0j2v153Q0l1r373i0H/ss-pull.png)
63
5c2217f @tj Initial commit
authored
64 ## Pub / Sub
65
23b783e document new sockets
Garrett Johnson authored
66 `PubSocket`s send messages to all subscribers without queueing. This is an
67 important difference when compared to a `PushSocket`, where the delivery of
68 messages will be queued during disconnects and sent again upon the next connection.
5c2217f @tj Initial commit
authored
69
70 ```js
afe7fd5 @tj rename to axon
authored
71 var axon = require('axon')
72 , sock = axon.socket('pub');
5c2217f @tj Initial commit
authored
73
74 sock.bind(3000);
75 console.log('pub server started');
76
77 setInterval(function(){
78 sock.send('hello');
79 }, 500);
80 ```
81
23b783e document new sockets
Garrett Johnson authored
82 `SubSocket` simply recieves any messages from a `PubSocket`:
5c2217f @tj Initial commit
authored
83
84 ```js
afe7fd5 @tj rename to axon
authored
85 var axon = require('axon')
86 , sock = axon.socket('sub');
5c2217f @tj Initial commit
authored
87
88 sock.connect(3000);
89
90 sock.on('message', function(msg){
91 console.log(msg.toString());
92 });
93 ```
94
6792e01 @tj add req/rep docs
authored
95 ## Req / Rep
96
97 `ReqSocket` is similar to a `PushSocket` in that it round-robins messages
98 to connected `RepSocket`s, however it differs in that this communication is
99 bi-directional, every `req.send()` _must_ provide a callback which is invoked
100 when the `RepSocket` replies.
101
102 ```js
103 var axon = require('axon')
104 , sock = axon.socket('req');
105
106 req.bind(3000);
107
108 req.send(img, function(res){
109
110 });
111 ```
112
113 `RepSocket`s receive a `reply` callback that is used to respond to the request,
114 you may have several of these nodes.
115
116 ```js
117 var axon = require('axon')
118 , sock = axon.socket('rep');
119
120 sock.connect(3000);
121
122 sock.on('message', function(img, reply){
123 // resize the image
124 reply(img);
125 });
126 ```
127
128 Like other sockets you may provide multiple arguments or an array of arguments,
129 followed by the callbacks. For example here we provide a task name of "resize"
130 to facilitate multiple tasks over a single socket:
131
132 ```js
133 var axon = require('axon')
134 , sock = axon.socket('req');
135
136 req.bind(3000);
137
138 req.send('resize', img, function(res){
139
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(task, img, reply){
153 switch (task.toString()) {
154 case 'resize':
155 // resize the image
156 reply(img);
157 break;
158 }
159 });
160 ```
161
5c2217f @tj Initial commit
authored
162 ## EmitterSocket
163
164 `EmitterSocket`'s send and receive messages behaving like regular node `EventEmitter`s.
23b783e document new sockets
Garrett Johnson authored
165 This is achieved by using pub / sub sockets behind the scenes and automatically formatting
065e458 @tj fix readme typos
authored
166 messages with the "json" codec. Currently we simply define the `EmitterSocket` as a `PubSocket` if you `.bind()`, and `SubSocket` if you `.connect()`, providing the natural API you're used to:
5c2217f @tj Initial commit
authored
167
168 server.js:
169
170 ```js
afe7fd5 @tj rename to axon
authored
171 var axon = require('axon')
172 , sock = axon.socket('emitter');
5c2217f @tj Initial commit
authored
173
174 sock.bind(3000);
175 console.log('pub server started');
176
177 setInterval(function(){
178 sock.emit('login', { name: 'tobi' });
179 }, 500);
180 ```
181
182 client.js:
183
184 ```js
afe7fd5 @tj rename to axon
authored
185 var axon = require('axon')
186 , sock = axon.socket('emitter');
5c2217f @tj Initial commit
authored
187
188 sock.connect(3000);
189 console.log('sub client connected');
190
191 sock.on('login', function(user){
192 console.log('%s signed in', user.name);
193 });
194 ```
195
23b783e document new sockets
Garrett Johnson authored
196 ## Req / Rep
197
065e458 @tj fix readme typos
authored
198 `ReqSocket`s send and receive messages, queueing messages on remote disconnects. There
199 is no "lock step" involved, allowing messages sent later to receive replies prior to
200 previously sent messages. `RepSocket`s reply to received messages, there is no concept of `send()`. Each
201 received message will have a `reply` callback, which will send the response back to the remote peer:
23b783e document new sockets
Garrett Johnson authored
202
203 client.js
204 ```js
1c22b06 @tj fix readme require()s
authored
205 var axon = require('axon')
23b783e document new sockets
Garrett Johnson authored
206 , sock = axon.socket('req');
207
208 sock.connect(3000);
209
210 sock.on('message', function(msg){
211 console.log('got: %s', msg.toString());
212 });
213
214 setInterval(function(){
215 sock.send('ping');
216 }, 150);
217 ```
218
219 server.js
220 ```js
221
1c22b06 @tj fix readme require()s
authored
222 var axon = require('axon')
23b783e document new sockets
Garrett Johnson authored
223 , sock = axon.socket('rep');
224
225 sock.bind(3000);
226
227 sock.on('message', function(msg, reply){
228 console.log('got: %s', msg.toString());
229 reply('pong');
230 });
231 ```
232
233 ## Socket Options
234
235 Every socket has associated options that can be configured via `get/set`.
236
237 - `identity` - The "name" of the socket that uniqued identifies it.
238 - `retry timeout` - The amount of time until retries will not be attempted again.
239
065e458 @tj fix readme typos
authored
240 PubSockets additionally have options for batching:
23b783e document new sockets
Garrett Johnson authored
241
065e458 @tj fix readme typos
authored
242 - `batch max` - Max amount of messages to buffer in memory.
23b783e document new sockets
Garrett Johnson authored
243 - `batch ttl` - Amount of time to buffer messages before sending.
244
2153413 @tj add some docs for the previous commit
authored
245 ## Binding / Connecting
246
23b783e document new sockets
Garrett Johnson authored
247 In addition to passing a portno, binding to INADDR_ANY by default, you
248 may also specify the hostname via `.bind(port, host)`, another alternative
249 is to specify the url much like zmq via `tcp://<hostname>:<portno>`, thus
250 the following are equivalent:
2153413 @tj add some docs for the previous commit
authored
251
252 ```
253 sock.bind(3000)
254 sock.bind(3000, '0.0.0.0')
255 sock.bind('tcp://0.0.0.0:3000')
256
257 sock.connect(3000)
258 sock.connect(3000, '0.0.0.0')
259 sock.connect('tcp://0.0.0.0:3000')
260 ```
261
5c2217f @tj Initial commit
authored
262 ## Protocol
263
23b783e document new sockets
Garrett Johnson authored
264 The wire protocol is simple and very much zeromq-like, where `<length>` is
265 a BE 24 bit unsigned integer representing a maximum length of roughly ~16mb. The `<meta>`
266 data byte is currently only used to store the codec, for example "json" is simply `1`,
267 in turn JSON messages received on the client end will then be automatically decoded for
268 you by selecting this same codec.
5c2217f @tj Initial commit
authored
269
270 ```
271 octet: 0 1 2 3 <length>
272 +------+------+------+------+------------------...
273 | meta | <length> | data ...
274 +------+------+------+------+------------------...
275 ```
276
23b783e document new sockets
Garrett Johnson authored
277 Thus 5 bytes is the smallest message axon supports at the moment. Later if
278 necessary we can use the meta to indicate a small message and ditch octet 2 and 3
279 allowing for 3 byte messages.
05fbb1f @tj refactor framing
authored
280
43fbdf1 @tj add ss.codec.define() docs
authored
281 ## Codecs
282
23b783e document new sockets
Garrett Johnson authored
283 To define a codec simply invoke the `axon.codec.define()` method, for example
284 here is the JSON codec:
43fbdf1 @tj add ss.codec.define() docs
authored
285
286 ```js
23b783e document new sockets
Garrett Johnson authored
287 var axon = require('axon');
43fbdf1 @tj add ss.codec.define() docs
authored
288
23b783e document new sockets
Garrett Johnson authored
289 axon.codec.define('json', {
43fbdf1 @tj add ss.codec.define() docs
authored
290 encode: JSON.stringify,
291 decode: JSON.parse
292 });
293 ```
294
23b783e document new sockets
Garrett Johnson authored
295 __Note:__ codecs must be defined on both the sending and receiving ends, otherwise
296 axon cannot properly decode the messages. You may of course ignore this
065e458 @tj fix readme typos
authored
297 feature all together and simply pass encoded data to `.send()`.
43fbdf1 @tj add ss.codec.define() docs
authored
298
91f026a @tj add benchmarks to readme
authored
299 ## Performance
300
23b783e document new sockets
Garrett Johnson authored
301 I haven't profiled or tuned anything yet but so far for on my macbook pro.
8a27a53 @tj add more bm results to readme
authored
302
dd52c6d @tj add new batching benchmarks
authored
303 64 byte messages:
8a27a53 @tj add more bm results to readme
authored
304
305 ```
306
f195b92 use MBP benchmarks
Tyler Holowaychuk authored
307 min: 22,085 ops/s
308 mean: 585,944 ops/s
309 median: 606,176 ops/s
310 total: 326,7126 ops in 6.5s
311 through: 35.76318359375 mb/s
8a27a53 @tj add more bm results to readme
authored
312
313 ```
314
315 1k messages:
316
317 ```
318
f195b92 use MBP benchmarks
Tyler Holowaychuk authored
319 min: 1,851 ops/s
320 mean: 34,0156 ops/s
321 median: 449,660 ops/s
322 total: 329,831 ops in 4.241s
323 through: 332.18359375 mb/s
5fb13be @tj add redis comparison
authored
324
325 ```
326
00b5dcc @tj add some docs
authored
327 ## What's it good for?
328
56d87b6 @tj docs
authored
329 Axon are not meant to combat zeromq nor provide feature parity,
00b5dcc @tj add some docs
authored
330 but provide a nice solution when you don't need the insane
331 nanosecond latency or language interoperability that zeromq provides
afe7fd5 @tj rename to axon
authored
332 as axon do not rely on any third-party compiled libraries.
00b5dcc @tj add some docs
authored
333
5c2217f @tj Initial commit
authored
334 ## Running tests
335
336 ```
337 $ npm install
338 $ make test
339 ```
340
a3db9ac @tj authors
authored
341 ## Authors
342
343 - [visionmedia](http://github.com/visionmedia)
344 - [gjohnson](https://github.com/gjohnson)
345
18f2621 @tj Update master
authored
346 ## Links
347
348 - [Screencast](https://vimeo.com/45818408)
349
5c2217f @tj Initial commit
authored
350 ## Todo
351
352 - more tests
353 - code cov
354 - weighted fair queuing
ec44133 @tj todo
authored
355 - cap batch size
1f68ca9 @tj todo
authored
356 - zero-copy for batches...
cbb70e5 @tj todo
authored
357 - make batching configurable... disable for lower latency
5c2217f @tj Initial commit
authored
358 - subscriptions
359 - ...
360
23b783e document new sockets
Garrett Johnson authored
361 ## License
5c2217f @tj Initial commit
authored
362
363 (The MIT License)
364
365 Copyright (c) 2012 TJ Holowaychuk &lt;tj@vision-media.ca&gt;
366
367 Permission is hereby granted, free of charge, to any person obtaining
368 a copy of this software and associated documentation files (the
369 'Software'), to deal in the Software without restriction, including
370 without limitation the rights to use, copy, modify, merge, publish,
371 distribute, sublicense, and/or sell copies of the Software, and to
372 permit persons to whom the Software is furnished to do so, subject to
373 the following conditions:
374
375 The above copyright notice and this permission notice shall be
376 included in all copies or substantial portions of the Software.
377
378 THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
379 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
380 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
381 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
382 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
383 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
384 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
385
Something went wrong with that request. Please try again.