0

em-rocketio-linda-clientを作った

インストール

% gem install em-rocketio-linda-client

pure EventMachine実装なので高速。

Lindaで音楽を再生するやつでplayしながらstopタプルを待ち受けるのに使っている。

0

em-websocketで1万クライアント以上さばく方法

em-websocketの接続数の上限が1015ぐらいなんだけど増やせた。forkとかは使わない。

環境はUbuntu12.04。
Macはepoll使えないので無理。

まずこちらを参考にファイルディスクリプタの上限を増やしておく。
ファイルディスクリプタの上限値を増やす – そ、そんなことないんだから!


で、EM::runの前にepollを使うようにしてset_descriptor_table_sizeを設定すればおk

require 'eventmachine'
require 'em-websocket'

EM.epoll
EM.set_descriptor_table_size 60000
EM::run
EM::WebSocket.run :host => "0.0.0.0", :port => 8080 do |ws|
## 略
end
end

クライアント側はem-websocket-clientを使って試した。こちらもEventMachine起動前にEM.epollしてEM.set_descriptor_table_sizeしておく必要ある。

1万クライアント接続している状態で、全クライアントに数byteのデータ送るのに0.5秒ぐらいかかった。
14000ぐらいでなんか動きが怪しくなった。

参考:File: EPOLL [EventMachine]


なかなか上のページに辿りつかなかったんだけど、thinの中でem-websocketを使ってる時にthinの–max-connsオプションを増やしたらなぜかwebsocketの方も接続数が増えちゃったので、thinとrackのソース読んで追って行ったらたどり着いた。

0

HerokuのSinatraにバックグラウンドワーカーを詰め込んで節約

Webアプリと同じプロセスにworker入れてお金が節約できる。


Webアプリは “リクエスト来る→サーバーで処理→レスポンス返す” というのを繰り返すわけだが、サーバーでの処理に時間がかかる場合にそこを別のプロセスに任せて、先にレスポンスを返しておいて、あとで結果は取りに来てよ、という実装をする事がある。


時間がかかる処理は2つに大別できる。

  1. 動画をエンコードするとか。CPU負荷が高くて時間がかかるのでWebサーバーとは別の場所で動かしたい
  2. Twitter APIを10回ぐらい使った結果をまとめて返すとか。CPU負荷は低いけどIO待ちが長い
2の方について、HerokuのRuby環境で安く上げる方法をまとめる。


手法

HerokuのcedarスタックでRuby使う時はwebサーバーとしてThinが起動する。
ThinはEventMachineの中で動いてるので、EM::defer等が使える。
Herokuは1プロセス目は無料、2プロセス目を起動させると課金されるが、EventMachineでworkerをWebアプリのプロセス内に同居させればお金がかからなくなる。


非同期処理

例えば、ユーザー登録されたらメール返す処理の場合
post '/regist_user' do
mail_addr = params[:mail]
send_mail(mail_addr, 'hello!!') ## メール送信する処理
redirect '/' ## トップページに戻す
end
これだとメールが送信されるまでレスポンスを返せないので、ブラウザが固まる。
また、Sinatra+Thinを1プロセスしか起動していない場合、1リクエスト/レスポンス処理するまで次のリクエストが処理できないので、
メール送信されるまで他の人からのアクセスを全員待たせる事になる。


重い処理をEM::deferで囲むだけで、そこは別スレッドで処理される。すぐにレスポンスが返るので、みんな待たずに済む。
post '/regist_user' do
mail_addr = params[:mail]
EM::defer do
send_mail(mail_addr, 'hello!!') ## メール送信する処理
end
redirect '/' ## すぐレスポンス返す
end


たとえばTwitter APIを連続使用する時は1秒間隔を空けろとか指定があるけど、そういうのをSinatraのプロセス内で行うならEM::deferでやってしまうのが良いと思う。
お金払ってdelayed_jobを使わなくても、EM::deferで囲むだけで非同期になるので便利。
CPUに負荷がかかるタイプの処理は素直にお金払って別のプロセス起動したほうがいいと思う。


ジョブキュー

処理時間が長い仕事が大量にある時、仕事のリストを作っておいて、順番に処理していくという手法がある。
普通はDB等に仕事を保存しておいて、Webアプリとは別のプロセスが順番に処理し、結果をDBに入れておくとかするけど
これもWebアプリに内蔵させられる。

config.ru でSinatraアプリを起動した後にEM::deferを書いておくと、Webアプリとは別スレッドでずっと動き続けるループが作れる。
require 'sinatra'
require 'eventmachine'
## (略)

run Sinatra::Application

EM::defer do
loop do
sleep 5
next if @@jobs.empty?
job = @@jobs.shift ## ジョブ1つ取り出す
## job処理する
end
end


起動しといたスレッドにジョブ追加する
post '/add_job' do
@@jobs.push '仕事'
end
キューにはDBとかgearmanとか使ったほうが良いと思う。


注意点

しばらくアクセスが無いと、プロセスがkillされる。クリティカルな処理は大量にキューに入れて処理しない方が良い。
メモリ使用量も注意するべき。Dyno(プロセス)ひとつあたり512MB割り当てられていて、1.5GB超えたら再起動すると書かれている。

実際はアクセスが無いと長くても2,3時間以内にはkillされてる気がするので、この方法あんまりアテにしない方が良いと思う。


あと、この「Sinatraにワーカー埋め込む」というのはEventMachine内で動くWebサーバー(ThinやWebrick)だけで使える方法なので、
自分のサーバーでUnicornやApache+Passengerで運用する場合は動くコードなのか知らない。調べてない。

0

Skype Chat Gatewayと、WebブラウザからSkypeチャットできるやつ作った

半年ぐらい前に作って、書くのを完全に忘れてた。
Skype Botの類が簡単に作れるようになるし、スマホの重いSkypeクライアント起動しなくてもチャット読めたりしてなかなか便利です。skype-socket-gatewayは捨てましょう。

 

Mac版とLinux版がある。Mac版はchatの読み書きができるけど、Linux版はAPIがよくわからなくて書き込みしかできない。

動かし方はそれぞれREADMEに書いたので読んで欲しい
起動するとHTTPサーバーがport 8787で立ち上がる。
自分のプログラム <--(HTTP)--> Skype-Gateway <--(AppleScript)--> Skype.app
という感じで通信する。

HTTP-POSTでchatに発言できるので、bot等が作りやすい。
例えばcurlで発言する
curl -d 'hello!!' http://localhost:8787
これでchatにhello!!と投稿される。


Mac版にはLaunchAgentに登録する.plistファイルも付けておいたので、Mac起動と同時にskype-chat-gatewayも自動起動させれる。

 

ついでにMac版には “WebUI” というディレクトリが同梱されている。
Webブラウザ上でチャットが使える。

SinatraアプリがMac版skype-chat-gatewayと通信している。
スマホ版Skypeが重すぎて常時起動してられないのでちゃちゃっと作ってみた。
ChromeやSafariで開いておくとWebkit NotificationでGrowlのような通知が出るので、本格的にSkype起動して無くても良くなってくる。

Linux版はチャットが読めないのでWebUI付けてない。

0

PhidgetsのサーボモーターをHTTPサーバー化した

phidgets-servo-serverというのを作った。

上のリンク先のgithubにphidgets関連のライブラリのインストール方法は書いてある。準備すると、

phidgets-servo-server --port 8901
でサーバーが起動する。
eventmachine_httpserverでphidgets-ffiをHTTPから使えるようにしただけ。

使い方は簡単で、HTTP-GETでサーボモーターの現在の角度が取得できる
% curl http://localhost:8901
HTTP-POSTで指定角度に回転する。
% curl -d '90' http://localhost:8901
 

 

リポジトリのWebUIディレクトリにHTML+JSでサーボを回すサンプルがある。

phidgets-servo-serverを起動したマシンのディスク上でWebブラウザで開けば、警告がでるがスライダーを回す毎にサーボが回る。
サーバーに置いたらcross domain問題があるのでそのままでは使えない。
Webブラウザ →(ajax)→ サーバー →(HTTP-POST)→ phidgets-servo-server のように中継するwebアプリをSinatraかなんかで書いて使う。


 

 

このような1つのマシンのUSBポートに接続する特殊なデバイスは、同時に複数のプログラムからアクセスする事ができなかったり、ハードウェアと同じマシン上でプログラムを実行しないとならないんだけどサーバー化してしまえばどこからでも使えるようになる。格段に実装しやすくなる。

特殊デバイスはどんどんサーバー化しよう。

他にも
なんかがある。