Text
Page: 1
Rubyを使った
分散全文検索ミドルウェア
須藤功平
株式会社クリアコード
RubyWorld Conference 2014
2014/11/13
Rubyを使った分散全文検索ミドルウェア
Powered by Rabbit 2.1.4
Page: 2
趣意書
Rubyを
普通の人々に
浸透させたい!
Rubyを使った分散全文検索ミドルウェア
Powered by Rabbit 2.1.4
Page: 3
この発表の内容
浸透促進案の
提案
Rubyを使った分散全文検索ミドルウェア
Powered by Rabbit 2.1.4
Page: 4
浸透対象の普通の人々
✓ よくプログラムを書く人
✓ ただしRubyとは縁遠い
✓ →よくRubyを書くようになる
✓ たまにプログラムを書く人
✓ インフラの人とか
✓ →たまにRubyを書くようになる
Rubyを使った分散全文検索ミドルウェア
Powered by Rabbit 2.1.4
Page: 5
浸透方法
✓ 技術的な攻め方
✓ 多機能・高機能・高性能
✓ 他よりいいですよ
✓ 心理的・政治的な攻め方
✓ 流行り
✓ 「みんな」使っていますよ
Rubyを使った分散全文検索ミドルウェア
Powered by Rabbit 2.1.4
Page: 6
提案方針
✓ 技術的な攻め方
✓ 多機能・高機能・高性能
✓ 他よりいいですよ
✓ 心理的・政治的な攻め方
✓ 流行り
✓ 「みんな」使っていますよ
Rubyを使った分散全文検索ミドルウェア
Powered by Rabbit 2.1.4
Page: 7
流行っている状態
シェアを独占している
✓ キラーアプリがある
✓ 例:Ruby on Rails
✓ 有用アプリの多くがRuby製
✓ 例:Chef, Puppet, Vagrant,
Serverspec
Rubyを使った分散全文検索ミドルウェア
Powered by Rabbit 2.1.4
Page: 8
キラーアプリは難しい
シェアを独占している
✓ キラーアプリがある
✓ 例:Ruby on Rails
✓ 有用アプリの多くがRuby製
✓ 例:Chef, Puppet, Vagrant,
Serverspec
Rubyを使った分散全文検索ミドルウェア
Powered by Rabbit 2.1.4
Page: 9
多有用アプリ状況を目指す
✓ Ruby製アプリ使う
✓ Ruby製アプリを優先して選ぶ
✓ 使っていることを広くアピール
✓ Ruby製アプリを作る
✓ そこそこ有用で十分
✓ たくさん作る
Rubyを使った分散全文検索ミドルウェア
Powered by Rabbit 2.1.4
Page: 10
Ruby製アプリ作りを促す
✓ 成功事例(きっかけ)
✓ 後続が真似したくなればよい
✓ そんなに流行らなくてもよい
✓ 開発ノウハウ(助け)
✓ 後続が開発しやすくなる
✓ ライブラリー化されていると尚よし
Rubyを使った分散全文検索ミドルウェア
Powered by Rabbit 2.1.4
Page: 11
どんなアプリがよいか
ミドルウェア
↓
自作のアプリは
好きな言語で書ける
(言語による採用障壁が低め)
(例:RabbitMQはErlang製だがアプリはErlang以外が多い)
Rubyを使った分散全文検索ミドルウェア
Powered by Rabbit 2.1.4
Page: 12
ミドルウェア
✓ データストア(RDBMSやKVS)
✓ 検索システム
✓ メールシステム
✓ メッセージキュー
✓ ログ活用(分析や監視)
Rubyを使った分散全文検索ミドルウェア
Powered by Rabbit 2.1.4
Page: 13
Rubyでミドルウェア
✓ 成功事例
✓ Fluentd, ROMA
✓ milter manager
✓ 分散全文検索エンジンを開発中
(Droonga)
✓ 開発ノウハウ
✓ →これから紹介
Rubyを使った分散全文検索ミドルウェア
Powered by Rabbit 2.1.4
Page: 14
開発ノウハウ:方針
✓ トレードオフと向き合う
✓ どこを強みにするか
✓ どこは競合と戦わないか
✓ 全方位で勝つことはできない
✓ Rubyだって速さじゃCに勝てない
✓ でも楽しさならCに勝てる
Rubyを使った分散全文検索ミドルウェア
Powered by Rabbit 2.1.4
Page: 15
強みの選び方
✓ 使いやすさで勝負する
✓ 最高速で勝負しない
✓ 多機能で勝負しない
Rubyを使った分散全文検索ミドルウェア
Powered by Rabbit 2.1.4
Page: 16
ミドルウェアの使いやすさ
✓ 導入・設定・運用の簡単さ
✓ 多くのミドルウェアは大変←ヒント
✓ 例:設定なしで動くと簡単
✓ 止めないことが前提
✓ 無停止で設定再読み込み
✓ 無停止でアップグレード
Rubyを使った分散全文検索ミドルウェア
Powered by Rabbit 2.1.4
Page: 17
強みの選び方 - 使いやすさ
✓ 使いやすさで勝負する
✓ ユーザーの手間を減らす
✓ かゆいところに手が届く
✓ 最高速で勝負しない
✓ 多機能で勝負しない
Rubyを使った分散全文検索ミドルウェア
Powered by Rabbit 2.1.4
Page: 18
性能
✓ 最高速は目指さない
✓ C/C++とかJavaに負ける
✓ 十分な速度は目指す
✓ ミドルウェアが
ボトルネックにならない程度
Rubyを使った分散全文検索ミドルウェア
Powered by Rabbit 2.1.4
Page: 19
ミドルウェアと性能
✓ ミドルウェア=サーバー
✓ 並行処理をいかにがんばるか
✓ 評価基準
✓ レイテンシー(1リクエストに注目)
✓ スループット(単位時間に注目)
Rubyを使った分散全文検索ミドルウェア
Powered by Rabbit 2.1.4
Page: 20
ボトルネックの解消方法
✓ なりやすい箇所
✓ CPU
✓ ネットワーク
✓ なるかもしれない箇所
✓ I/Oとメモリー
Rubyを使った分散全文検索ミドルウェア
Powered by Rabbit 2.1.4
Page: 21
CPUネック
✓ 処理を減らす
✓ マルチプロセス
✓ 後述
✓ Cで拡張ライブラリーを書く
✓ Fluentd: MessagePack
✓ Droonga: MessagePack, Groonga
Rubyを使った分散全文検索ミドルウェア
Powered by Rabbit 2.1.4
Page: 22
マルチプロセス実装
✓ ServerEngine(ライブラリー)
✓ nスレッド+シグナル+fork (spawn)
✓ Droonga
✓ 1スレッド+パイプ+spawn +イベントループ
✓ ↑の方がオススメ
Rubyを使った分散全文検索ミドルウェア
Powered by Rabbit 2.1.4
Page: 23
ServerEngine
Process
Supervisor
Logging
Heartbeat
Signal
Rubyを使った分散全文検索ミドルウェア
Thread
fork
Worker
Worker
heartbeat
Worker
signal
Powered by Rabbit 2.1.4
Page: 24
ServerEngineモデル1
✓ 基本はSupervisor→Worker
✓ gracefulな再起動をしにくい
(無停止で設定再読み込みできれば必要ない)
✓ 新Workerの準備完了を知れない
✓ 無停止アップグレード×
Rubyを使った分散全文検索ミドルウェア
Powered by Rabbit 2.1.4
Page: 25
ServerEngineモデル2
✓ スレッドは難しい
✓ エラーをちゃんと処理しないと
問題を見逃す
✓ シグナルは難しい
✓ 終了中に何度でもSIGINT
✓ forkは難しい
Rubyを使った分散全文検索ミドルウェア
Powered by Rabbit 2.1.4
Page: 26
ServerEngineモデル3
✓ ライブラリー化していてえらい
Rubyを使った分散全文検索ミドルウェア
Powered by Rabbit 2.1.4
Page: 27
Droonga
Process
Supervisor
Event loop
spawn
pipe
command
(ready)
(stop)
Rubyを使った分散全文検索ミドルウェア
Worker
Worker
Worker
Powered by Rabbit 2.1.4
Page: 28
Droongaモデル1
✓ 通信はSupervisor↔Worker
✓ gracefulな再起動をしやすい
✓ 新Workerが準備完了
→Supervisorに通知
→旧Workerをgracefulに終了
✓ 無停止更新ができる
Rubyを使った分散全文検索ミドルウェア
Powered by Rabbit 2.1.4
Page: 29
Droongaモデル2
✓ シンプルになる
✓ 1スレッド・シグナルなし
✓ stop中にn回stopがこない
✓ 終了処理中に割り込まれない
✓ イベント駆動は複雑
Rubyを使った分散全文検索ミドルウェア
Powered by Rabbit 2.1.4
Page: 30
ネットワークネック
✓ 通信量を減らす
✓ データを減らす(ムリなら圧縮)
(LZ4で十分ならLZ4、ムリならzlib)
✓ ノンブロッキングI/Oと多重化
✓ 拡張ライブラリー必須
✓ →Cool.io, nio4r, EventMachine
✓ イベント駆動なコードは複雑
Rubyを使った分散全文検索ミドルウェア
Powered by Rabbit 2.1.4
Page: 31
イベント駆動なコード
Coolio::TCPServer.new(HOST, PORT) do |client|
n_reads = 0
client.on_read do |data|
p data
client.write(data)
n_reads += 1
if n_reads == 2
client.on_write_complete {client.close}
end
end
end
Rubyを使った分散全文検索ミドルウェア
Powered by Rabbit 2.1.4
Page: 32
同期っぽく書けるAPI
Coolio::TCPServer.new(HOST, PORT) do |client|
Fiber.run do # <- 並行にしたい処理を明示
client.extend(Synchronizable) # <- 42行
2.times do
data = client.read
p data
client.write(data)
end
client.close
end
end
Rubyを使った分散全文検索ミドルウェア
Powered by Rabbit 2.1.4
Page: 33
同期っぽく書けるAPI
✓ ユーザーがFiberを書くのが
カッコ悪い
✓ 同期っぽい中で
並行に処理したくなったら?
✓ pubsubっぽいことをしたいとか
Rubyを使った分散全文検索ミドルウェア
Powered by Rabbit 2.1.4
Page: 34
Promiseな世界
server.accept.then do |client|
client.read.then do |data|
p data
client.write(data)
end.then do
client.close
end
end.catch do |error|
end
Rubyを使った分散全文検索ミドルウェア
Powered by Rabbit 2.1.4
Page: 35
Promiseな世界
✓ 繰り返しを書きにくい
✓ メソッドチェーンがカッコ悪い
✓ catchがカッコ悪い
Rubyを使った分散全文検索ミドルウェア
Powered by Rabbit 2.1.4
Page: 36
API案:基本
# 同期っぽいAPI
clinet = server.accept
# 非同期API
server.accept do |request|
begin
client = request.socket
rescue
end
end
Rubyを使った分散全文検索ミドルウェア
Powered by Rabbit 2.1.4
Page: 37
API案:組み合わせ
server.accept do |request|
client = request.socket
2.times do
data = client.read
p data
client.write(data)
end
client.close
end
Rubyを使った分散全文検索ミドルウェア
Powered by Rabbit 2.1.4
Page: 38
API案
✓ Fiberが見えない
✓ 書き方の組み合わせが自然
✓ ブロックなし→同期っぽいAPI
✓ ブロックあり→非同期API
✓ 実装していない😜
Rubyを使った分散全文検索ミドルウェア
Powered by Rabbit 2.1.4
Page: 39
I/Oとメモリーネック
✓ データストアをCで書く
✓ Droonga: Groonga
✓ ROMA: Tokyo Cabinet, SQLite3
✓ コアの機能もCで書く
✓ データコピーも減らしたいとき
Rubyを使った分散全文検索ミドルウェア
Powered by Rabbit 2.1.4
Page: 40
強みの選び方 - 性能
✓ 使いやすさで勝負する
✓ 最高速で勝負しない
✓ でも、十分な速度は目指す
✓ ボトルネックにならなければよい
✓ 多機能で勝負しない
Rubyを使った分散全文検索ミドルウェア
Powered by Rabbit 2.1.4
Page: 41
機能
✓ 多機能をウリにしない
✓ 多機能だと遅くなる(ことが多い)
✓ 組み込みの機能より拡張性
✓ →プラグイン機能
✓ Fluentd, ROMA, Droonga
Rubyを使った分散全文検索ミドルウェア
Powered by Rabbit 2.1.4
Page: 42
プラグイン機能のポイント
✓ 開発者向け
✓ 作りやすい
✓ テストしやすい
✓ リリースしやすい
✓ ユーザー向け
✓ インストールしやすい
✓ 設定しやすい
Rubyを使った分散全文検索ミドルウェア
Powered by Rabbit 2.1.4
Page: 43
開発者向け
✓ 作りやすさ
✓ scaffoldいらずのAPI
✓ テストしやすさ
✓ ドライバー・スタブを提供
✓ リリースしやすさ
✓ gem
Rubyを使った分散全文検索ミドルウェア
Powered by Rabbit 2.1.4
Page: 44
ユーザー向け
✓ インストールのしやすさ
✓ Rubyをそんなに知らない前提なのに
直接gemを使ってもらうのってアリ?
✓ 設定のしやすさ
✓ できるだけ少なく
✓ できればno configuration
Rubyを使った分散全文検索ミドルウェア
Powered by Rabbit 2.1.4
Page: 45
強みの選び方 - 機能
✓ 使いやすさで勝負する
✓ 最高速で勝負しない
✓ 多機能で勝負しない
✓ 組込機能よりも簡単拡張で勝負
✓ Ruby初心者でも開発できる簡単さ
✓ →プラグイン開発でRubyデビュー
(tDiaryスタイルのRuby浸透方法)
Rubyを使った分散全文検索ミドルウェア
Powered by Rabbit 2.1.4
Page: 46
まとめ1
✓ 趣意書
✓ Rubyを浸透させたい!
✓ この発表
✓ 浸透促進案の提案
✓ ミドルウェア分野での促進案
Rubyを使った分散全文検索ミドルウェア
Powered by Rabbit 2.1.4
Page: 47
まとめ2:促進案
✓ たくさんの人が使う
✓ 他の方がよさそうでも
Ruby製を優先して使う
✓ 使っていることを広める
✓ たくさん作る
Rubyを使った分散全文検索ミドルウェア
Powered by Rabbit 2.1.4
Page: 48
まとめ3:作るノウハウ
✓ 使いやすさで勝負する
✓ ユーザーの手間を減らす
✓ 最高速で勝負しない
✓ ボトルネックにならなければよい
✓ 多機能で勝負しない
✓ 組込機能より拡張性
Rubyを使った分散全文検索ミドルウェア
Powered by Rabbit 2.1.4
Page: 49
おまけ
Droongaの紹介
Rubyを使った分散全文検索ミドルウェア
Powered by Rabbit 2.1.4
Page: 50
Droongaとは
✓ Ruby製
✓ 分散全文検索エンジン
✓ SPOFなしの構成
Rubyを使った分散全文検索ミドルウェア
Powered by Rabbit 2.1.4
Page: 51
Droongaの特徴
✓ 処理をパイプラインとして
つなげられる 予定
✓ 処理はプラグイン可能
✓ Rubyで簡単に (予定) 書ける
✓ Groonga互換API提供
✓ Groonga = 既存全文検索エンジン
Rubyを使った分散全文検索ミドルウェア
Powered by Rabbit 2.1.4
Page: 52
Droongaの実装:性能
✓ レイテンシー
✓ Groongaより高いけど
気になるほどではない
✓ スループット
✓ ノード数を増やせばGroongaより速い
Rubyを使った分散全文検索ミドルウェア
Powered by Rabbit 2.1.4
Page: 53
Droongaの実装:機能
✓ プラグインで拡張可能
Rubyを使った分散全文検索ミドルウェア
Powered by Rabbit 2.1.4
Page: 54
Droongaの実装:使いやすさ
✓ インストール
✓ インストーラー提供で簡易化
✓ これからがんばる
✓ 設定・更新・運用
✓ プラグインの作りやすさ
Rubyを使った分散全文検索ミドルウェア
Powered by Rabbit 2.1.4
Page: 55
Droonga
http://droonga.org/
11/29(いい肉の日)
Groongaイベント開催
(東京)
http://groonga.doorkeeper.jp/events/15816
Rubyを使った分散全文検索ミドルウェア
Powered by Rabbit 2.1.4