2013年1月15日火曜日

redis 2.6のaofファイルを覗いてみた

最近ちょこちょこ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が楽しくなってきた今日この頃なのでした。

2 件のコメント :

  1. keysコマンドですべてのkeyが取得できますよ http://redis.io/commands/keys

    返信削除
  2. keysコマンドだとkey名だけで、valueが引き抜けなかったのでこんなやっつけになったのです。。

    おとなしくforeachで回せば良かったと今気付きました。。orz

    返信削除