2009年2月28日土曜日

postgresqlのslow-log

基本的なことなのかも知れませんが、postgresql用スローログの取得方法についてメモ。
僕のテストサーバーでのPostgresqlバージョンは7.4.12です。

1)postgresql.confの設定(ソースからインストールした場合は/usr/local/pgsql/data下にあります)
syslog = 2 # range 0-2; 0=stdout; 1=both; 2=syslog
log_min_duration_statement = 100 # milliseconds
syslog_facility = 'LOCAL0' # この設定はなくてもOK?
を追加。(クエリ実行に100ミリ秒以上かかったクエリをsyslogへ出力。facilityはlocal0に設定)

2)/etc/syslog.confの設定
local0.* /var/log/postgres
を追加。(facility0を/var/log/postgresへログ出力)
*.info;mail.none;authpriv.none;cron.none /var/log/messages
をコメントアウトして
*.info;mail.none;authpriv.none;cron.none;local0.none /var/log/messages
を追加。(これがないと/var/log/messagesと/var/log/postgresの両方にログが出てしまう)

3)postgresqlとsyslogを再起動
# /sbin/service postgres reload
# /sbin/service syslog restart
以上で、実行に時間のかかるクエリのログが取得できます。
他にもpostgresql.confでいろいろ設定できるようなので、試してみる価値ありそうです。

これ試してみて、サーバーが重くなったら即時に設定を元に戻してpostgresqlとsyslogを再起動してください。

以上。・゚・(ノε`)・゚・。

fsockopen()でタイムアウト

よくWEBサイトで、広告バナーを広告サーバー(ADサーバー)から取得→表示という事が行われます。

その場合、phpなサイトではfsockopen()を使って、ソケット通信でバナーを取得する事が多いと思うのですがその場合のメモ。

※以下PHPマニュアルより
resource fsockopen ( string $hostname [, int $port [, int &$errno [, string &$errstr [, float $timeout ]]]] )
第5引数の float $timeout はソケット通信時のタイムアウト時間(秒)です。
で!僕はtimeout秒数は、設定した秒数ソケットの応答がなかった場合に接続を断念するものだと思っていました。

いや、そうなんですけど、言葉で説明むずかしいのですが、
1)ソケット接続完了
2)fputs()で情報を取得しに行く
3)応答がない、、、
4)timeout秒だけ頑張る
5)それでも応答がなければ諦める
↑のような動作だと思っていたのです。

調べてみると、実はそうではなくtimeout秒数は、ソケット接続を確立させるために待つ秒数であり、接続完了後に応答がなくて待つ秒数ではないみたいです。(実際そういう現象に遭遇しました、、><)

ソケットは接続確立されたが、ソケット接続先のサーバーから応答がない場合に切断したい場合の処理は

soket_set_timeout()と
stream_get_meta_data()を使え!
array stream_get_meta_data ( resource $stream )
既存の stream に関する情報を取得します。 ストリームは fopen() か、 fsockopen() か、pfsockopen() で 作成されたいずれのものも指定できます。 結果の配列は次のような項目を含みます。

timed_out (bool ) - 最後に fread() または fgets() でデータを待っている時にタイムアウトした場合 TRUE を返します。
この関数は、結果が配列で返ってくるのですがその中の'time_out'がtrueだった場合は応答時間切れのフラグです。

-- 以下サンプル
// ソケットでHOST:PORTに接続(TIMEOUT秒は頑張る)
if ($fp = @fsockopen(HOST, PORT, err_no, err_str, TIMEOUT)) {
  // 接続確立したら、タイムアウトは5秒に設定
  socket_set_timeout($fp, 5);
  // ソケットのメタデータを取得
  $socket_data_arr = stream_get_meta_data($fp);
  // ソケットでデータを送信
  fputs($fp, $hoge);
  // 応答があれば応答を取得
  $buf = "";
  // $socket_data_arr[time_out"]がtrueなら接続タイムアウト!
  while (!feof($fp) && !$socket_data_arr["time_out"]) {
    $buf .= fgets($fp, 1024);
  }
  fclose($fp);
}

以上。・゚・(ノε`)・゚・。

linuxのlocale設定メモ

イマイチLinuxについて分からないことが多いです。
例えばjavaで
public static void main(String[] args) {
System.out.println("ほげ");
}
と、EUC-JPで作成した場合に

1)まず、コンパイルで怒られた。
# javac Hoge.java
「コラー!!"??????"ってなんじゃー!?ASCIIコードマッピングにないでー!怒」
みたいな感じで。

2)だから、コンパイルにエンコードオプションをつける
# javac -encoding euc-jp Hoge.java
するとコンパイルできる。

3)じゃあ実行してみる。予想では標準出力(僕のテスト環境ではコンソール画面)に「ほげ」と出る予定。
しかし、出ない。というか文字化け(?)
# java Hoge
4)なんでだろぅ?と熟考したところ、あ!そういえば環境変数LANG=Cにしてたわ!ということで、LANG=ja_JP.euc_JPに!!

5)ところが僕のテストサーバー(ubuntu)は、ja_JP.euc_JPがないみたい、、、。UTF8しかない。
# locale -a | grep ja
ja_JP.utf8
6)ココらへんからだいぶ曖昧ですが、LANG=に存在しないロケール情報を登録してもLinux側で設定してくれないみたい?
# export LANG=foobartestest (←ありえないロケール)
# echo $LANG
foobartesttest
となるが、実際はデフォルトの(僕の場合はC)LANGで表示される。

7)という事で、ubuntuにEUC-JPとついでにSJISを入れてあげる。
# localedef -i ja_JP -f EUC-JP ja_JP.eucJP
# localedef -i ja_JP -f SJIS ja_JP.sjis
# locale -a | grep ja
ja_JP.eucjp
ja_JP.sjis
ja_JP.utf8
入った!

8)では、Linuxコンソールの文字コードをeucjpにして、もう一度
# java Hoge
ほげ
出た!!!!

とりあえず、そんな上記のような感じでjavaで日本語表示できました。

まー本来の目的はjavaで日本語表示することではなかったのですが、とりあえずLinuxの言語設定に関して少し知識が増えたかな?という感じでした。

apacheのカスタムエラーレスポンスについてメモ

Apacheの設定で、

ErrorDocument 404 http://外部URL/filename?param=value
のような事をしたい時ってあるよね。

いや、俺はありました。
ユーザーがリクエストしたファイル名とパラメータが何だったか?を取得する方法がないかな~?って調べてたらあった。

こんな時はApacheが自動的に

REDIRECT_HTTP_ACCEPT=*/*, image/gif, image/x-xbitmap, image/jpeg
REDIRECT_HTTP_USER_AGENT=Mozilla/1.1b2 (X11; I; HP-UX A.09.05 9000/712)
REDIRECT_PATH=.:/bin:/usr/local/bin:/etc
REDIRECT_QUERY_STRING=
REDIRECT_REMOTE_ADDR=121.345.78.123
REDIRECT_REMOTE_HOST=ooh.ahhh.com
REDIRECT_SERVER_NAME=crash.bang.edu
REDIRECT_SERVER_PORT=80
REDIRECT_SERVER_SOFTWARE=Apache/0.8.15
REDIRECT_URL=/cgi-bin/buggy.pl
という変数を作ってみれるみたいです。
だから、ErrorDocumentで指定したファイル内で
$_ENV["REDIRECT_XX"]ってやれば取得できる。
※外部URLへリダイレクトされた(ErrorDocumentが外部URL)場合は無理です。


「おおー!便利ー!」って思ったけど、よく考えたらそんな事しなくても簡単にphpで

$_SERVER["REQUEST_URI"]
で取れちゃうジャン。
ま、いつか使うかもね。

2009年2月4日水曜日

[Linux]openしているプロセス情報を表示する

どうも、俺です。

今扱っているWEBシステムで、セッションファイルとApacheのアクセスログを/tmpではなく/tmpfsとしてメモリ上に保存しています。

ある日/tmpfsが上限の900MBに達してしまい、「こりゃヤバイ!」ということで600MB程あるApacheのアクセスログをローテートさせたのですが、/tmpfsの使用容量はほとんど変わりません。
# df
Filesystem 1K-blocks Used   Available Use% Mounted on
/tmpfs    921600   873120 48480   95%  /tmpfs
実は、Apacheアクセスログをローテートさせた時に再起動も行っているのですが、
とある子プロセスがゾンビとなり、access_logへのポインタを保持し続けていたようです。
なので
# ls -l /tmpfs
としても出てこないのですが、古いaccess_logが/tmpfs上に残っていたようです。

# /usr/sbin/lsof | grep deleted
とすれば、本来であればあるはずのないaccess_logが出てきました。

あとはそのプロセスをkillして万事解決です。
しかし、なんでApacheの子プロセス残っちゃったのか調べないとな~。。。

amazon