InfoQ

InfoQ

Articles

マイブックマーク

ブックマークするためにログイン または 会員登録 する

ブックマークされました!

ブックマークがエラーになりました。もう一度お願いします。

RubyのFiberを非同期I/Oに使うNeverBlockとRevactor

作者 Werner Schuster , 翻訳者 金森 諭 投稿日 2009年1月7日

セクション
運用/インフラ,
デベロップメント,
設計/アーキテクチャ
トピック
ランタイム ,
Ruby ,
プログラミング ,
データアクセス ,
Ruby on Rails ,
パフォーマンス&スケーラビリティ
タグ
Concurrency ,
MySQL ,
Ruby on Rails ,
Rails ,
Ruby1.9 ,
Rubinius ,
データベース

Fiber(参考記事・英語) は活用できる新しい並行性プリミティブ(もっとも基本的な要素)としてRubyプログラマの中で徐々に認識されだしています。その中で、ユーザ空間スレッドやRuby 1.9のGiant Interpreter Lock(GIL:Ruby言語のスレッドが1度に1つしか走らないようにする)の問題に対処するのに、Fiberとノンブロッキングあるいは非同期の I/Oを組み合わせた方法を採用する2つの試みがあります。

ブロッキングシステムコールの一番の問題は、ほぼI/Oに関することです。readのようなブロッキングシステムコールでは1度に1つのデータしか返りません。するとユーザ空間でスレッドを実行するシステムでは、ひとつのプロセス内の全てのスレッドがブロックされることになります。解決策はI/O要求をI /Oのブロッキングと切り離すことです。その一つの方法がブロッキングシステムコールが実行される前にI/O要求をキャッチして、このI/O要求をノンブロッキングな形で送り、要求元のFiberを一時停止させて別のFiberに実行権を与えるやり方です。そしてこのI/O要求に対しての応答をシステムが受けたら、元のFiberを再度スケジューリングすることになります。

Fiberはユーザに試練を課すことなくこの考えを実装する有益な並行性ツールとなります。今Fiberを使ったソリューションを実現するためのライブラリが2つあります。まさにこのためのソリューションとしてあるのがNeverBlockライブラリ(リンク)です(GithubにNeverBlock(リンク)、NeverBlock PG(リンク)、NeverBlock PG adapter for ActiveRecord(リンク)、非同期操作をサポートするMySQLアダプタのMySQLPlus(リンク)のレポジトリがあります)。より汎用的なソリューションとして、ErlangのActorや通信プロセスなどの考え方に基づいたTony Arcieri氏によるRevacotrライブラリがあります。私たちはNeverBlockプロジェクトのMohammad A. Ali氏(リンク)とRevactorライブラリのTony Arcier氏(リンク)に話を聞きました。

NeverBlock

InfoQ:NeverBlock がすることを正確に言うとどういうことになるでしょう?私が見る限り、Fiberに格納されたコードをコネクションプールに渡して、コネクションが利用可能になるとそれらFiberの実行を再開できるようにするのがNeverBlockのようです。NeverBlockの一番の利点はなんでしょうか?
 

Mohammad A. Ali:プーリングの機能はNeverBlock以外のところが適切に機能するために必要だったものです。全てのものを一つのところに集めることで、Rails、 Merb、Ramazeのようなアプリケーションがスレッドセーフのフルセットをもたなくても即座にI/O並行性を利用できるようになります。

これを実現するために、NeverBlockのFiberプールから取得したFiberで要求をラップするウェブサーバと、それらのFiberを認識して、中断や再開の要求に応じて扱うことのできるI/Oライブラリ(DB操作だけでなく全てのI/O操作をおこなう)が必要でした。そして EventMachineあるいはRevのようなイベントループ(イベントを監視する機構)を使ってそれら全てを調和させる必要がありました。


InfoQ: PG はNeverBlockとPostgreSQLドライバを使っていますが、PostgreSQLはすでにノンブロッキングI/Oを装備していますね。この場合NeverBlock PGはどのような役割をもっているのでしょうか?もしMySQLのようなノンブロッキングI/Oがなさそうなもの用のドライバを使うとしたら、 NeverBlockはどのような手助けとなるでしょうか?

Mohammad A. Ali:NeverBlock::PGはノンブロッキング操作を透過的におこなえるようにしますが、そのためにはそのFiberを次のようにNeverBlockのFiberプールで作る必要があります。

pool.spawn do
 res1 = db.exec(query1)
 res2 = db.exec(query2_that_depends_on_query1)
end 

ノンブロッキングを実装する大抵のものではこれよりずっと複雑なことをしないといけません。Fiberのおかげで一見ブロッキングがあるように見えるコードを書くだけでノンブロッキングを実現することができます。

今わたしたちはNeverBlock::PGドライバをさらに先へ進めようとしているところです。ちょうど新しいActiveRecord- NeverBlock-Postgresql用アダプタをリリースしたところで、これによってActiveRecordにノンブロッキングI/Oがもたらされます。この次にNeverBlockがターゲットにするものが何かは簡単に推測できると思います。

NeverBlockの特徴的な点は、他のプログラムに適用してもほとんど違いが分からないだろうということです。

NeverBlock はブロッキングをおこなうプログラムをノンブロッキングにすることはできません。NeverBlockがおこなうのは、ブロッキングするように見えるコードでも、ノンブロッキングの特性を損なうことなしに、ノンブロッキングをおこなうプログラムを書けるようにすることです。ですから、将来に向けて Asymy(非同期型のMySQLドライバ)のような取り組みについても大変注目しています。

編集部注:このインタビューの後に非同期型のMySQLドライバの最初の試みとしてMySQLPlus(first attempt at an asynchronous MySQL driver, MySQLPlus)が公開されました。



InfoQ: このライブラリで必要なFiberはRuby 1.9でしか使えません。このことが(Ruby 1.9はまだ多くの変更がおこなわれていて、まだそれほど多くの採用はされてないと考える)ユーザにとって問題となるという考えはありますか?このライブラリあるいは一般的にはFiberの利点がRuby 1.9を採用するきっかけとなるとお考えでしょうか?

Mohammad A. Ali :私はRuby 1.9で生まれた最良のもののひとつがFiberだと考えています。同じ機能はRuby 1.8でもcontinuation(継続)を使って可能ですが、パフォーマンスが悪いという面があります。ともあれ安定版の1.9がリリースされようとしていますし、私は全員が1.9に移行すべきだと強く思っています。NeverBlockやRevactor、その他類するものによる利点が、人々の移行を決心させるくらいのものであってほしいと願っています。


InfoQ:  NeverBlockのソースコードについてですが、NeverBlockではFiberクラスを拡張していくつかのメソッドを追加していますね。これはなぜですか?

Mohammad A. Ali :Fiber によって複数のスレッドを使う場合、Fiber内のローカル変数を保持しておくことに関してFiberはあまり融通が効きません。トランザクションを実行しているActiveRecordを切り替えるためにはこのような機能が必要でしたし、そのことがFiberに分かるようにする必要もありました。また Fiberでの処理でもノンブロッキング処理をするかしないかを選択できるようにするのにも必要なことでした。


InfoQ: Revactorについて耳にしたことはありますか?

Mohammad A. Ali :ええ、私はRevactorに少し関わったことがあります。それにNeverBlockではEventMachineだけでなくRevを第2のバックエンドとして(まだ実験段階で)実際に使っています。しかしNeverBlockの目標はRevactorとは異なっています。RevactorはRubyに新しい並行モデルをもたらすものですが、NeverBlockは現行のRubyプログラムに最低限の変更を加えるだけで並行性をもたせるためのものです。


編集部注:非同期のMySQLドライバーであるMySQLPlusの初期バージョン(リンク)はこのインタビューの後にリリースされました。

 

Revactor

InfoQ: Revactorの現状はどうなっているでしょう?

Tony Arcieri: 他の無数にあるプロジェクトと比べると少し注目度は低いですが、それでもちゃんと商用利用されているほどになっています。


InfoQ:  Revactorの将来のバージョンでは何が予定されているのですか?

Tony Arcieri: 最近Aman Gupta氏がRuby 1.8向けに「哀れな人たち用Fiber」実装をリリースしました。同じようにRevactorをRuby 1.8にポートすることも可能かもしれませんが、パフォーマンスで苦しむことになりそうです。

今のところRevactorではすべてのActorが同一のRubyスレッドにあることを前提にしています。ほぼ全体において異なるスレッドにある Actorのメッセージ送信は可能になっていますが、まだそれは完全でなく有効になっていません。私はこの機構がサポートされることに関心のある人たちと話をしてきているのですが、早いうちにその成果がRevactorに取り入れられることを願っています。


InfoQ: ユーザはRevactorのActorを直接使ってプログラムする必要があるのでしょうか。それともRevactorのActorを他のライブラリのバックエンドで使える、つまり(ディベロッパが)透過的にRevactorのActorを使えるようになっているのでしょうか?
 

Tony Arcieri:  Revactor はRubinius(Smalltalk風のバイトコードによるRuby実装)でのActor実装と互換性がありますが、現段階ではRubiniusの Actorを使ってErlangのgen_tcpほど簡単にネットワークプログラミングができるような状況ではありません。とはいえ、Actorを使ったネットワークアプリケーションを書いているプログラマの目がRevactorに集まり始めたところですし、いずれその人たちのアプリケーションを Rubiniusに持ってくることもできるようになるでしょう。


InfoQ: ブロッキングをおこなうI/O要求のスケジューリングはどのようにおこなわれているのでしょう?I/O要求を実行するのにカーネルスレッドをいくつか使っているのでしょうか?
 

Tony Arcieri:Actor から送信された全てのメッセージの処理が終わっていて、かつメッセージを送ったActor以外にActorが実行可能になっていないなら、 Revactorは私が書いたRevという(EventMachineに似た)ライブラリを使ってI/Oイベントを管理します。RevはRuby 1.9のrb_thread_blocking_region()を使って、I/Oの利用可能状態を知るためにブロッキングシステムコールを監視するので、別のカーネルスレッドを作る必要はありません。RevactorにはRubyのTCPSocketクラスをダックタイプするクラス(Revactor::TCP)があり、これによってブロッキングシステムコールがされた時にそれをActorスケジューラに送って保留するようにしています。Rubyのソケットを使っている既存ライブラリがRevactor::TCPを使うようにするモンキーパッチ(元のコードを変更するのでなく実行時に変更するパッチ)を作るのは簡単でした。その一例をあげると、RevactorはMongrel(Webサーバ)に小さなモンキーパッチをあてて並行処理にThreadでなくActorを使うようにしています。


InfoQ: I/O要求を連続して出すコードにはどのように対処しているのでしょう?リクエストをひとつにまとめるのでしょうか?

Tony Arcieri: 表面的にはそのような要求で「ブロッキング」が起きているように見えます。I/O要求が出された時に、実行中のActorは中断されI/O処理が完了した後に再開するようスケジュールしなおされます。これによりブロッキングが不可欠なインターフェースに依存しているライブラリでもRevactor上で効率的に動かすことができます。逆に現状Revactorで動かすことのできないものとしてはActiveRecordやDataMapperがあります。


InfoQ: RubiniusのActorについてはどうでしょう?

Tony Arcieri: Rubinius のActorもTCPSocketの「アクティブモード」を使えばRevactorができることは全てできます。これはあるTCPSocketからの入力を必ず読み取るのではなく、標準の内部Actorメッセージングを使って、非同期で決められたActorに入力データが渡されるということです。これによりActorでI/Oと内部Actorメッセージを並行して処理できます。RubiniusのVMは今C++で書き直されているとこで、これが終わった時に「アクティブモード」メッセージ配信を実装するのに必要な全ての機能が揃うことを期待しています。それらが整えばRubiniusのActorの改良をおこないたいと考えています。


InfoQ:  RubiniusでRevactorをサポートするようにする計画はありますか?

Tony Arcieri: いいえ、RevactorはかなりYARVの機能に依存しています。RubiniusはTaskおよびChannel方式による優れた並行処理モデルと I/Oサポートを備え、既存のActor実装でもこの両方有効利用することができます。RevactorとRubiniusのActorはお互いをかなりダックタイプしているので、双互換性のあるプログラムを書くのもさほど頭を悩ますことではないはずです。


InfoQ: ActorやRevectorを(Ruby 1.9でなく)Rubiniusで動かすメリットはなんでしょう?

Tony Arcieri: 差しあたりRuby 1.9の方が一般的にパフォーマンスがよく既存のライブラリとも相性がいいです。Rubiniusは発展途中で目下書き直しをおこなっているところです。将来的にはRuby 1.9以上に多くのメリットを持つようになるでしょう。並行処理やI/OのTask/Channel抽象化がRuby 1.9にあるものよりずっと洗練されているからです。Rubyは1.8でも1.9でもEventMachineやRevのようなイベントフレームワークと Ruby標準のI/Oが当分並行して使われるでしょうが、Rubiniusでは最初から高度なI/Oを備えています。


InfoQ: Revactorを使っているプロジェクトをなにかご存知ですか?

Tony Arcieri: 内部のプロジェクトで使っている多方面の人たちと話すことがあるのですが、ほとんどは並列HTTPクライアントとして使っています。公開されているプロジェクトでRevactorを使っていると聞いたことはありません。


InfoQ:Ryby 1.9あるいはFiberを使ったライブラリに依存していることがRevactorの採用の妨げにならないでしょうか?

Tony Arcieri: それはあると思います。Ruby 1.9に関連したバグは相応にありましたし、ほとんどの人がRevactorを使ってみることにはかなり慎重だと思います。しかし、これまでも多くのプロジェクトが後になって急に現れるということがありました。そういうプロジェクトではFiberを使ったイベントフレームワークと組み合わせていて、たとえばRy Dahl氏のFlowウェブサーバなどがそうです。

 

原文はこちらです:http://www.infoq.com/articles/fibers-neverblock-revactor
(このArticleは2008年8月28日に原文が掲載されました)

特集コンテンツ一覧

GAE開発の落とし穴

Googleのクラウド環境をつかったGoogle App Engineによる開発するにあたり、初めての試みで苦悩する開発者達の経験をもとに、各開発フェーズにあわせて問題点やどう解決したかをご紹介します

イベントレポート:「Coqチュートリアル#1」

去る1月12日、定理証明支援系ツールCoqの初心者向けチュートリアルが開催さ れた(http://kokucheese.com/event/index/23667/)。今後も2月2日 (http://kokucheese.com/event/index/23744/)、2月9日、2月16日と引き続き開 催されていく予定である。本記事では、開催の様子をレポートする。

Javaの未来についてのNeal Gafter氏とのディスカッション

Choosing Options

Neal Gafter氏はOracleによるJava買収の影響に関する議論、Javaにセグメンテッドスタックやメタオブジェクトプロトコルを追加することについての主張、そしてJavaとC#との比較について話をしてくれた。

Google Dartのエッセンス:アプリケーションの構築、スナップショット、Isolate

GoogleはVMをともなう新しい言語であり、JSコンパイラでもあるDartをプレビューした。 InfoQはDartのアプリの構築に貢献する文法の裏側を探った:スナップショット、Isolate、モジュール方式

CSPベースのモデル検査ツール「Process Analysis Toolkit」

本記事ではCSPベースの「マルチドメイン・モデル検査ツール」である、PAT(Process Analysis Toolkit)について紹介する。モデル検査は、形式手法(Formal Method)という方法論を基礎とする技術であり、複雑さが増大しながらも安全性を求められる、現在のソフトウェア開発の状況に対する処方箋の1つとして注目されている手法である。

Jenkinsによる継続的インテグレーションのススメ(4) ~CloudBeesでJenkinsをサービスとして使う~

前回まで、Jenkinsの幾つかの側面に注目して解説をしてきました。シリーズ最後の今回は、Jenkinsをサービスとして使う方法を紹介します。

書籍『抽象によるソフトウェア設計-Alloyではじめる形式手法-』の紹介

Alloyは、MITにて開発された仕様記述言語であり、ツールによる自動解析を使い、インクリメンタルに形式仕様が書けることが特長である。筆者らはAlloy開発者による、Alloyを使った形式手法入門書を翻訳、今夏にオーム社より刊行した。本記事では、Alloyの簡単な概要と、翻訳書『抽象によるソフトウェア設計』(「Alloy本」)を紹介する。

Windows デバイスで開発するタッチユーザーインターフェイス

スマートフォンを中心としたマルチデバイスにおけるタッチユーザーインターフェイスへの対応は、既に必須の項目となりつつある。本記事では、Windows デバイスにおける UX のベースとなっている「メトロ」というデザイン言語を掘り下げながら、既存環境を意識しつつもどのようにタッチユーザーインターフェイス開発に取り組んでいくべきであるかについて解説していく。