apacheへのrequestで消費するリソース量をloggingするモジュール

■ mod_resource_checker  [Download](apcheリソースloggingモジュール)

サーバー内で複数のWEBサービスを提供したい場合に、chroot環境でのIPベースと、Virtualhostを用いたnameベースがある。

IPの枯渇や、ハードウェアにあまりお金をかけない、プロセス数の問題などで、最近ではnameベースを用いてサービスを提供することが多い。

ただし、nameベースでは様々な問題が起きる。

例えば、

  • VirtualHost毎にログを残す場合、VirtualHostの数が増えてくると、fdの数が足りなくなる
  • セキュリティ的にsuEXEC環境をとらないといけなくなる
  • DSO版phpにも対応できるようにmod_ruidを使わないといけない
  • mod_ruidを使うとCAPABILITYの問題で、request毎にプロセスを破棄しないといけなくてパフォーマンスが落ちる

など・・・

続きを読む

mod_limitipconnの制限内容の落とし穴

かなり有名なmod_limitipconnですが、色々制限方法の記事をみていると、きっちりとその性能を説明できていないものが多い気がする。

あるディレクトリ以下又はファイルに対する同一IPからの同時接続数を制限するというのが、このモジュールの役目なんだが、大事なところが説明されていない。

例えば、よくある以下のような制限を行ったとする。

<Location /hoge>
    MaxConnPerIP 3
</Location>

多くの情報ではこの設定だと、

[warning]

http://example.jp/hoge/index.cgi等、hoge/以下へのアクセスに対して、同一IPからの同時接続数を3に制限する。

[/warning]

とかかれていることが多い。

しかし、ここには大きな落とし穴がある。

続きを読む

apache2系のmodule開発

1.3系については、通称パンダ本に結構書いてあるので、情報量が少なめの2系モジュールに関する開発について。

基本は、1.3系と違い、2系はhook関数というものを作ってそれをモジュールから登録し、apacheコアにhookさせて、登録した関数を実行させるという流れ。

モジュールというのは、結局のところ「apacheコアが呼び出すhook関数を登録するためにある」といってもいいくらいかな。

流れとしては、以下のようにhook関数を登録して、

static void register_hooks(apr_pool_t *p)
{
    ap_hook_access_checker(lalimit_access_checker, NULL, NULL, APR_HOOK_MIDDLE);
}

続きを読む

apr_psprintfはかなり楽(apache2.x系)

apacheモジュールのメンテとかをしているんだが、メモリ管理系のapahceAPIはかなり楽だ。

本来なら、変数のサイズを常に気にしてcallocしたりfreeしたりする必要があるんだが、apacheAPIを使ってリソースpoolに管理を任せたら、その辺を全く気にしなくて良い。

sprintfするのも一苦労だけど、ここでもメモリ系を考えなくて良いAPIのapr_psprintfなどがあって、sprintfの第一引数は本来メモリを割り当てておく必要があるが、その必要も無い。

例えばこんなの。↓

if (x != NULL)
    buf_len += strlen(x);
else
    buf_len += NULL_LENGTH;
if (y != NULL)
    buf_len += strlen(y);
else
    buf_len += NULL_LENGTH;
buf = calloc(buf_len + 1, sizeof(char));
if  (buf == NULL)
    return "allocate error";
sprintf(buf, "x=%s y=%s", x, y)

free(buf);

この例だとbufには元々char方のxとかyだけを使っているが、ここにアドレスとかintを使うと、桁数計算とかでcharとしてのサイズがどれだけになるかとかが非常に面倒。

しかし、APIだと上のより面倒になりそうな実装がこんな風にかけちゃう。↓

buf = (char *)apr_psprintf(apr_pool_t *p,"x=%s y=%s z=%d adr=%x", x, y, z, adr);

こんな風に、整形した文字列に必要なサイズを自動で判断しリソースプールで確保してくれる。

こんなに楽だと、C書いてることを忘れそうだ・・・

NTPD上の示す時間とLocal Timeを比較

NTPD上の時間と、LocalTimeとを比較するスクリプトを作ってみた。

結構色んな要素を含んでいて勉強になったかな。
ネットワークバイト列から時間への変換などをunpackを用いて実装する。

#!/usr/bin/perl

use strict;
use Socket;

# Local Time Lag Alart Threshold Seconds
my $threshold_sec = 30;

# NTPD Informations
my $host = 'ntp1.jst.mfeed.ad.jp';
my $protocol = "ntp";
my $sec_of_70years = 2_208_988_800;

# Local Settings
my $hostname = `/bin/hostname`;
chomp($hostname);
my $date = `/bin/date +%Y/%m/%d-%H:%M:%S`;
chomp($date);

# Variable Settings
my @buf;
my ($connect_host, $port, $ipaddr, $host_addr);
my ($send_data, $send_data_byte, $port_by_byte, $host_by_in_addr_struct, $recv_data);
my ($TransmitTime, $ntpd_time, $ntpd_time_sec, $local_time, $local_time_sec, $deley_sec);

if (!socket(SOCKET, PF_INET, SOCK_DGRAM, getprotobyname("udp"))) {
    print "socket: $!";
    exit 1;
}

$port_by_byte = scalar(getservbyname($protocol, "udp"));
$host_by_in_addr_struct = inet_aton($host);
$connect_host = sockaddr_in($port_by_byte, $host_by_in_addr_struct);

$send_data = pack("N12", 0x0B000000);
$send_data_byte = send(SOCKET, $send_data, 0, $connect_host);
if (!defined($send_data_byte)) {
    print "send : $!";
    exit 2;
}

$host_addr = recv(SOCKET, $recv_data, 1024, 0);
if (!defined($host_addr)) {
    print "recv : $!";
    exit 3;
}

($port, $ipaddr) = sockaddr_in($host_addr);
$host = gethostbyaddr($ipaddr, AF_INET);
print "DEBUG: Host: $host, Port: $port\n";

@buf = unpack("B32 B32 B32 B32 B64 B64 B64 B64 B*", $recv_data);
@buf = unpack("N*" , $recv_data);
$TransmitTime = $buf[10];

$ntpd_time_sec = $TransmitTime - $sec_of_70years;
$local_time_sec = time();
$deley_sec = abs($local_time_sec - $ntpd_time_sec);

# DEBUG
$ntpd_time = scalar(localtime($ntpd_time_sec));
$local_time = scalar(localtime());
print "DEBUG: ntpd? time: $ntpd_time.???? ntpd? time sec: $ntpd_time_sec\n";
print "DEBUG: local time: $local_time.???? local time sec: $local_time_sec\n";

if ($deley_sec >= $threshold_sec) {
    print "DEBUG: There is Local time lag ( = $deley_sec seconds ) over $threshold_sec seconds in $date at $hostname.\n";
}

実行結果はこんな感じ。

# perl a
DEBUG: Host: ntp1.jst.mfeed.ad.jp, Port: 123
DEBUG: ntpd  time: Wed Mar 11 22:43:06 2009.     ntpd  time sec: 1236778986
DEBUG: local time: Wed Mar 11 22:41:23 2009.     local time sec: 1236778883
DEBUG: There is Local time lag ( = 103 seconds ) over 30 seconds in 2009/03/11-22:41:23 at server01.