だるろぐ

だるいぶろぐです

create table して ERROR 1005 (HY000): Can't create table '$DB_NAME.$TABLE_NAME' (errno: -1) と言われたら .ibd ファイルが何故か存在しているから消せばいい

タイトル読んでお疲れさまでした。以上。

メモ

innodb_file_per_table の設定をしておくと、テーブルを作ると .ibd ファイルが作られる。

ref: http://nippondanji.blogspot.com/2009/01/innodb_16.html

drop table すればこのファイルも消える。


テーブルを作るとき、既存テーブルと同名だった場合は分かりやすいエラーが出る。

mysql> create database foo;
Query OK, 1 row affected (0.11 sec)

mysql> use foo
Database changed

mysql> create table bar(a int) engine=innodb;
Query OK, 0 rows affected (0.01 sec)

mysql> create table bar(a int) engine=innodb;
ERROR 1050 (42S01): Table 'bar' already exists


が、何故かテーブルは存在しないが .ibd ファイルは存在するという不思議な環境のもとでは、以下のように言われる。

mysql> create table bar(a int) engine=innodb;
ERROR 1005 (HY000): Can't create table 'foo.bar' (errno: -1)

おとなしく .ibd を消せばいい。というかそんな状況になってる時点で何かがおかしい。

# ls ~mysql/foo/bar.ibd
/var/lib/mysql/foo/bar.ibd

# rm ~mysql/foo/bar.ibd


という事を会社でしでかして解決してもらうなどしていました。
手間と迷惑をおかけしております。

nginxのconfigでifの並記を実現する

追記 Wed Jan 11 10:53:25 JST 2012
本では「並記」じゃなくて「並置」と書いてました

nginxの本(ハイパフォーマンスHTTPサーバ Nginx入門)を読んで、なるほどと思ったメモ。

例えばapachemod_rewriteのこんなのを

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]

nginxで実現しようとすると、素直にはいかない。
nginxのifは、if-elseも無いし、if andも無いし、ifのブロックの中に更にifを書けないので。

なので変数を使ってこのようにする手法が載っていた。

set $check "";

if (!-f $request_filename) {
    set $check "A";
}

if (!-d $request_filename) {
    set $check "${check}B";
}

if ($check = "AB") {
    rewrite . /index.php last
}


ifが成立したら、それぞれのifの中で変数に値を代入していって、最終的な変数の値を見る。
少々BKくさい。


本にも載っていたけど、この例ならば以下でいい。これはあくまで例示の為に載っていたのだけど、何でこんな例を選んだのだろ。

if (!-e $request_filename) {
    rewrite . /index.php last
}


そして今軽くググったら既に皆こういうことをしていたのだけどメモなので気にしない。

httpdでcacheする apache編

※このエントリは微妙に自力ではありません


webアプリを運用していて、静的・動的問わず

  • 転送量がやばい
  • 負荷がやばい
  • そのせいで誰かがやばい

などといったときがあることもあって、普通はmemcachedなりsquidなりを使うけど、

  • そこまでガッツリcacheする程ではない
  • 又はめんどい
  • 又はわざわざ他のミドルウェア導入せんでもhttpdだけである程度なら
  • いいから早く何とかしろ

などのケースが有ったり無かったり。


で、静的コンテンツをhttpdでさくっと対処する場合の話。
apacheだったらそこでmod_cache。
mod_cacheにはディスクに記憶するmod_disk_cacheとメモリに記憶するmod_mem_cacheがある。
静的コンテンツならmod_disk_cache、動的コンテンツ・リバースプロキシならmod_mem_cacheが定石らしい。

設定内容

例えば /images/ 以下のファイルをキャッシュする場合。

    <IfModule mod_disk_cache.c>
        CacheEnable disk /images/
        CacheRoot /dev/shm/mod_cache
        CacheDefaultExpire 3600
        CacheIgnoreCacheControl On
        CacheIgnoreNoLastMod On
        CacheDirLevels 1
        CacheDirLength 1
    </IfModule>

で、ディレクトリ作ってやる。

% sudo mkdir /dev/shm/mod_cache
% sudo chmod 777 /dev/shm/mod_cache

本当はディレクトリはこんな権限777じゃなくて、apacheを動かしているユーザ・グループで作るべし。
キャッシュをr/wするのはapacheを動かしているユーザなので。
777だとrootにならなくてもディレクトリにcdできるし中見るのも楽だわーとかになるので俺は個人的に777にしているだけである。
セキュリティホールになる気がしなくもない。


大体はマニュアルに載っているのだけど。

CacheEnable

http://httpd.apache.org/docs/2.2/ja/mod/mod_cache.html#cacheenable

キャッシュするパスと、mod_disk_cache/mod_mem_cacheのどちらを使うか指定する。
fdを指定した場合がマニュアル見てもいまいち分からないが多分必要になることは無い気がするのでYAGNIの精神で華麗にスルー。

CacheDirLength / CacheDirLevels

http://httpd.apache.org/docs/2.2/ja/mod/mod_disk_cache.html#cachedirlevels

cacheするのに使うディレクトリの階層と長さと。キャッシュするファイルが少なければどっちも1でいいだろう。
多くなったら…YAGNIの精神で略。

CacheRoot

http://httpd.apache.org/docs/2.2/ja/mod/mod_disk_cache.html#cacheroot

キャッシュするディレクトリを指定する。apacheは作ってくれないから手動で作る。
どうせなら物理ディスクよりもtmpfsを使った方がディスクio減るんじゃないかと。
そういえばtmpfsとramディスクってどっちが性能いいんだっけ。

CacheDefaultExpire

http://httpd.apache.org/docs/2.2/ja/mod/mod_cache.html#cachedefaultexpire

キャッシュする時間。内容が変化しない静的コンテンツなら巨大な値でもいい。

CacheIgnoreNoLastMod

http://httpd.apache.org/docs/2.2/ja/mod/mod_cache.html#cacheignorenolastmod

Last-Modifiedが無かろうとキャッシュする。ご丁寧にLMつけてるケースの方が少ない気がする。

CacheIgnoreCacheControl

http://httpd.apache.org/docs/2.2/ja/mod/mod_cache.html#cacheignorecachecontrol

個人的にはこれがハマりどころ。
ヘッダでCache-Control: no-cache や Pragma: no-storeがあってもキャッシュを返す。
俺はfirefoxでリロードして設定を確認するのだけど、どうもfirefoxさんのリロードはスーパーリロードか何かになっているらしく、mod_cacheがキャッシュを作ってもそのキャッシュを使わない。
アクセスログも304ではなく200が返る。それじゃ困るんですよ。

キャッシュの動作

これで例えば /images/hoge.jpg とかにアクセスするとこんなファイルが出来る。

% find /dev/shm/mod_cache/ -type f
/dev/shm/mod_cache/6/KXf3h0Y6M8uQNrbWN0eyA.data
/dev/shm/mod_cache/6/KXf3h0Y6M8uQNrbWN0eyA.header


※ここからうそ臭いです


キャッシュファイルのプロセスはこう。

  1. アクセスされたらキャッシュファイルが生成される
  2. 生成されてからCacheDefaultExpireで指定した秒数が経過するまでは、アクセスが来てもキャッシュがコンテンツを返し、実ファイルにはアクセスがいかない
  3. CacheDefaultExpire秒が経過しても、キャッシュファイルは削除されない。次のアクセスがきて初めて削除される。そして新しいキャッシュファイルが生成される。

なので、沢山のファイルにアクセスされた後に、コンテンツ一新などしてそのファイル全てがアクセスされなくなると、削除されないキャッシュファイルがたくさん残る。
手動でキャッシュを削除してやってもいいやも。
以下をcronで実行するとか。

find /dev/shm/mod_cache -type f -exec rm '{}' \;

todo

httpdでcacheする nginx編」を書く

例えば複数のpsgiをplackupするときにforkを使う

※この記事は自力ではありません


1つのアプリの中で複数の.psgiをplackupしたいときがある。
そんなとき、

  • 複数ターミナルを立ち上げてplackup
  • screenで複数ウィンドウ

などの手段で1個1個コマンド打ってもいい、のだけど、例えばforkでこんなことを。


今回は5000番と5001番を使う簡単なpsgiを例に取る。

psgi

# 5000.psgi

return sub {
    return [
        '200',
        [ 'Content-Type' => 'text/plain' ],
        [ "port: 5000" ],
    ];
};

# 5001.psgi

return sub {
    return [
        '200',
        [ 'Content-Type' => 'text/plain' ],
        [ "port: 5001" ],
    ];
};

打ちたいコマンド

% plackup 5000.psgi -p 5000 # デフォルトで5000番だけど例なので明示的に
% plackup 5001.psgi -p 5001


この2つのコマンドを1個のプログラムの中でforkして同時に動かす。

# main.pl

use strict;
use warnings;

my %children;

for my $arg (@ARGV) {
    if ($arg =~ /500\d/) {
        my $pid = fork;
        defined $pid or die "can not fork";

        if ($pid == 0) {
            exec "plackup $arg.psgi -p $arg";
            #die $!;
        }

        $children{$pid} = 1;
    }
}

#$SIG{TERM} = $SIG{INT} = $SIG{HUP} = sub {
#    kill 'TERM', keys %children;
#};

while (keys %children) {
    my $pid = wait;
    #delete $children{$pid};
}


見たまんまだけど一応流れ。

  1. 子プロセスを作って実行したいコマンドをexec
  2. 子プロセスのプロセスidを記憶
  3. 親プロセスが子プロセス全てをwait

あとは

% perl main.pl 5000 5001

で2つのコマンドを実行できる。終わったらc-cで全部止まる。



っていうのをボスがやってるのを見て真似している。
https://github.com/kazeburo/GrowthForecast/blob/master/growthforecast.pl
とかでも似たようなことをしている。

todo

上記のmain.plのコメントアウト部分はボスを真似したはいいものの、理解できない上にいじりまくってデバッグしていたら無くても動くことに気付いてでも書いたからには必要で意味があるはずなんだろうなと思いつつ結局放置しているのでいつか頑張る予定のまま永い月日が経っている。

cronやdaemontoolsで標準パス以外に置いてあるperlを使うなど

perlbrewを使っている場合など、PATHに含まれていないコマンドをcrontabやrunで使うとき自分はこうしてる。

変数で定義

PERL5LIB=/path/to/my/lib
myperl=/path/to/my/perl

$myperl /path/to/app.pl

PATHの先頭にpath追加

PERL5LIB=/path/to/my/lib
export PATH=/path/to/my/bin:$PATH

perl /path/to/app.pl


後者が誤爆する可能性が無くは無いかなあと思いつつ特に問題無い。

defunctプロセスが居ると svc -u できない

/service/hoge/run
/service/hoge/log/run
/service/hoge/log/main

などを置いて普通にdaemontoolsで運用していたとする。
何故か svc -dx などではなく、 kill -9 などで hoge/run と hoge/log/run を殺したりしたとする。
するといくら svc -dx したり /service/hoge/ を再配置したり supervise を削除したりしても、 svc -u で起動しなくなる。
ログすら吐かなくなる。
そんなときは ps auxf などで見ると [defunct] とかそれっぽいゾンビプロセスが居るはずなので、そいつを kill -9 してやる。