みなさんこんにちは、リンカーズ情報システム部の大河原です。
弊社でもテックブログを始めることになりました。Twitter(@Linkers4System)とあわせてよろしくお願いします。
LT会 with Matz とは?
リンカーズで運用している2つのWebサービス、
- 「ものづくり系マッチングサービス」Linkers
- 「金融機関向けビジネスマッチング支援システム」Linkers for BANK
では、それぞれフレームワークとしてRuby on Railsを採用しています。
弊社では在籍するエンジニアが技術力を磨いていくための社内勉強会に力をいれており、その一環として、アドバイザー:まつもとゆきひろ氏(Matz)との勉強会を月例で行っています。
まつもとさんは言わずと知れたRubyの生みの親です。リンカーズのエンジニアにとって、この勉強会は普段学んだ技術をぶつけて疑問を解消する場となっています。
勉強会は担当者2名が順にLTを行い、それぞれまつもとさんにコメントをいただく形で進めます。
前置きが長くなりましたが、11月20日(火)に行われた勉強会の様子を紹介します!
LT1「RubyのJITを試してみた」
この度、Ruby 2.6.0-preview3がリリースされたことにより、さっそくメンバーの1人がベンチマークを行ってくれました。
JIT(Just-In-Time)コンパイラとは、コードの実行時にコンパイルを行うことによって実行速度の向上を測る技術です。「OptcarrotというCPU負荷中心のベンチマークにおいてRuby 2.5の約1.7倍の性能向上を達成」しているとのこと。
今回の発表では実用を意識して、実際にプロダクトで用いているRSpecでのModelテストをベンチマークに用いて、
- Ruby2.5.3, 2.6.0-preview3(JITなし), 2.6.0-preview3(JITあり) での比較
- JITのコンパイル結果がキャッシュされるメソッドの数(
jit-max-cache
, デフォルト: 1000)を変化させて比較 - ファイルがJITコンパイルの対象となるための呼び出し回数(
jit-min-calls
, デフォルト: 5)を変化させて比較
を行っていました。
その結果、
- デフォルトで実行するとJITを行ったほうがずっと遅い
- 2.6.0-preview3のJITなしに比べ、JITありは約1.7倍時間がかかる
jit-max-cache
を変化させても、対象メソッドが多すぎて使い尽くしてしまうため、コンパイル時間増加のデメリットの方が大きいjit-min-calls
を増やすと性能が徐々に上がるが、100,000くらいで頭打ちになる- このときの実行時間は2.6.0-preview3のJITなしと同じくらいで、別に速くはない
- デフォルトが5というのは少なすぎる気がする
のような結果と考察が得られました。
まつもとさんからは、以下のようなコメントをいただきました。
- RubyのJITは中間コードとしてC言語を生成する形のため、高速化の工夫はしている
- 工夫1: precompiled header - Ruby標準のHeaderファイルはサイズが大きいので、不要な情報を削除
- 工夫2: コンパイルと実行の並行処理
- JITコンパイラはベンチマークには効くが、実用アプリケーションにはまだ課題が多い
- 2.6.0での進歩は「JITが使えるようになった」ことそのもの
- 将来的にはChromeのJavaScriptエンジンで実績のある2段階JIT構成となる可能性もある
まだまだできたばかりのJITコンパイラですので、ユーザ側として今後の発展に期待、といったところでしょうか。
(参照の局所性が小さいRailsにはそもそもあまり向いてないのかも知れません。まつもとさんからもありましたが、Rubyは「Railsのための言語」ではないですからね
LT2「Rubyスクリプトのデーモン化」
以下のようなお客様の要望がありました。
ユーザテスト環境で操作するとき、複数のアカウントで届いたメールを1人で確認したい
Gmailにアクセスできる環境ならばexample+something@example.com
のようにエイリアスを使えば済む話なのですが、Gmailにアクセスできない環境であるとのこと。
つまり、1人に1つしかメールアドレスがないため、複数のメールアドレスから届いたメールを確認する手段がないということです。
複数アカウントへのメールをすべて受け取れるソフトはいくつかあるものの、開発環境用でユーザ認証などの細かい制御ができず、自作することに。
スクラッチで実装したのは、Railsでできない「メールを受け取る」という操作を行うデーモンです。
しかし、このデーモン化の方法が問題で、情報が錯綜しており何が正解かわからない。使用したライブラリ(MidiSmtpServer)のドキュメントにも書かれていませんでした。
結局、Process.daemon
を使って1行で済ますことにしたとのこと。
まつもとさんによると、Process.daemon
はC言語のdaemonメソッドを継承して作ったとのこと。
「正しい」かどうかは別にして、作者の意図通りの使い方であるようです。
また、Process.daemon
関連のコードを読む過程で以下のような箇所があり、
def daemonize_app if RUBY_VERSION < "1.9" exit if fork Process.setsid exit if fork Dir.chdir "/" STDIN.reopen "/dev/null" STDOUT.reopen "/dev/null", "a" STDERR.reopen "/dev/null", "a" else Process.daemon end end
RUBY_VERSION < "1.9"
の制御構造についても、まつもとさんに聞いてみました。
すると、以下のような回答をいただけました。
- これはダブルフォークと言われるテクニック
- UNIXプロセスを独立させてinitプロセス(全プロセスの親プロセス)の子にする
- 「なるほどUnixプロセス ― Rubyで学ぶUnixの基礎」を読みましょう
システムプログラムに強いメンバーが少なく、ほとんどの人が初めて知った内容でした。
読書会のテーマ候補に一度上がったことがあるのですが、現在のテーマ(「体系的に学ぶ 安全なWebアプリケーションの作り方 第2版」)が終わったら再度検討したほうが良さそうです。
We Are Hiring!!
リンカーズでは、上記レポートにある月例LT会の他、毎週月曜に前島真一(@netwillnet )氏との読書会を行うなど、社内勉強会に力を入れています。
ビジネスマッチングに興味のある方、Railsエンジニアとしてキャリアアップしたい方、どなたでも以下のリンクからお問い合わせください。
今後も、更新を継続していく予定です。ご期待下さい!