はじめに
以下の記事で「FastCGIはプロセスを再利用するから速い」という点を記事に書きました。
今回は、FastCGIのもう一つの特徴である
「複数のプロセスを使って同時にリクエストを処理できる(=並行処理が可能)」
という点を実際にコードを書いて確かめてみたいと思います。
概要
Webサーバーがリクエストを受け取るたびに、
空いているFastCGIプロセスに処理を割り当てる仕組みです。
これにより、リクエストの同時処理(並行処理)を可能にしています。
試してみる
では実際にFastCGIが「複数プロセスで並行処理できる」ことを確認します。
そのために、疑似的に重い処理を含むFastCGIサーバーを複数プロセスで起動して、
同時リクエストを送るとどう動作するかを見てみます。
準備
①fastCGIサーバー
PIDを出力させます。
スリープ処理を挟んで処理完了まで3秒程度かかるようにしています。
package main
import (
"fmt"
"net"
"net/http"
"net/http/fcgi"
"os"
"time"
)
func handler(w http.ResponseWriter, r *http.Request) {
pid := os.Getpid()
// 並列で処理されているかを確認するため3秒スリープ
time.Sleep(3 * time.Second)
fmt.Fprintf(w, "Hello from FastCGI! PID: %d\n", pid)
}
func main() {
port := os.Args[1]
listener, _ := net.Listen("tcp", ":"+port)
fmt.Printf("Starting FastCGI server on :%s (PID: %d)\n", port, os.Getpid())
fcgi.Serve(listener, http.HandlerFunc(handler))
}
②作成した①のプロセスを3つ起動させておく
並行処理をさせるため、3つのFastCGIプロセスを起動させておきます。
PID USER TIME COMMAND
1 root 0:00 sh -c ./server 9001 & ./server 9002 & ./server 9003 & tail -f /dev/null
7 root 0:00 ./server 9001 ※これ
8 root 0:00 ./server 9002 ※これ
9 root 0:00 ./server 9003 ※これ
29 root 0:00 sh
35 root 0:00 ps aux
③ Nginx設定
それぞれ3つのプロセスに処理がいくようにNginxを設定する。
# FastCGIプロセス群をNginxのupstreamでまとめます。
upstream fastcgi_backend {
server 127.0.0.1:9001;
server 127.0.0.1:9002;
server 127.0.0.1:9003;
}
server {
listen 8080;
location /fastcgi/ {
include fastcgi_params;
fastcgi_pass fastcgi_backend;
}
}
確認
3つのFastCGIプロセスが同時に処理できるか確認します。
time ( \
curl -s http://localhost:8080/fastcgi/hello & \
curl -s http://localhost:8080/fastcgi/hello & \
curl -s http://localhost:8080/fastcgi/hello & \
wait \
)
結果
Hello from FastCGI! PID: 8
Hello from FastCGI! PID: 7
Hello from FastCGI! PID: 9
0.02s user 0.03s system 1% cpu 3.042 total
起動中のPID(8・7・9)をそれぞれ使用して、処理が3秒程度(3.042秒)で終了していることが確認できました。
直列で処理している場合は9秒以上かかっているはずなので、FastCGIがマルチプロセスで同時並行に処理していることが確認できました。
さいごに
CGIでも並行処理は可能ですが、リクエストのたびにプロセス起動するため、サーバーに負荷がかかり非効率です。
FastCGIでは事前に複数のプロセスを起動しておくことで、効率的な並行処理ができる仕組みになっています。