OpenIDでテキストを共有できます
- 新規作成
- OpenIDで認証してエントリーを新規作成します
- 共有
- エントリーにはOpenIDで閲覧と編集に制限かけることができます
- 変更履歴
- 編集履歴もあるので、コラボレーションにも活用できます
新着エントリー
Image::Magickの暴走対策
なんかImage::MagickがCPU100%喰って終了しなくなることがあるので、alarmで対策。
try {
local $SIG{ALRM} = sub {
die "error:timeout";
};
alarm(60);
my $img = Image::Magick->new;
....
} catch {
die $_;
} finally {
alarm(0);
};
Try::Tiny便利
test
テストです。
memcachedは早くないよ。使い方によっては
memcached、memcached clientは早くても、オブジェクトのシリアライズ、デシリアライズなどを経由することで思っているよりもずっと遅くなるので注意しよう
#!/usr/bin/perl use strict; use warnings; use Cache::Memcached::Fast; use DateTime; use Benchmark; my $now = DateTime->now(); my $mem = Cache::Memcached::Fast->new({ servers => [qw/localhost:11211/] }); $mem->set( heavy => $now ); $mem->set( light => time ); Benchmark::timethese( 20000, { 'heavy' => sub { $mem->get( 'heavy' ); }, 'light' => sub { $mem->get( 'light' ); }, });
上は、DateTimeオブジェクトと単なるUNIX時間(数字)を入れて、取得するのを比べてみる例
% perl test.pl
Benchmark: timing 20000 iterations of heavy, light...
heavy: 8 wallclock secs ( 6.38 usr + 0.40 sys = 6.78 CPU) @ 2949.85/s (n=20000)
light: 1 wallclock secs ( 0.11 usr + 0.32 sys = 0.43 CPU) @ 46511.63/s (n=20000)
1/10以下の処理スピードとなります。注目すべきは、usrのCPU。ユーザ空間のCPUもたくさん喰うのでWebアプリケーションサーバなら他の処理も結構影響を受けるよね。より大きなオブジェクトの場合はその分、時間もCPUもたくさん消費してしまうよ!
memcachedは早いはずという考えて、1ページを生成する間に同じkeyをなんども取得してしまう事があるかもしれないけど、そこは一度アプリケーションのプロセスでキャッシュするなどの対策を考えよう
(memcahcedの仕組みを知るためのエントリーです。シリアライザーの速度に関するエントリーではありません)
mogilefsのような分散Webストレージを妄想ちう(メモです)
思うところがあって、シンプルでスケーラブルな分散Webストレージを考え中。
メモなのでまとまってません。ノード周りはmixiのインスパイア
ターゲットしてはファイル数が億単位になっても大丈夫なぐらいを目指す
いくつか機能としては
- MySQLに分散情報、メタデータを持つ。
- bucketという単位を持つ。bucketごと削除が可能かも。ジョブキューが必須
- ファイルは3台(ハードコード)のノードにコピーする
- ノードは3台一組。壊れたら同じ組のノードからコピーして復旧する
- ファイルの保存時に、1台のノードでも保存ができなかったら、別の組に変更する。書いてしまった分はジョブキュー経由で削除
- ファイルのアップロードはwebdavみたいなインターフェイスで
外部のURL構造は、
http://ws.foo.com/{bucket_name}/{filename}
とし、内部的には
http://node:port/{00}/{00}/{00}/{bucket_id}_{filename_id}
とする。
この際、{filename_id}は、tmaesakaのDigest::MurmurHashを使って32bit uintとなる。
1つのbucketにマジ大量のファイルを置かなければ衝突する可能性はそれなり低い。。はず。
{00}/{00}/{00} はfilename_idの下6桁から生成で。
bucket_idはauto_incrementで付加する。
この様な仕組みを持つと、元のファイル名をかなり小さい容量に圧縮ができ、また計算で求められるため、元のファイル名から内部ファイル名への変換テーブルを持たなくて済む。つまりメタデータのDBを小さくできる。
元のファイル名や付加情報は、コンテンツのヘッダに埋め込む
file content = [length(2byte)][{json data}][data..]
json = {
ct: 'image/jpeg',
fn: 'original_filename.jpg'
}
JSONでシリアライズして、長さと一緒に保存しちゃう。
ここまでで、MySQLのスキーマを考えてみると
CREATE TABLE nodes (
id INT UNSINGED NOT NULL PRIMARY KEY AUTO_INCREMENT,
gid SMALLINT UNSINGED NOT NULL,
node varchar(64),
can_read TINYINT UNSIGNED DEFAULT 0,
is_fresh TINYINT UNSIGNED DEFAULT 0
) ENGINE=InnoDB;
#id, gid, node, can_read, is_fresh
#1, 1, '192.168.55.10:80', 1, 1
#2, 1, '192.168.55.11:80', 1, 1
#3, 1, '192.168.55.12:80', 1, 1
#4, 2, '192.168.55.13:80', 1, 1
#5, 2, '192.168.55.14:80', 1, 1
#6, 2, '192.168.55.15:80', 1, 1
CREATE TABLE buckets (
id INT UNSINGED NOT NULL PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(32) UNIQUE,
enable TINYINT UNSINGED DEFAULT 1, --# 一時停止
delete TINYINT UNSINGED DEFAULT 0, --# 完全削除
) ENGINE=InnoDB
#id, name, enable, delete
#1, 'kazeburo', 1, 1
#2, 'chibiburo', 1, 1
#3, '_system', 1, 1
CREATE TABLE objects (
fid INT UNSINGED NOT NULL, --# filename_id, murmurhash(filename)
bucket_id INT UNSINGED NOT NULL,
gid SMALLINT UNSINGED NOT NULL,
PRIMARY KEY(ckey, bucket_id),
INDEX (bucket_id)
) ENGINE=InnoDB;
#fid, bucket_id, gid
#1173386060, 1, 1 #http://ws.foo.com/kazeburo/greatphoto.jpg => node 1,2,3
#3157638903, 2, 1 #http://ws.foo.com/chibiburo/myphoto.jpg => node 1,2,3
#1357344895, 1, 2 #http://ws.foo.com/kazeburo/new.jpg => node 4,5,6
な感じ。
objectsテーブルは、1行のデータサイズが10byteと小さいので、億単位のrowを入れてもなんとかなるんじゃないかと思う。
(object テーブルを変更しました 2010/07/30)
shell scriptでportが閉じるまで待つ
ncの-zオプションが使える
while nc -z localhost 11211 > /dev/null 2>&1; do echo 'wait for exit' sleep 1 done echo 'exited'
Gearman::XS試し中
workerでdieするときの動作
worker
#!/usr/bin/perl use strict; use warnings; use Gearman::XS qw(:constants); use Gearman::XS::Worker; my $worker = Gearman::XS::Worker->new; $worker->add_server("127.0.0.1", 4730); $worker->add_function( "reverse", 0, sub { die shift->workload() }, {} ); while(1){ warn "work start"; my $ret = $worker->work(); warn "return: $ret"; warn "error:" . $worker->error(); warn "work end"; }
client
% echo foo | gearman -t 1000 -h 127.0.0.1 -p 4730 -f reverse Job failed
worker log
work start at testworker.pl line 20. Job: 'reverse' died with: foo at testworker.pl line 14. return: 0 at testworker.pl line 22. error:gearman_wait:timeout reached at testworker.pl line 23. work end at testworker.pl line 24. work start at testworker.pl line 2
dieしてもworkの戻り値は0=成功。
errorの内容をみないとわからない
けど、dieしなくてもerrorに
error:gearman_wait:timeout reached at testworker.pl line 23.
とかでたりもするし、dieしてもtimeoutでたり、何もでなかったり。
何この謎仕様
__DIR__
package DIR; use strict; use warnings; use base qw/Exporter/; use Cwd qw/realpath/; use File::Basename qw/dirname/; our @EXPORT = qw/__DIR__ __RDIR__ __RFILE__/; sub __DIR__ () { dirname( (caller)[1] ); } sub __RDIR__ () { dirname( realpath( (caller)[1] )); } sub __RFILE__ () { realpath( (caller)[1] ); } 1;
Memcachedの起動パラメータをSNMP経由で取得する
statsで調べることができないmax connectionとか調べたいときに
まず、PIDを調べる。PIDはstatsでとれる
% telnet 192.168.x.x 11211 Trying 192.168.x.x... Connected to xxx (192.168.x.x). Escape character is '^]'. stats STAT pid 27060 **ココ STAT uptime 6128543 STAT time 1278056399 (略)
SNMPで起動パラメータがとれる
snmpwalk -c DataHotel -v 2c 192.168.x.x hrSWRunParameters.[pid] HOST-RESOURCES-MIB::hrSWRunParameters.27060 = STRING: "-m 64 -c 1024 -u memcached -p 12345"
SNMPでCPU数
HOST-RESOURCES-MIBいろいろとれるね
http://www.oidview.com/mibs/0/HOST-RESOURCES-MIB.html
% snmpwalk -v 2c -c public localhost hrDeviceType|grep hrDeviceProcessor HOST-RESOURCES-MIB::hrDeviceType.768 = OID: HOST-RESOURCES-TYPES::hrDeviceProcessor HOST-RESOURCES-MIB::hrDeviceType.769 = OID: HOST-RESOURCES-TYPES::hrDeviceProcessor
CPUの詳細は
% snmpwalk -v 2c -c public localhost hrDeviceDescr HOST-RESOURCES-MIB::hrDeviceDescr.768 = STRING: AuthenticAMD: Quad-Core AMD Opteron(tm) Processor 1354 HOST-RESOURCES-MIB::hrDeviceDescr.769 = STRING: AuthenticAMD: Quad-Core AMD Opteron(tm) Processor 1354