西脇.rb & 東灘.rb(第3回) SPDYでRails動かすまで + Rubyのthread調べた
もくもく会第3回いってきました。
今回のお題は2つ
なぜ二つになったかというとSPDY調べていくうちに
Rails(ruby) 関係ないやん( ̄Д ̄;)
となったため急遽追加。
Mac(lion) で SPDYでRails動かすまで
nginxが1.4よりSPDYが標準装備となったらしい http://nginx.org/en/CHANGES-1.4
これはもらった!
APサーバーはunicornでもよかったが、自分はネコ科の動物には目がないので nginx + puma でいくことにする。
Nginxをコンパイル。
brewにあるやつみても 1.4.0 ではなさそうなので、ソースを落としてくる。
cd work/ wget http://nginx.org/download/nginx-1.4.0.tar.gz tar zxvf nginx-1.4.0.tar.gz
色々調べるとSSLも最新でないとダメみたい。
Mac(Lion)の標準搭載はだいぶ古いのでこれまたソースをダウンロードしてくる。
NginxのconfigureでOpenSSLのソースあるところを指定するとそのまま取り込んでくれるらしい
べんり〜
cd work/ngix-1.4.0 wget http://www.openssl.org/source/openssl-1.0.1e.tar.gz tar zxvf openssl-1.0.1e.tar.gz
configureはちょっと特殊。
Macで運用するわけではないし、うまくいかなかったときにversion複数さくさく切り替えれると楽かなと適当なところにbinary置く事にした。
あとでbrewで入れるかもしれないし。
最後のオプションでOpenSSLのソースを展開したディレクトリを指定。
./configure \ --prefix=$HOME/work/nginx \ --sbin-path=$HOME/work/nginx/sbin \ --with-http_spdy_module \ --conf-path=$HOME/work/nginx/etc/nginx.conf \ --error-log-path=$HOME/work/nginx/var/error.log \ --http-log-path=$HOME/work/nginx/var/access.log \ --http-client-body-temp-path=$HOME/work/nginx/tmp/client_body \ --http-proxy-temp-path=$HOME/work/nginx/tmp/proxy \ --http-fastcgi-temp-path=$HOME/work/nginx/tmp/fastcgi \ --http-uwsgi-temp-path=$HOME/work/nginx/tmp/uwsgi \ --http-scgi-temp-path=$HOME/work/nginx/tmp/scgi \ --pid-path=$HOME/work/nginx/tmp/nginx.pid \ --lock-path=$HOME/work/nginx/var/nginx \ --with-http_ssl_module \ --with-openssl=./openssl-1.0.1e
ここでエラー
./configure: error: the HTTP rewrite module require the PCRE library. ...
rewrite はおそらく使わないけどとりあえず入れる事にする。
sudo brew install pcre
そしてmake
make
んで、またエラー
WARNING! If you wish to build 64-bit library, then you have to invoke './Configure darwin64-x86_64-cc' *manually* You have about 5 seconds to press Ctrl-C to abort.
いろいろ調べたら OpenSSL の話だった。
んで、configure の中身読みながら以下をconfigureに追加
--with-openssl-opt=darwin64-x86_64-cc
するも撃沈。
いくら調べてもよくわからない(Shellがたいして読めない)んで直接書き換える。
diff -u auto/lib/openssl/make.org auto/lib/openssl/make --- make.org 2013-05-06 21:21:58.000000000 +0900 +++ make 2013-05-06 21:19:42.000000000 +0900 @@ -56,7 +56,7 @@ $OPENSSL/.openssl/include/openssl/ssl.h: $NGX_MAKEFILE cd $OPENSSL \\ && \$(MAKE) clean \\ - && ./config --prefix=$ngx_prefix no-shared $OPENSSL_OPT \\ + && ./Configure darwin64-x86_64-cc --prefix=$ngx_prefix no-shared $OPENSSL_OPT \\ && \$(MAKE) \\ && \$(MAKE) install LIBDIR=lib
make
成功ヾ(@^▽^@)ノ
証明書は以前練習で発行したのを使用。
最後にコンフィグの設定。デフォルトのやつをコピーして見よう見まねで変更
# ここに puma と通信する UnixSocket の path を指定 upstream app { server unix:///var/run/app.sock; } server { # listenポートを変えてssl spdy と追加 listen 3000 default ssl spdy; server_name localhost; # SSLの設定を追加 ssl on; ssl_certificate /path/to/your_cert.cert; ssl_certificate_key /path/to/your_secret.key; ssl_session_timeout 5m; root /path/to/app/public; location / { # root html; # index index.html index.htm; # ここでupstream指定 proxy_pass http://app; # 多分Headerに元のHostを足してる? proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } #error_page 404 /404.html; ....
Railsを準備
まずはインストールするフォルダを作成
mkdir app cd app
次にGemfileを作成。今回はせっかくなので一番新しいのを使った。
source "https://rubygems.org" gem "rails", "4.0.0.rc1"
rails をインストール
bundle install --path vendor/bundle
Railsの基本ファイルを生成。
rails new .
上でGemfileが上書きされるので、上書きされたGemfileにpumaを追加
gem "puma"
puma インストール
bundle
puma確認
bundle exec rails s puma => Booting Puma => Rails 4.0.0.rc1 application starting in development on http://0.0.0.0:3000 => Run `rails server -h` for more startup options => Ctrl-C to shutdown server Puma 2.0.1 starting... * Min threads: 0, max threads: 16 * Environment: development * Listening on tcp://0.0.0.0:3000
最後にSPDY確認
こちら(spdy indicator)のchromeエクテンションで確認。
nginx起動。
sbin/nginx
puma 起動
# -bでさっきnginxで指定した UnixSocket のpathを指定 bundle exec puma -b unix:///var/run/app.sock
ブラウザで確認
RubyのThreadについてしらべる
RubyにはGVL(Giant VM lock)なるものがあるらしくどういうものなのってことで、調べたかったのは以下の5点
- CPU100%以上ちゃんと使うの?
- switchのタイミングは?
- Monitor の便利な使い方
- Thread.currentの使いどころ
- Abort on Exceptionの使いどころ
んで、時間内に調べられたのは上2つ
CPU100%以上ちゃんと使うの?
公式のDocより引用
ネイティブスレッドを用いて実装されていますが、 現在の実装では Ruby VM は Giant VM lock (GVL) を有しており、同時に実行される ネイティブスレッドは常にひとつです。 ただし、IO 関連のブロックする可能性があるシステムコールを行う場合には GVL を解放します。その場合にはスレッドは同時に実行され得ます。 また拡張ライブラリから GVL を操作できるので、複数のスレッドを 同時に実行するような拡張ライブラリは作成可能です。
同時に実行されるネイティブスレッドは常にひとつです。
(・_・?)...ン?
じゃあCPU100%しか使わないの?
def fib(n) n < 2 ? n : fib(n-1) + fib(n - 2) end th1 = Thread.new { sleep 1 100.times { fib(1000) } } th2 = Thread.new { sleep 1 100.times { fib(1000) } } th1.join; th2.join;
ちゃんとつかってる!理由はわからないけど\(^o^)/
switchのタイミングは?
IO 関連のブロックする可能性があるシステムコールを行う場合には GVL を解放します。
さっぱりわからないのでぐぐってみるととてもよいスライドを見つける
http://www.slideshare.net/kosaki55tea/ruby-gvlimprovement-8617719
全ては理解できなかったけど、無理矢理理解すると
- IOのようなwaitが発生しそうな処理のときにswitchする。たぶんsleepもだとおもう
- 長い時間同じthreadが走らないようにTimerでswitchする。これは必ず同じthreadがもう一度Lockをとらないようにしている。
ふむふむ。ならこれでどう?
th1 = Thread.new { sleep 1 30.times { $th1 << $global $global += 1 w.write("..") } } th2 = Thread.new { sleep 1 30.times { $th2 << $global $global += 1 r.read(1) } } th1.join; th2.join p $th1 p "------------" p "------------" p "------------" p $th2
きれいには切り替わらないな \(^o^)/
この辺で時間終了。
レビュー中(発表中) に Unixの仕組みと似ているという大変貴重な意見をいただけたので、時間できたときにもう少しCのRubyのソース追ったりして調べてみようっと。
その後の懇談会にて、こんなぐだぐだな発表に関わらずMVPをいただけたヾ(@^▽^@)ノ
これが何か良くわかってないけど、プリペイドカードっぽいのでスターバックスいって支払いのときに出してみて店員の反応を見て考えようw
今回は書く事多くてつかれたw