0

Sinatra RocketIOのcometの負荷が軽くなった

sinatraにSocketIOっぽいwebsocket/comet機能を追加できるプラグインを作っている。
今日はcometの負荷を軽くした。

shokai/sinatra-rocketio · GitHub


comet、複数回のサーバーへのpushをキューに溜めてまとめて送信するようにした。
cometioのpost_intervalで設定できる

設定例

set :cometio, :timeout => 120, :post_interval => 2
set :websocketio, :port => 8080
set :rocketio, :websocket => true, :comet => true # enable WebSocket and Comet
post_interval => 2 でタメたキューを2秒ごとにサーバーに送る。


websocketは1プロセスで1万5千ぐらい接続できるんだけど、cometが重くて足ひっぱってたのでこれで軽くなったと思う。

例えばこういうコードの時に今まで10回pushされてたけど、10回分まとめてajaxするので軽い。
for(var i = 0; i < 10; i++){
io.push("chat", "hoge("+i+")");
}

sinatra-cometio v0.5.1から有効になってる機能で、sinatra-rocketioとは別のgemなので
bundle updateしてアップデートしてください

0

ブラウザ用EventEmitterを作った

もうあるので車輪の再発明だけど、作った
https://github.com/shokai/event_emitter.js


元々sinatra-cometioの中で使っていたのを切り出して、テストとか書いた。

Ruby版といっしょに使うと楽しい。

event emitterとは


Node.jsに含まれているライブラリ。をWebブラウザだけで動くように実装しなおした。


こんな感じでapplyすると
var User = function(){
new EventEmitter().apply(this);
this.name = '';
};

イベント登録して
var user = new User();
user.name = 'shokai';
user.on('go', function(data.place){
alert(user.name+' -> '+data.place);
});

呼び出せるようになる
user.emit('go', {place: 'mountain'}); // "shokai -> mountain"

あと、onのかわりにonceで登録すると1回だけ呼び出せるイベントになったりとかある。
JavaScriptの全てオブジェクトに簡単にイベント機能が追加できる。
くわしくはREADMEを見て。


test


ブラウザで使うjsだけどterminalでテストしたかったので、nodeunitを使った。


このようにnode実行した時はnode moduleとして読み込めるように、event_emitter.jsの末尾でmodule.exportsに登録しておいた。
var EventEmitter = function(){
/** 略 **/
};

if(typeof module !== 'undefined' && typeof module.exports !== 'undefined'){
module.exports = EventEmitter;
}

あとはnodeunitでテストを書いた。


JavaScriptの圧縮


uglify-jsで圧縮した

0

Sinatra用のcometプラグインを作った

追記:RocketIOに統合されました → 橋本商会 » Sinatra RocketIOというプラグイン作った、これでWebSocketとCometが使える

******

作った

Sinatra Comet I/O

インストール

gem install sinatra-cometio



通信を意識せずに、サーバー側からクライアントの関数、クライアント側からサーバーの関数を呼び出せる。


サーバーからクライアントへプッシュする例

サーバー側


Ruby
require 'sinatra'
require 'sinatra/cometio'

CometIO.push :chat, :name => "shokai", :message=> "hello work!!"


クライアント側


HTML
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<script src="<%= cometio_js %>"></script>

JS
var io = new CometIO().connect();
io.on("chat", function(data){
console.log(data.name + " : " + data.message); // -> "shokai : hello work!!"
});


クライアント→サーバーの例や、新規クライアント接続イベントやエラーイベント等についてもSinatra Comet I/Oに書きました


サンプルとしてHerokuでチャットを作った。 http://cometio-chat.herokuapp.com

チャットの場合同時に300クライアントぐらいしか接続できないっぽい。スケールさせる方法はよくわからない。
少人数で使うちょっとしたツールにリッチなUIを持たせる時などに便利だと思います。


*チャットサンプルですが1台のマシンから2つchrome開いても、交互に通信するみたいです。片方をsafariにするか、chromeをプライベートブラウズモードにすると動きます
色々やってたら大丈夫になりました

0

cometだけどsinatraからサーバープッシュできれば関係ないよね

前に書いたsinatra/streamingでcometするやつを使いやすいようにgemにして、sinatra-cometioというsinatraのpluginを作った。
https://github.com/shokai/sinatra-cometio

thin等のEventMachine上のサーバーで動く。Apache+Passenger等では動かない。


チャットを作った例 http://cometio-chat.herokuapp.com


インストール

gem install sinatra-cometio


なかなか簡単に使えるようになっている。socket.ioを参考にした。

サーバー側
onのイベント名でクライアント側からのアレを受け取って、クライアント側のイベント名を指定して送り返す
require 'sinatra'
require 'sinatra/cometio'

## echo
CometIO.on :chat do |data|
puts "#{data.name} : #{data.message}"
self.push :chat, data # server --> client
end

require ‘sinatra-cometio’すると /cometio 以下にcomet用のrouteやjsファイルが生成されるようになっている。


クライアント側
jQueryが必要。
cometio.jsを読み込むんだけど、cometio.jsのURLはcometio_jsというヘルパー関数が返してくれる
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<script src="<%= cometio_js %>"></script>


on(イベント名, callback)でサーバーから来たデータを受け取る。push(イベント名, データ)でサーバーに送る。
var io = new CometIO().connect();

// client <-- server
io.on("chat", function(data){
consle.log(data.name+" : "+data.message);
});

// client --> server
io.push("chat", {name: "shokai", message: "hello"}); // 送信ボタン押したイベントとかから呼び出す


ちゃんと測ってないけど500ぐらいぶら下がってしばらくすると接続エラーが出始めた。300ぐらいなら問題ない。
大してメモリも食わないのでforkしておけばいいのではないか

まだsessionがないので、つないでいるクライアント全員に送るしかない、なんとかする