Upload
kubo39
View
982
Download
5
Embed Size (px)
Citation preview
Webサーバ・bossanを書いた話
@shitsyndrome /kubo39@github
bossan
話すこと
● bossan とはなにか● なんで作ったか● 基本構成● I/O戦略● セキュリティ● パフォーマンス
What's bossan?
● Ruby's rack web server● 高速● HTTP1.1サポート● Linux のみサポート
なんで作ったか
● Cの勉強● 就職活動の一環● 既存のrackサーバに不満
- パフォーマンス
- Eventmachineに依存しすぎ● ゴリゴリなにか書きたかった!
基本構成
● シングルプロセス、シングルスレッド● イベントドリブン(I/O多重化)● 機能は最小限に、パフォーマンス重視
I/O戦略
● readは全部読み込むまでread callback仕掛ける● writeはwritevを使用
- writevについては後述
- writeはまとめて書き出す
一般的なI/O特性
● read(2) / write(2)
fdが読み込み/書き込み完了するまで
他のfdをブロック
=> 「I/Oブロッキング」
ネットワーク x I/O
● ブロックすると、一人のレスポンス/リクエストが
終わるまで他は待たされる
=> 単位時間当たりの処理能力低下
● 一般的に1:NなサーバはマルチスレッドやIO多重化で実装
I/O多重化
● I/O可能になったfdを通知する仕組み
- 順番が入れ替わったりすることもある● 実装はいろいろ
select,poll,epoll(linux),kqueue(bsd),..
● Bossanはepollのみサポート
picoev
● イベントループを扱うためのライブラリ● 前述したepollを使いやすい形で提供
- 本来はkqueueやpollなどの下のレイヤーの差 異を隠蔽して使うためのもの
- 素のepoll扱うのはめんどい
Asynchronous I/O(おまけ)
● 非同期にI/Oを行う
fdのread/write自体が非同期● 通知時にはすでにread/writeは完了
- readの場合はバッファにデータが入ってる● 実装が複雑
- APIがクソ
- bossanでは使ってません
セキュリティ
● Max content length の設定
- クソでかいデータきたら困る
- 本体が16M越えたら413返す● 遅いリクエストはばっさりclose
- slowloris対策● Long Header DoS対策
- http-parserで対処
http-parser
● パース処理は重い → Cでかかれたもの使用● node.jsの作者のもの使用● コールバックスタイル
- バッファ切れる度に呼び出し● ヘッダを全部読み込む前にパース開始
- Long header DoS対策
パフォーマンス
● ほとんどCで実装
- Rubyは遅い
- いかにRubyのコード減らすか● 単純にCで書いてもそこまででない
- システムコール減らす : writev● ソケットオプション
- TCP_NODELAY, TCP_CORK● タイムキャッシュ
Rubyのコード減らす
● Rubyは遅い
- オブジェクトの生成コストが高い● 例:文字列
RubyのStringは生成の度にmemcpy()走る
- 可能な限りCの文字列使用
- staticな値で使いまわす
システムコール減らす
● システムコールは遅い
- OSのコンテキストスイッチが発生
- Linuxはマルチスレッドなので相互排他必要
● writev: 複数のバッファからの書き込みを同時に
- 自前でバッファ連結する手間省く
- カーネル内でatomicに連結
TCP_NODELAY / TCP_CORK
● TCPで小さいバッファで通信してると遅延が
起こりやすい● ソケットオプションで遅延させないようにできる
ー writevと併用することで効果を発揮● 参考URL
https://access.redhat.com/knowledge/docs/ja-JP/Red_Hat_Enterprise_MRG/2/html/Realtime_Reference_Guide/chap-Realtime_Reference_Guide-Sockets.html
タイムキャッシュ
● Dateヘッダ用に● HTTPの世界は秒オーダーでいい
- 時間を毎回引かない(gettimeofday発生)
- 1秒間はキャッシュした値を使いまわす● nginxのtime cacheを参考
ベンチマーク
● 条件(なるべく同一に)
Content-Type: text/plain
本文: “hello, world!”
ログ出力なし
apache bench : ab -c 25 -n 100000● nginxのみデフォルト設定
ベンチマーク
● 比較用サーバ
- thin : Ruby,シングルスレッド+イベントループ
- goliath : Ruby, シングルスレッド+イベントルー プ+軽量スレッド(fiber)
- nginx: C, prefork+イベントループ
- node.js : js, シングルスレッド+イベントループ
ベンチマーク
Bossan(0.1.3) 18453.22 [#/sec]
Thin(1.5.0) 9460.58 [#/sec]
Goliath(1.0.1) 940.56 [#/sec]
Nginx(1.1.19) 20297.02 [#/sec]
Node.js(0.8.15) 10013.64 [#/sec]
コード
● https://github.com/kubo39/bossan
なにかあれば