epoll | RubyGems.org | your community gem host
epollはnginxやnode(libuv)などでも使われている、大量のファイルディスクリプタを効率よく監視するためのAPIのことです。
イベントドリブンI/O
epoll APIはLinuxでのみ(たぶん)動作し、Mac等のBSDでは似たAPIとしてkqueueがあります。
例えばepollを軸にサーバーを作るなら、serverが作った各クライアント間とのI/Oをできるだけ待ちをなくして読み書きできるときに実行する事が可能です。並行で低リソースに処理できるので、大量のリクエストを同時に処理することが期待されます。
epollではレベルトリガ通知(今なら大丈夫通知!)、エッジトリガ通知(前から変わったよ通知!)のどちらにも対応し、いわゆるイベントドリブンI/Oを実現します。
Rubyでのepollを使っているgemといえば、eventmachineやfluentdで有名なcool.ioなどがあります。
今回はローレベルAPIだけを持つ小さなライブラリとしてのAPIを作りました。 CでがんばるよりRubyでがんばりたい方にオススメです。
検証
簡単なサーバーを作ってab($ ab -k -n 10000 -c 1000 http://127.0.0.1:4000/
)で性能を測ってみました。
webrick
性能比較用に誰でも使えるwebrickから。
webrickは内部的にはselectで待ってthreadを立てる方式のようです。
require 'webrick' srv = WEBrick::HTTPServer.new(DocumentRoot: './', BindAddress: '127.0.0.1', Port: 4000) srv.start
Requests per second: 5132.49 [#/sec] (mean)
epoll
エッジトリガ通知で各I/Oに指定した通知が来たら処理という風に書くことができます。 APIがローレベルなのでコードが長くなりがち。
require 'epoll' ep = Epoll.create ep.add server, Epoll::IN loop do ep.wait.each do |ev| data = ev.data events = ev.events if data == server socket = server.accept ep.add socket, Epoll::IN|Epoll::ET elsif (events & Epoll::IN) != 0 data.recv(1024) ep.mod data, Epoll::OUT|Epoll::ET elsif (events & Epoll::OUT) != 0 data.puts response ep.del data data.close else raise IOError end end end
Requests per second: 5601.02 [#/sec] (mean)
まとめ
Webrickは素晴らしく汎用的で大量の機能を持ち、正しくRequestをパースしてResponseを組み立てて……としているので一概には言えませんが、epollのserverもまあ速いとは言いがたい感じなので、ラッパーを書くなりするとよいのかもしれません。
あとLinuxプログラミングインターフェースが参考図書として最高です。
- 作者: Michael Kerrisk,千住治郎
- 出版社/メーカー: オライリージャパン
- 発売日: 2012/12/01
- メディア: 大型本
- クリック: 14回
- この商品を含むブログ (5件) を見る
io-epollでは、GVL対応もしたのでtimeout{}
で囲ったりもできます。
しかし、まだまだ実験的な実装段階なので、「使ってるよ!」とかでよいので @_ksss_で皆様の声・アイデアをお待ちしております。
see also
- Linux Programming、epollの話 - mixi Engineers' Blog
- I/Oを多重化するためのシステムコール(select, poll, epoll, kqueue) - $shibayu36->blog;
- Community Blog
- Kazuho@Cybozu Labs: 「サーバ書くなら epoll 使うべき」は、今でも正しいのか
- 人間とウェブの未来 - 非同期I/OやノンブロッキングI/O及びI/Oの多重化について
- Ruby - 最速F5アタック研究会 - Qiita
TODO
ffiってなんだ。