はじめてのRuby(Rack)挑戦記録

5:07
おはようございます。
今日は今までやろうやろうと思って放置していたRubyに初挑戦します。
perl使いなので書き方や考え方がperlに偏っているかもしれませんがご了承下さい。

5:10
まずはRubyのインストール

sudo apt-get install librack-ruby


5:13
hello world
参考にしたのはこのページ
http://route477.net/d/?date=20080716

mkdir rack
cd rack
vi criticalspeed.rb

rbというのはperlでいうところのpmなのだろうか?
→plのようなものらしい(by IRC)

criticalspeed.rb

require 'rubygems'
require 'rack'

class CriticalSpeed
  def call(env)
    [200, {"Content-Type" => "text/plain"}, ["Hello, World"]]
  end
end
vi criticalspeed.ru

多分ruというのはperlでいうところのpl。
→.psgi相当とのこと(by twitter

criticalspeed.ru

require 'criticalspeed'
run CriticalSpeed.new
rackup criticalspeed.ru

no such file to load rubygems

sudo apt-get install rubygems
rackup criticalspeed.ru

無事wgethello world成功。9292番portが標準みたい。

9:36
もう30分経過。新しいことをやると時間が経つのがはやいなあ。
次はKyoto Cabinet入れる。
実はこれのrubyバインディングが触りたくて今日rubyをはじめたようなもの。
参考にしたのはこのページ
http://1978th.net/kyotocabinet/spex-en.html
http://1978th.net/kyotocabinet/rubydoc/

sudo apt-get install g++
cd /tmp
wget http://1978th.net/kyotocabinet/kyotocabinet-0.9.8.tar.gz
tar zxvf kyotocabinet-0.9.8.tar.gz
cd kyotocabinet-0.9.8
./configure
make
make check
sudo make install
cd ..
wget http://1978th.net/kyotocabinet/rubypkg/kyotocabinet-ruby-1.0.tar.gz
tar zxvf kyotocabinet-ruby-1.0.tar.gz
cd kyotocabinet-ruby-1.0
ruby extconf.rb

no such file to load mkmf
extconf.rb は Makefile.pl相当?
ruby のバージョンは1.8.7みたい。1.9を入れるべきかもしれないけど、よくわからないので保留。

sudo apt-get install ruby1.8-dev
ruby extconf.rb
make
sudo make install

インストールに成功した模様

6:02
開始から約1時間経過。
今度はKyotoCabinetに値を入れる練習。

cd ~/rack
vi make_kyotocabinet_benchmark_htmls.rb

make_kyotocabinet_benchmark_htmls.rb

require 'kyotocabinet'
include KyotoCabinet

DB::process('casket.kch', DB::OWRITER | DB::OCREATE) do |db|
  db['www.example.com/index.html'] = 'hello kyoto cabinet'
end

何故DBを閉じなくていいのかわからない。do |db|ってなんだ?tie?
IRCで教えてもらったけどまだ???状態
エラーが出ていないので値が入ったと仮定して先に進む。
→作者のブログで解説が出て理解できた
mixi Engineers’ Blog » 京都収納棚紅玉束縛: Rubyで簡単、DBプログラミング mixi Engineers’ Blog » 京都収納棚紅玉束縛: Rubyで簡単、DBプログラミング

6:27
KyotoCabinetから値を取り出してRack経由で表示してみる。

criticalspeed.rb

require 'rubygems'
require 'rack'
require 'kyotocabinet'
include KyotoCabinet

class CriticalSpeed
  def call(env)
    req = Rack::Request.new(env)
    fullpath = req.fullpath().sub(/^\//, '')
    output = nil
    DB::process('casket.kch', DB::OREADER) do |db|
      output = db[fullpath]
    end
    if output
      [200, {"Content-Type" => "text/html"}, [output]]
    else
      [404, {"Content-Type" => "text/plain"}, ['404 not found']]
    end
  end
end

置換の違いにとまどったけど、なんとかできた。
perl版とちょっと違うけどrubyのほうが短く書けるなあ。

7:25
別のマシンからベンチマークを取ってみる

/usr/sbin/ab -n 100 -c 10 http://192.168.1.123:9292/www.example.com/index.html
Request per second: 15.81 [#/sec] (mean)

Rack(WEBrick)が遅いなあと感じる。Rackで使えるウェブサーバーって何がオススメ?
いずれにしても私のrubyスキルでは最適化なんてとても無理っぽい。

7:35
@j_kinjou さんからThinやEventedMongrelがいいとの情報 thx。
twitter便利。

sudo apt-get install gem
sudo gem install rack
sudo gem install thin
rackup --env production -s thin criticalspeed.ru
/usr/sbin/ab -n 10000 -c 100 http://192.168.1.123:9292/www.example.com/index.html
Request per second: 1193.70 [#/sec] (mean)

Mongrelを入れて何これはやい。もしかしてperl版よりはやいんじゃないか?
と思ったらデータが帰って来ていない。
Thinも何故か動かない
本日初のハマリなので朝食を食べる

9:00
とりあえずこの記事を公開する。
あとRubyIRCに入ってみた。日本語が使えるのが嬉しい。

はまった原因は --env productionだった模様。その遠因としてRackのバージョンが0.1だった。
というわけでRuby Enterprize EditionというのをIRCで教えてもらいインストールした。
その後流れで、Passengerをインストール
http://www.modrails.com/install.html

11:04
IRCで教わって環境を新しくした結果Thinが動いた

sudo apt-get install gem
sudo gem install rack
sudo gem install thin
rackup --env production -s thin criticalspeed.ru
/usr/sbin/ab -n 10000 -c 100 http://192.168.1.123:9292/www.example.com/index.html
Total transferred: 190000 bytes
Request per second: 591.91 [#/sec] (mean)

16:00
お昼寝していたらこんな時間になった。
50000ページKyotoCabinetに突っ込む時間を計測することにする。

make_kyotocabinet_benchmark_htmls.rb

require 'kyotocabinet'
require 'rubygems'
require 'random_data'
require 'net/http'
include KyotoCabinet
Net::HTTP.version_1_2

html_body = Net::HTTP.get('www.real-unreal.info', '/readmejp100.html')
DB::process('casket.kch', DB::OWRITER | DB::OCREATE) do |db|
  domain = 'www.example.com'
  db[domain + '/index.html'] = html_body;
  10000.times do
    rand_word = Random.alphanumeric(5)
    dir_name = domain + '/' + rand_word
    ["index", *"index2".."index5"].each{|base| db["#{dir_name}/#{base}.html"] = html_body}
  end
end
time ruby make_kyotocabinet_benchmark_htmls.rb
1.34s user 1.76s system 12% cpu 24.262 total
/usr/sbin/ab -n 10000 -c 100 http://192.168.1.123:9292/www.example.com/index.html
Total transferred: 138440000 bytes
Request per second: 182.61 [#/sec] (mean)

というわけではじめてのRubyプログラミングとしてやりたいことは一応できました。
IRCで助けてくれたRubyコミュニティの方々ありがとうございました。
ソースでRubyらしくない書き方とかあると思うので気がついたら教えてください。

WEBrickとThinでパフォーマンスが一桁以上違うんですね。

18:00
RubyIRCでソースを見てもらう。
Net::HTTPが1行で書ける事をおしえてもらったので修正

18:13
10000.times.do end という書き方を教えてもらったので修正
もはや最後のは元々自分で書いたコードと別物に修正

追記:作者の方の解説(ちょっと難しいです)
mixi Engineers’ Blog » 京都収納棚紅玉束縛: Rubyで簡単、DBプログラミング mixi Engineers’ Blog » 京都収納棚紅玉束縛: Rubyで簡単、DBプログラミング