bossan dentoo

Post on 28-May-2015

982 Views

Category:

Documents

5 Downloads

Preview:

Click to see full reader

TRANSCRIPT

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

なにかあれば

top related