unoh.github.com

C/C++でFastCGIを作る

Thu Oct 18 06:30:45 -0700 2007

こんにちは satoです。



現在 Ruby on Rails で書かれた アプリケーションの 一部のURIを高速化するために、lighttpd + FastCGI で 書き直しています。FastCGI は あらかじめ プロセスを常駐させておき、リクエストが来た際に、常駐しているプロセスに Unix domain socket あるいは TCP/IP で通信を行い プロセス起動時のオーバーヘッドを無くすことにより、処理を高速化します。今回は lighttpd + FastCGI で Hello word を作る 解説します。



まず lighttpd と FastCGI を 用意します 環境はCentOS5です。



lighttpd:
yum install lighttpd
FastCGI:
wget http://www.fastcgi.com/dist/fcgi.tar.gz
tar xzvf fcgi-2.4.0.tar.gz
cd fcgi-2.4.0
make
sudo make install


lighttpd の設定ファイル ligttpd.conf を編集します


vi /etc/lighttpd/lighttpd.conf 
server.modules              = (
  "mod_access",
  "mod_fastcgi",
  ""mod_accesslog")
(中略)
fastcgi.server = (
    "/" => (
        ("socket" => "/dev/shm/test.fcgi.socket.1",
         "check-local" => "disable")
   )
)


簡単に説明しますと、mod_fastcgiモジュールを有効にして、 / に来たリクエストを /dev/shm/test.fcgi.socket.1 に送ります


fastcgi の test.cpp のソースは以下です。



#include "fcgi_config.h"
#include 
#ifdef HAVE_UNISTD_H
#include 
#endif
#ifdef _WIN32
#include 
#else
extern char **environ;
#endif
#include "fcgi_stdio.h"
int main () {
    int count = 0;
    while (FCGI_Accept() >= 0) {
        printf("Content-type: text/html\r\n"
            "\r\n"
            "FastCGI HelloWorld"
            "

FastCGI HelloWorld

\n" "Request number %d, Process ID: %d

\n", ++count, getpid()); } return 0; }



簡単に解説しますと FCGI_Accept() は システムコール の accept と似たような感じでリクエストが発生すると 待ち状態から ループに入ります。次にprintfですが これは #include "fcgi_stdio.h" の中で


#define printf FCGI_printf


となっていて 実際には FCGI_printfが 呼ばれます。 FCGI_printf は 最終的には システムコールの write を呼んで 通信などを行います(windowsでは send関数)。あとは content-type を出力して おしまいです。fcgi はそのまま終了しないで FCGI_Accept に戻り、リクエストがあるのを待ちます



g++ -o test.fcgi test.c -lfcgi 

として test.fcgi の バイナリができたら、lighttpd に付属している spawn-fcgi というツールで fcgiを立ち上げます



sudo spawn-fcgi -f ./test.fcgi -s /dev/shm/test.fcgi.socket.1 2>&1 > /dev/null


これでアクセスできるはずです。何度もアクセスすると プロセスは終了しないので、プロセスIDは変わっていないのに、count は増えているかと思います。mysqlのconnectや設定ファイルの読み出しは ループの外で行いましょう。


勉強会の時にも出た質問なんですが、Apache module で作らない理由は、Apache にしか使用できないということと、そのサーバを他用途で使用するときに mod_test が読まれていると 無駄に connectionを張ってしまったりするためです。