最近ちょこちょこredis触ってます。
この前、`redisに載ってる全KEYをダンプしたい!'とかふと思い付いてやろうと思ったんですが、
redis-cliから叩くにも良さそうなものがないので、ダンプファイルから抜こうと思いました。
dump.rdbはこんなデータ。
$ od -c dump.rdb
0000000 R E D I S 0 0 0 6 376 \0 \n 003 b b b
0000020 032 032 \0 \0 \0 022 \0 \0 \0 002 \0 \0 006 s e c
0000040 o n d \b 005 f i r s t 377 \0 003 a b c
0000060 300 \n \0 002 a a 003 n i c 377 y 6 210 q 365
0000100 ` t 177
0000103
bbbというリストに"second", "first"の2要素、abcというキーに"10"、aaというキーに"nic"が入ってる。
先頭12バイト(\0\nまで)がヘッダっぽい感じで、1バイトでキーの名前の長さ、キー名、
キー名の終端はよく判らない、1バイトで値の長さ、値、の順?
よし、あきらめる。
マニュアル読めば書いてあるのかも知れないけど、
こんなものを俺のPerl力でパースさせていたら多分redisの新バージョンが出てしまう。
折り良く(?)aofファイルも出力(というかこっちがメインで運用してた)させていたので、
そっちを何とか解析できないかと思って覗いてみる。
$ od -c appendonly.aof
0000000 * 2 \r \n $ 6 \r \n S E L E C T \r \n
0000020 $ 1 \r \n 0 \r \n * 3 \r \n $ 3 \r \n s
0000040 e t \r \n $ 2 \r \n a a \r \n $ 3 \r \n
0000060 n i c \r \n * 3 \r \n $ 3 \r \n s e t
0000100 \r \n $ 3 \r \n a b c \r \n $ 2 \r \n 1
0000120 0 \r \n * 3 \r \n $ 5 \r \n l p u s h
0000140 \r \n $ 3 \r \n b b b \r \n $ 5 \r \n f
0000160 i r s t \r \n * 3 \r \n $ 5 \r \n l p
0000200 u s h \r \n $ 3 \r \n b b b \r \n $ 6
0000220 \r \n s e c o n d \r \n * 1 \r \n $ 4
0000240 \r \n s a v e \r \n
0000250
…ん?; なんかすごくASCII文字だなこれ。
$ head appendonly.aof
*2
$6
SELECT
$1
0
*3
$3
set
$2
aa
…ほう!
レスポンスが間に入って読みにくいけど、これredisの生コマンドっぽい。
というか、まさにこれだった。プロトコル仕様。すてき。
欲しいのはキーの名前とキーの長さだったので、レスポンスの部分は省くことに決定。
キーの名前に英大文字は使っていないという噂だったので、/^[A-Z]+$/をリクエストとして扱うことに大決定。
取り敢えず書いてみる。
$ cat appendonly.pl
#!/usr/bin/perl
use strict;
use warnings;
use Fcntl;
my $sBuff = "";
my $sTmp = "";
sysopen(IN, "/usr/redis/appendonly.aof", O_RDONLY);
sysopen(OUT, "/usr/redis/tmp.aof", O_WRONLY | O_CREAT);
while ($sBuff = <IN>) {
chomp $sBuff;
if ($sBuff =~ /^[A-Z]+$/) {
if ($sTmp ne "") {
printf(OUT "%s\n", $sTmp);
$sTmp = "";
}
} elsif ($sBuff =~ /^(\*|\$)/) {
next;
}
$sBuff =~ s/[\r\n]/ /g;
$sTmp .= $sBuff;
}
printf(OUT "%s\n", $sTmp);
__END__
我ながらやっつけ仕事。。
ともあれこれで、
`SET key value\n'
の列挙されたテキストファイルが/usr/redis/tmp.aofにどばーと吐き出される。
これを適当にawk '{print $2,length($3)}' とかで切って集計したりしていて気付いたんだけど、
aofファイルにはタイムスタンプが無いのでちょっと不便。
そこで、redis-cli set mymark `date "%Y/%m/%d %H:%M:%S"`とかするようにcronに仕込んでおくと、
awk '{if ($2 == "mymark") {print $3} else if ($2 == "keyname") {print $2,length($3)}}' ..
とやった時に特定のキーが時間経過とともにめりめり大きくなっていくのが確認できたり。
意外とredisが楽しくなってきた今日この頃なのでした。
keysコマンドですべてのkeyが取得できますよ http://redis.io/commands/keys
返信削除keysコマンドだとkey名だけで、valueが引き抜けなかったのでこんなやっつけになったのです。。
返信削除おとなしくforeachで回せば良かったと今気付きました。。orz