Apacheモジュールの作り方(2.x系)

総閲覧回数:4,014,087回 / ブログ拍手:2,609
作品DB等各サービスの機能追加情報や、技術系・面白系記事を中心に提供。
記事の投稿は基本Twitterでも告知させて頂いています。
連絡は作品DBの論客の方なら私書、DB外ユーザの方ならメールTwitterで可能です。
アクセス記録[推移 / PV内訳(過去1日 / 過去1週間) / 外部アクセス元 (昨日 / 過去1週間) / ログイン論客足跡]
プロフィール私書(メール)
   /   /送済
評価(一覧   /)
投票   /共:   /
ファン登録
作品/情報/
DB構築()
ブログ
[書く]
攻略記事リンク集
My Play List
<=次の記事 文字::libiconvのバージョンとC++での使い方
=>前の記事 PlayStation 3::HDMI接続の威力&インターネットクライアントとして

1.
2010/02/13 同日2番目 C言語 / C++ > Apache Module > Apacheモジュールの作り方(2.x系)」
[この書込みのみ表示(記事URL紹介用) / 編集 / 削除 / トラバ送信 / 共有分類に追加(タグ付け)]拍手:4個

1. Apacheモジュールの作り方
    1. Apacheモジュール手始め
        1. rootで下準備
        2. ひな形作成
        3. とりあえず動かす
    2. リダイレクトするapacheモジュールを作ってみる
        1. リクエストパラメーター処理用ライブラリlibapreqをインストール
        2. ひな形作成
        3. ソースコード
        4. redirモジュールをインストール
        5. 動かす
        6. パフォーマンスを比較
    3. 開発にあたって多分参考になるところ

1. Apacheモジュールの作り方

今更ながらApacheモジュールに手を出してみようと思ったので、C言語でApacheモジュールの作り方手始め(Apache2.x系向け)メモしておこうと思います。
Apacheモジュールの作り方に関する本は少しだけ出ていますが、全部1.3系が基本なので、Apache2.2系を使っている自分としてはあまり使えない...、と放置していたけど、実用途でちょっと簡単なの作ってみようと思ったのでやってみました。
以下、Cent OSの最新版付属のhttpdを使った場合で書いてみます。
あんまりネット上にも情報が無かったので手探りで。
基本的にapacheモジュールを使う理由は速度や負荷軽減の為、というのが主目的になると思います。
    1. Apacheモジュール手始め


      1. rootで下準備

rootで
yum install httpd-devel
をインストール。
apacheモジュール開発に必要なコマンドがインストールされます。
      2. ひな形作成

まずhello worldを作ってみましょう。
/usr/sbin/apxs -g -n hellow_world

そうすると
mod_hello_world.c
というものが出来るので中身を眺めてみましょう。

#include "httpd.h"
#include "http_config.h"
#include "http_protocol.h"
#include "ap_config.h"

/* The sample content handler */
static int hello_world_handler(request_rec *r)
{
    if (strcmp(r->handler, "hello_world")) {
        return DECLINED;
    }
    r->content_type = "text/html";      

    if (!r->header_only)
        ap_rputs("The sample page from mod_hello_world.c\n", r);
    return OK;
}

static void hello_world_register_hooks(apr_pool_t *p)
{
    ap_hook_handler(hello_world_handler, NULL, NULL, APR_HOOK_MIDDLE);
}

/* Dispatch list for API hooks */
module AP_MODULE_DECLARE_DATA hello_world_module = {
    STANDARD20_MODULE_STUFF, 
    NULL,                  /* create per-dir    config structures */
    NULL,                  /* merge  per-dir    config structures */
    NULL,                  /* create per-server config structures */
    NULL,                  /* merge  per-server config structures */
    NULL,                  /* table of config file commands       */
    hello_world_register_hooks  /* register hooks                      */
};

      3. とりあえず動かす

/usr/sbin/apxs -c -i mod_hello_world.c
でインストールし(モジュールのディレクトリに権限があるのなら/無ければrootで)、
vi /etc/httpd/conf/httpd.conf

LoadModule hello_world_module modules/mod_hello_world.so
<Location /hello_world>
SetHandler hello_world
</Location>
を追加。
apachectl restart
し、
http://サーバー名/hello_wolrd
にアクセスすると、最初のひな形
The sample page from mod_hello_world.c
が表示される。

_handelerの所の処理が実行される事が分りました。
ここまではプログラミングすら必要なく動かせるので、これだけで動くんだと理解する為の最初の勉強としては中々ナイス。
    2. リダイレクトするapacheモジュールを作ってみる

外部へのリンクの流れを把握するには、リダイレクト用のページを用意するというのがあります。
後でapacheのaccess_logを解析して、外部への流れを把握するのに使えます。
特に頻繁に機能を追加するようなものでもないので、apacheでモジュールを作るには適している分野の一つです(更新がほとんどないプログラム)。
これを作ってみます。
要件としては、
url=...
としてパラメタ-を受け取る事と、リダイレクトのHTTPヘッダーを返す機能が必要になります。
      1. リクエストパラメーター処理用ライブラリlibapreqをインストール

http://www.apache.org/dist/httpd/libapreq/
からapache2系のlibapreq最新版をダウンロードしてインストールします。
# rootになってインストールします
su - 

32bit環境
VERSION=2-2.13
wget http://www.apache.org/dist/httpd/libapreq/libapreq$VERSION.tar.gz
tar xvfz  libapreq$VERSION.tar.gz
cd libapreq$VERSION;
./configure --with-apache-include=/usr/include/httpd
make;
make install;

64bit環境
VERSION=2-2.13
wget http://www.apache.org/dist/httpd/libapreq/libapreq$VERSION.tar.gz
tar xvfz  libapreq$VERSION.tar.gz
cd libapreq$VERSION;
./configure --with-apache-include=/usr/local/apache2/include;
make;
make install;
64bit環境だとconfigureで生成されるlibtoolが駄目だと気付くのに時間が掛かった。
消去して/usr/bin/libtool を使うようにシンボリックリンクを張っている。
一体何の為に独自のlibtoolを生成しているんだ?
とにかく64bit環境だとバグるので消す。

そして
vi /etc/httpd/conf/httpd.conf

LoadModule apreq_module modules/mod_apreq2.so
を追加
      2. ひな形作成

短いネーミングで作ってみる。
apxs -g -n redir
      3. ソースコード

#include "httpd.h"
#include "http_config.h"
#include "http_protocol.h"
#include "ap_config.h"

#include "apreq2/apreq_module_apache2.h"

/* The sample content handler */
static int redir_handler(request_rec *r)
{
  apreq_handle_t *req;
  const apreq_param_t *url;
  if (strcmp(r->handler, "redir")) {
    return DECLINED;
  }
  req = apreq_handle_apache2(r);
  
  url = apreq_param(req, "url");
  if (!url)
    return DECLINED;
  
  apr_table_set(r->headers_out, "Location", url->v.data);
  return 301;
}

static void redir_register_hooks(apr_pool_t *p)
{
    ap_hook_handler(redir_handler, NULL, NULL, APR_HOOK_MIDDLE);
}

/* Dispatch list for API hooks */
module AP_MODULE_DECLARE_DATA redir_module = {
    STANDARD20_MODULE_STUFF, 
    NULL,                  /* create per-dir    config structures */
    NULL,                  /* merge  per-dir    config structures */
    NULL,                  /* create per-server config structures */
    NULL,                  /* merge  per-server config structures */
    NULL,                  /* table of config file commands       */
    redir_register_hooks  /* register hooks                      */
};

      4. redirモジュールをインストール

localの方に入れているのなら
apxs -I /usr/local/apr/include/apreq2/ -c -i mod_redir.c

デフォルトのところに入れているのなら
apxs -I /usr/include/apreq2/ -c -i mod_redir.c

vi /etc/httpd/conf/httpd.conf
LoadModule redir_module modules/mod_redir.so
<Location /redir>
SetHandler redir
</Location>

apachectl restart
      5. 動かす

http://サーバー名/redir?url=http://www.yahoo.co.jp/
きちんとリダイレクトされ、access_logに記録されている事を確認。
現在実運用に使っています。
      6. パフォーマンスを比較

簡単にですが、mod_perlプログラム
#!/usr/bin/perl -w
package redir;
use strict;
use CGI::Accessup;

my $pro=new redir;
$pro->run();
sub new(){
        my $self={};
        return bless $self;
}

sub run(){
  my $self=shift;
  $self->init_vars();
  $self->{'c'}->redirect($self->{'url'});
}

sub init_vars(){
  my $self=shift;
  $self->{'c'}=new CGI::Accessup;
  $self->{'url'}=$self->{'c'}->param('url') || $self->{'c'}->show_error("url parameter is missing");
}
とパフォーマンスを比較

# 10個同時接続で10000リクエスト実行
ab -n 10000 -c 10 -w "http://開発マシン/redir?url=http://www.yahoo.co.jp/" > c.html
ab -n 10000 -c 10 -w "http://開発マシン/redir.asp?url=http://www.yahoo.co.jp/" > perl.html

比較してみると、手元のPCでやっているのでとりわけmod_perl版にはバラツキが毎回ありましたが、5回程それぞれ実行してみたところ、
 C言語apacheモジュールmod_perl
1秒間のリクエスト回数2536, 2544, 2577, 2615, 2709142, 364, 620, 843, 857
となりました。
C言語によるapacheモジュールの方がかなり高速に動いているのと、また、それもありますが、負荷が高くマシンスペックが低い環境でも、かなり安定した時間での実行が期待出来る事が分ります。
mod_perlでは時間が掛かりすぎてタイムアウトで実行され切らない時もありました。

↓で紹介する本でだと時間を整形するプログラムの実行結果の差として
 C言語apacheモジュールmod_perlJava Servlet(Tomcat)PHPCGI(C)CGI(Perl)
1秒間のリクエスト回数3111081051024912
という例が処理速度の差として紹介されています。
    3. 開発にあたって多分参考になるところ

ぱっと見2.x系の情報があまりあるようには見えませんが、
http://modules.apache.org/reference.php
が公式推奨の文章。

後は実際のモジュールのソースコードを見つつ勉強が王道かなぁ。
とりあえず手始めモジュールを作って、後はやりたい事をやっているモジュールのソースを眺めていくのが一番手軽かなと。
文章は見た限り、apache2.x系はあんまり整備されてなさそう。

1.3系の文章はオライリーとかからも出ているんですけどね。
 
といっても、Cとperlの解説があるといっても、perlの比率が多いので、C言語で書くにはかなり微妙...といった内容ですが。
速度を目的にApacheモジュールで書くのなら、perlじゃなくてCで書きたいですからね。

1.3系の情報から2.x系だったらどのようにやるのかを調べるというのが、本とか使った場合の調べ方になるかな。

今でも手に入るのはオライリーの本だけですが、自分が参考にしたのは
Apacheモジュール プログラミングガイド


読者が少ない分野な為絶版になり、新品で元々2800円程だったものが今見たら中古価格で1万円以上になっています。
こちらも1.3系向けに書かれていますが、ほんの少し(13ページ)だけ2.x系の書き方についての章があります。
「ノウハウが蓄積され、安定稼働しているApache1.3系が今後も現場では使われるだろう」という想定でそうなっているようですが、そんな事はなかったですし、結局つい先ほどApache1.3は先月完全にライフサイクルも終了しちゃいましたしね(Final Releaseのアナウンス)。
更新が続くソフトウェアについての本を書いたり、とりわけその過渡期に本を書くというのはどっちに合わせるのかという点で大変なのでしょうが、ちょっと残念な時期に出された内容になっちゃっています。
それでも希少なC言語のApacheモジュール本なので、情報は役に立つと思いますが。

コメントする4個


[他の記事も読む]
<=次の記事 文字::libiconvのバージョンとC++での使い方
=>前の記事 PlayStation 3::HDMI接続の威力&インターネットクライアントとして


大分類が「C言語 / C++」の記事
この論客の記事全て
↑上へ