ミドルウェアとして Use するだけでパフォーマンスが向上するなんて夢の様な話はないと思っていたけど、HTTP Coala はそれをやってのけている様です。
goware/httpcoala · GitHub
Go http middleware handler for request coalescing
https://github.com/goware/httpcoala
ちょっと信じがたかったので、まずはベンチマークを取ってみた。
Coala 未使用
package main
import (
"net/http"
"github.com/zenazn/goji"
"github.com/zenazn/goji/web"
)
func main() {
goji.Get("/", func(c web.C, w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello World"))
})
goji.Serve()
}
$ ab -n 10 -n 10000 http://localhost:8000/
Server Software:
Server Hostname: localhost
Server Port: 8000
Document Path: /
Document Length: 11 bytes
Concurrency Level: 10
Time taken for tests: 4.185837 seconds
Complete requests: 10000
Failed requests: 0
Write errors: 0
Total transferred: 1280000 bytes
HTML transferred: 110000 bytes
Requests per second: 2389.01 [#/sec] (mean)
Time per request: 4.186 [ms] (mean)
Time per request: 0.419 [ms] (mean, across all concurrent requests)
Transfer rate: 298.63 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.1 0 7
Processing: 0 3 1.5 4 31
Waiting: 0 2 1.5 2 30
Total: 0 3 1.5 4 31
Percentage of the requests served within a certain time (ms)
50% 4
66% 4
75% 4
80% 4
90% 5
95% 6
98% 7
99% 8
100% 31 (longest request)
Coala 使用
package main
import (
"net/http"
"github.com/goware/httpcoala"
"github.com/zenazn/goji"
"github.com/zenazn/goji/web"
)
func main() {
goji.Get("/", func(c web.C, w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello World"))
})
goji.Use(httpcoala.Route("GET")) // ココ
goji.Serve()
}
Server Software:
Server Hostname: localhost
Server Port: 8000
Document Path: /
Document Length: 11 bytes
Concurrency Level: 10
Time taken for tests: 3.860772 seconds
Complete requests: 10000
Failed requests: 0
Write errors: 0
Total transferred: 1280000 bytes
HTML transferred: 110000 bytes
Requests per second: 2590.16 [#/sec] (mean)
Time per request: 3.861 [ms] (mean)
Time per request: 0.386 [ms] (mean, across all concurrent requests)
Transfer rate: 323.77 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.0 0 1
Processing: 0 3 2.2 3 74
Waiting: 0 2 2.3 2 71
Total: 0 3 2.2 3 74
Percentage of the requests served within a certain time (ms)
50% 3
66% 3
75% 4
80% 4
90% 4
95% 5
98% 5
99% 6
100% 74 (longest request)
確かに若干ですがパフォーマンスが良くなってる。README.md によるとスレッド数を上げると
Without httpcoala middleware, Requests/sec: 7081.09
With httpcoala middleware, Requests/sec: 18373.87
2倍以上の差が出る場合もある様です。何がそうさせるのだろうとコードを読んでみた。
httpcoala/httpcoala.go at master · goware/httpcoala · GitHub
https://github.com/goware/httpcoala/blob/master/httpcoala.go
複数のリクエストを channel を使って結合し、同じレスポンスを返すという仕組みで毎回 ResponseWriter の生成や切断時処理を行うのを回避してる。ハンドラ内が遅くなればなるほど効果が出ます。
httpcoala/httpcoala.go at master · goware/httpcoala · GitHub
https://github.com/goware/httpcoala/blob/master/httpcoala.go#L71-L78
今回の様に同じ URL に対して同じメソッドのリクエストが頻繁に起こる場合には非常に有効な手段だと分かる。キャッシュではない為、リアルタイム性も担保される。なかなかいい所に目を付けてるなーと思った。
効果には個人差がある様です。