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