はじめに
FastCGIがどうして「Fast」なのか、名前だけでなんとなく理解していたものの、実際の動作原理は知りませんでした。
今回はCGIとFastCGIを比較しながらその違いを検証して、仕組みレベルで理解を深めてみたいと思います。
結論
主に以下の2つの理由です。
①一度起動したプロセスを再利用する(=起動オーバーヘッドがない)
② 管理された複数プロセスによって、効率的な並行処理が可能
この記事では、①に焦点を当てて掘り下げます。
②ついては、次の記事で詳しく解説します。
試してみる
CGIとFastCGIを比較できる環境を作って試してみます。
※検証ではwebサーバーにNginx、言語はGoを使います。
①FastCGIサーバー作成
package main
import (
"fmt"
"net"
"net/http"
"net/http/fcgi"
"os"
)
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello from FastCGI! PID: %d\n", os.Getpid())
}
func main() {
listener, err := net.Listen("tcp", ":9000")
if err != nil {
panic(fmt.Sprintf("Failed to listen on :9000: %v", err))
}
if err := fcgi.Serve(listener, http.HandlerFunc(handler)); err != nil {
panic(err)
}
}
Goには標準でFastCGIを扱うパッケージ(net/http/fcgi)が用意されているためそれを使います。
FastCGIサーバーを9000番ポートで起動して、プロセスIDを表示します。
②CGIサーバー作成
package main
import (
"fmt"
"os"
)
func main() {
fmt.Printf("Hello from CGI! PID: %d\n", os.Getpid())
}
CGIサーバーでも同じようにプロセスIDを表示させます。
③Nginx設定(CGI/FastCGIとのつなぎ)
server {
listen 8080;
# --- CGI ---
location /cgi/hello {
gzip off;
fastcgi_pass unix:/var/run/fcgiwrap.socket;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME /var/www/cgi-bin/hello.cgi;
}
# --- FastCGI ---
location /fastcgi/ {
include fastcgi_params;
fastcgi_pass fastcgi_backend:9000;
}
}
④動作確認
FastCGIとCGI経由でプログラムを動かす環境ができたので動作を確認してみます。
CGIで10回リクエスト
for i in $(seq 1 10); do curl http://localhost:8080/cgi/hello; done
FastCGIで10回リクエスト
for i in $(seq 1 10); do curl http://localhost:8080/fastcgi/hello; done
結果
# CGI
Hello from CGI! PID: 68
Hello from CGI! PID: 73
Hello from CGI! PID: 78
Hello from CGI! PID: 83
Hello from CGI! PID: 88
Hello from CGI! PID: 94
Hello from CGI! PID: 99
Hello from CGI! PID: 104
Hello from CGI! PID: 109
Hello from CGI! PID: 114
# FastCGI
Hello from FastCGI! PID: 1
Hello from FastCGI! PID: 1
Hello from FastCGI! PID: 1
Hello from FastCGI! PID: 1
Hello from FastCGI! PID: 1
Hello from FastCGI! PID: 1
Hello from FastCGI! PID: 1
Hello from FastCGI! PID: 1
Hello from FastCGI! PID: 1
Hello from FastCGI! PID: 1
CGIは毎回PIDが変わっていますが、FastCGIはPIDが変わっていませんでした。
プロセス起動オーバーヘッドを排除できる分「Fast」であるということがわかります。
まとめ
| 観点 | CGI | FastCGI |
|---|---|---|
| プロセス生成 | 毎回 | 1回だけ |
| パフォーマンス | 遅い | 高速 |
| スケーラビリティ | 低い | 高い |
さいごに
今回は「FastCGIがなぜ速いのか(=プロセス再利用)」という点にフォーカスして実際の動きを確かめました。
GoやNode.js、Pythonなどの最近のアプリ開発で主流な言語では アプリケーション自体がHTTPサーバーとして動作できるためwebサーバーをわざわざ構築しなくていいのもメリットの1つですね。