node.js+Socket.IOでリアルタイムアプリケーションが作れるわけだけど、WebSocket使うにしてもXHR-Polling使うにしてもサーバ経由して通信していれば当然タイムラグはあるわけで、それってどれくらい遅延するものなんだろう? と思っていろんなサーバで試してみた(追記しました)。
測定方法
var server = require('http').createServer(function (req, res) { require('data-section').get('html', function (err, data) { res.writeHead(200, { 'Content-Type': 'text/html' }); res.end(data); }); }); var io = require('socket.io').listen(server); // io.set('transports', ['xhr-polling']); io.sockets.on('connection', function (socket) { socket.on('ping', function (data) { socket.broadcast.json.emit('pong', { clients: Object.keys(io.sockets.clients()).length, data: data }); }); }); server.listen(3000); /*__DATA__ @@ html <!DOCTYPE html> <html> <head> <title>test</title> <script type="text/javascript" src="/socket.io/socket.io.js"></script> <script type="text/javascript"> var start = new Date().getTime(); var socket = io.connect(); var ua = window.navigator.userAgent; socket.on('pong', function (data) { var delay = new Date().getTime() - data.data.datetime; if (data.data.ua === ua) { console.log('pong: ' + delay + ' ms on ' + data.clients + ' clients'); } }); socket.on('connect', function () { console.log('connect: ' + (new Date().getTime() - start)); setInterval(function () { socket.emit('ping', { datetime: new Date().getTime(), ua: ua }); }, 1000); }); </script> </head> <body> </body> </html> __DATA__*/
こんなかんじで、Socket.IOに繋いで1秒毎にnew Date().getTime()
の値とuserAgentをサーバに送る。サーバはそれをそのまますべてのクライアントにbroadcastする。受け取った側はその瞬間の時間と受け取った値の時間の差分を算出する。これが、実際にどこかのクライアントからのメッセージが他のクライアントに届くまでのタイムラグになる、はず。
Chrome, Safari, Firefox, socket.io-clientから5接続ずつ繋いで合計20接続を維持する。同じアプリの別タブからのものだけがconsoleに出力されるので、Chrome(13.0.782.218 WebSocket使える)でそれをサンプリングしてみた。
ローカルサーバ(WebSocket)
node v0.4.11
まずはもっとも早いと思われる環境。ローカル環境でnodeサーバを立ち上げてlocalhostにアクセスする場合。
3 ms on 20 clients 2 ms on 20 clients 4 ms on 20 clients 4 ms on 20 clients 1 ms on 20 clients 3 ms on 20 clients 5 ms on 20 clients 2 ms on 20 clients 3 ms on 20 clients 3 ms on 20 clients ...
平均3.12ms。ほぼラグ無し。
ローカルサーバ(XHR-Polling)
var io = require('socket.io').listen(server);
+ io.set('transports', ['xhr-polling']);
io.sockets.on('connection', function (socket) {
とやって、無理矢理XHR-Pollingを使うように変えてみる。
40 ms on 20 clients 19 ms on 20 clients 19 ms on 20 clients 10 ms on 20 clients 17 ms on 20 clients 52 ms on 20 clients 29 ms on 20 clients 28 ms on 20 clients 22 ms on 20 clients 13 ms on 20 clients ...
平均23.17ms。やはりWebSocketの方が早いらしい。
さくらVPS(WebSocket)
CentOS 5.5, node v0.4.11
ローカルと同じものをさくらVPSで借りてるサーバ上で動かしてみた。
27 ms on 20 clients 10 ms on 20 clients 10 ms on 20 clients 8 ms on 20 clients 17 ms on 20 clients 9 ms on 20 clients 9 ms on 20 clients 11 ms on 20 clients 15 ms on 20 clients 9 ms on 20 clients ...
平均14.99ms。さすがにローカルよりは遅くなるけどかなり早い。
さくらVPS(XHR-Polling)
同様に強制的にXHR-Pollingにすると
12 ms on 20 clients 29 ms on 20 clients 13 ms on 20 clients 53 ms on 20 clients 21 ms on 20 clients 30 ms on 20 clients 13 ms on 20 clients 34 ms on 20 clients 20 ms on 20 clients 24 ms on 20 clients ...
平均26.77ms。こちらは意外とローカルと変わらないかも。
Joyent
JoyentのSmartMachines。WebSocketが普通に使える。
node v0.4.11
195 ms on 20 clients 204 ms on 20 clients 195 ms on 20 clients 204 ms on 20 clients 195 ms on 20 clients 204 ms on 20 clients 195 ms on 20 clients 204 ms on 20 clients 196 ms on 20 clients 205 ms on 20 clients ...
平均199.88ms。結構差が出るんですね…
DotCloud
DotCloudはWebSocket使えなくて、XHR-Pollingも通常は使えないので以前試した方法で無理矢理動かす。
node v0.4.10
341 ms on 20 clients 412 ms on 20 clients 279 ms on 20 clients 291 ms on 20 clients 234 ms on 20 clients 236 ms on 20 clients 310 ms on 20 clients 333 ms on 20 clients 295 ms on 20 clients 294 ms on 20 clients ...
平均330.28ms。
Heroku
HerokuのCeder StackでNodeを動かす。これもWebSocketは使えないので強制的にXHR-Pollingで動かす。
node v0.4.7
416 ms on 20 clients 339 ms on 20 clients 224 ms on 20 clients 326 ms on 20 clients 256 ms on 20 clients 260 ms on 20 clients 457 ms on 20 clients 371 ms on 20 clients 302 ms on 20 clients 208 ms on 20 clients
平均329.59。DotCloudと同じくらい?
まとめ
local | WebSocket | 3.12 |
local | XHR-Polling | 23.17 |
さくらVPS | WebSocket | 14.99 |
さくらVPS | XHR-Polling | 26.77 |
Joyent | WebSocket | 199.88 |
DotCloud | XHR-Polling | 330.28 |
Heroku | XHR-Polling | 329.59 |
いわゆるクラウドサービスは自分でサーバ用意しなくても気軽にアプリ作れて便利だけど、結構タイムラグは出るのでそのへんは注意した方が良いかも。それでも使うならやはりWebSocket使えるJoyentが良さげ。
WebSocket使えないブラウザでの速度も統一して計るべきだったかな…あとで計り直そうっと
追記
というツッコミをいただきました。確かにネットワークの遠さにとの関連も知りたいですね…というわけでpingも調べつつ全部計り直してみました。
client (すべて Mac OS X 10.6.8):
- Google Chrome 13.0.782.218
- Safari Version 5.1 (6534.50)
- Firefox 6.0.1
- socket.io-client 0.8.0
ping | Chrome | Safari | Firefox | sio-client | ||
---|---|---|---|---|---|---|
local | WebSocket | 0.1155 | 1.82 | 3.44 | 124.35 | 3.45 |
local | XHR-Polling | 0.1155 | 68.54 | 19.28 | 201.39 | 11.00 |
さくらVPS | WebSocket | 3.8999 | 7.66 | 14.45 | 76.89 | 36.56 |
さくらVPS | XHR-Polling | 3.8999 | 83.28 | 36.91 | 291.91 | 263.05 |
Joyent | WebSocket | 221.0034 | 205.2 | 211.39 | 766.38 | 251.58 |
DotCloud | XHR-Polling | 249.8081 | 498.45 | 2302.03 | 622.19 | 1594.32 |
Heroku | XHR-Polling | - | 512.06 | 518.21 | 471.19 | 895.93 |
なんか昨夜計ったものともだいぶ結果が違う…DotCloud x Safariの異常な数値は何だろう…? 計るタイミングやネットワークによって結構ぶれるのかなぁ
EC2の各リージョンとかでも試してみたいところですね。Flash Socketだとどうなるのか、なども気になるところです。