😀
Go言語のnet/httpでWebサーバを作る時に心配したこと
概要
二つの心配事
・Webサーバが複数リクエストを捌けるか
・ハンドラーに依存性注入しているクラスのインスタンスが毎回作られるか
Webサーバを建てる
以下のコードを実行する
package main
import (
"fmt"
"net/http"
)
type hoge struct {
count int
}
func NewHoge() hoge {
return hoge{count: 0}
}
func (h hoge) ServeHTTP(w http.ResponseWriter, r *http.Request) {
h.count++
fmt.Printf("hoge %dth\n", h.count)
}
func main() {
http.Handle("/hoge", NewHoge())
http.ListenAndServe(":8080", nil)
}
/hogeでリクエストが来たらハンドラの処理が走る
リクエストが来た時に、ハンドラがどのように生成されるかを把握するために
ハンドラにはcount変数を持たせて、ServeHTTPが呼ばれるたびに+1している
一つ目の心配: 複数リクエストを捌けるか
まず結論: net/httpを使うとリクエストごとにハンドラが生成されて捌かれる
apachebenchを使って調べる
以下のコマンドでは50リクエストをサーバに一斉に投げる
ab -n 50 -c 50 localhost:8080/hoge
その結果は
hoge 1th
という標準出力が50行羅列される
これはハンドラのcount変数を出力したものだが
1thから50thではない事から
リクエストの度にハンドラが生成されている事が分かった
どうやらリクエストの度にgoroutineが起動しているようで
その中でハンドラが毎回生成されているからだと考えられる
ハンドラに依存性注入する
モックを使えるようにするために、ハンドラにロジッククラスを注入したい
package main
import (
"fmt"
"net/http"
)
type logic struct {
count int
}
func NewLogic() logic {
return logic{
count: 0,
}
}
func (l logic) increment() {
l.count++
fmt.Printf("logic %dth\n", l.count)
}
type hoge struct {
l logic
}
func NewHoge(l logic) hoge {
return hoge{
l,
}
}
func (h hoge) ServeHTTP(w http.ResponseWriter, r *http.Request) {
h.l.increment()
}
func main() {
logic := NewLogic()
http.Handle("/hoge", NewHoge(logic))
http.ListenAndServe(":8080", nil)
}
上のコードでは注入したlogicというクラスをカウントしている
2つ目の心配事: 注入したインスタンスが毎回作られるか
まず結論: ハンドラがリクエストごとに作られるので、注入したやつも毎回作られる
以下のコマンドでは50リクエストをサーバに一斉に投げる
ab -n 50 -c 50 localhost:8080/hoge
その結果は
logic 1th
という標準出力が50行羅列される
ちゃんと注入したインスタンスも毎回作られるので
処理時間のかかるlogic部分でも、待ち時間が発生することは無さそう
Discussion