CentOS 5.8にコンパイル済みのTokuDB入りMySQLをインストールするよ
これはすんなりいきましたよ。
参照したのは
Documentation, Collateral and White Papers | Tokutek
の
TokuDB for MySQL 5.5 Users Guide(pdf)
基本的にはデフォルトだと/usr/local/mysqlにインストールする作りになってました。
あと、あらかじめmysqlユーザーとか作っておいてね。
インストール環境
# cat /etc/redhat-release CentOS release 5.8 (Final) # uname -a Linux hostname 2.6.18-308.13.1.el5 #1 SMP Tue Aug 21 17:10:18 EDT 2012 x86_64 x86_64 x86_64 GNU/Linux
手順
ダウンロードと解凍
TokuDB Community Edition Downloads | Tokutek
の
TokuDB 7.1.5 for MySQL 5.5.36, 64-bit Linux
をダウンロード
/usr/local/src
に設置
からの
# cd /usr/local/src # tar zxvf ./mysql-5.5.36-tokudb-7.1.5-linux-x86_64.tar.gz # mv ./mysql-5.5.36-tokudb-7.1.5-linux-x86_64 /usr/local/mysql
my.cnf設定
好きなので良いと思うんですが
# cd /usr/local/mysql # cp ./support-files/my-innodb-heavy-4G.cnf ./my.cnf # vi ./my.cnf ここで文字コード設定や必要な設定を
MySQL初期設定
# cd /usr/local/mysql # ./scripts/mysql_install_db \ --user=mysql chown -R mysql:mysql .
mysqld立ち上げ
# /usr/local/mysql/support-files/mysql.server start
ここで
mysql error while loading shared libraries: libaio.so.1: cannot open shar ed object file: No such file or directory
というエラーが出たので
yum -y install libaio libaio-devel
足りないモジュールをyumでインストール。
で、再度スタート
# cd /usr/local/mysql # ./support-files/mysql.server start
MySQL起動確認
# ps aux | grep mysql root 31436 0.0 0.0 64016 1284 pts/0 S 17:02 0:00 /bin/sh /usr/local/mysql/bin/mysqld_safe --datadir=/usr/local/mysql/data --pid-file=/usr/local/mysql/data/hostname.pid mysql 32090 1.4 2.3 3019076 288036 pts/0 Sl 17:02 0:01 /usr/local/mysql/bin/mysqld --basedir=/usr/local/mysql --datadir=/usr/local/mysql/data --plugin-dir=/usr/local/mysql/lib/plugin --user=mysql --log-error=/usr/local/mysql/data/hostname.err --open-files-limit=8192 --pid-file=/usr/local/mysql/data/hostname.pid --socket=/tmp/mysql.sock --port=3306
立ち上がってる!
TokuDB確認
# /usr/local/mysql/bin/mysql mysql> show engines; +--------------------+---------+----------------------------------------------------------------+--------------+------+------------+ | Engine | Support | Comment | Transactions | XA | Savepoints | +--------------------+---------+----------------------------------------------------------------+--------------+------+------------+ | FEDERATED | NO | Federated MySQL storage engine | NULL | NULL | NULL | | MRG_MYISAM | YES | Collection of identical MyISAM tables | NO | NO | NO | | MyISAM | DEFAULT | MyISAM storage engine | NO | NO | NO | | BLACKHOLE | YES | /dev/null storage engine (anything you write to it disappears) | NO | NO | NO | | CSV | YES | CSV storage engine | NO | NO | NO | | TokuDB | YES | Tokutek TokuDB Storage Engine with Fractal Tree(tm) Technology | YES | YES | YES | | MEMORY | YES | Hash based, stored in memory, useful for temporary tables | NO | NO | NO | | ARCHIVE | YES | Archive storage engine | NO | NO | NO | | InnoDB | YES | Supports transactions, row-level locking, and foreign keys | YES | YES | YES | | PERFORMANCE_SCHEMA | YES | Performance Schema | NO | NO | NO | +--------------------+---------+----------------------------------------------------------------+--------------+------+------------+ mysql> show plugins; | TokuDB | ACTIVE | STORAGE ENGINE | ha_tokudb.so | GPL | | TokuDB_trx | ACTIVE | INFORMATION SCHEMA | ha_tokudb.so | GPL | | TokuDB_locks | ACTIVE | INFORMATION SCHEMA | ha_tokudb.so | GPL | | TokuDB_lock_waits | ACTIVE | INFORMATION SCHEMA | ha_tokudb.so | GPL | | TokuDB_file_map | ACTIVE | INFORMATION SCHEMA | ha_tokudb.so | GPL | | TokuDB_fractal_tree_info | ACTIVE | INFORMATION SCHEMA | ha_tokudb.so | GPL | | TokuDB_fractal_tree_block_map | ACTIVE | INFORMATION SCHEMA | ha_tokudb.so | GPL |
TokuDBあった!
show enginesでTokuDBが無かった場合
# /usr/local/mysql/bin/mysql mysql> install plugin tokudb soname 'ha_tokudb.so'; mysql> install plugin tokudb_file_map soname 'ha_tokudb.so'; mysql> install plugin tokudb_fractal_tree_info soname 'ha_tokudb.so'; mysql> install plugin tokudb_fractal_tree_block_map soname 'ha_tokudb.so'; mysql> install plugin tokudb_trx soname 'ha_tokudb.so'; mysql> install plugin tokudb_locks soname 'ha_tokudb.so'; mysql> install plugin tokudb_lock_waits soname 'ha_tokudb.so';
TokuDB用に設定ファイル更新
デフォルトのストレージエンジンをTokuDBに
・my.cnf書き換え # vi /usr/local/mysql/my.cnf > default-storage-engine = MYISAM < default-storage-engine = TokuDB ・再起動 # /usr/local/mysql/support-files/mysql.server restart Shutting down MySQL... SUCCESS! Starting MySQL.. SUCCESS! ・確認 # /usr/local/mysql/bin/mysql mysql> use test; mysql> CREATE TABLE `create_test` ( `hoge` int(10) unsigned NOT NULL DEFAULT '0', `fuga` varchar(120) NOT NULL DEFAULT '' ); *************************** 1. row *************************** Table: create_test Create Table: CREATE TABLE `create_test` ( `hoge` int(10) unsigned NOT NULL DEFAULT '0', `fuga` varchar(120) NOT NULL DEFAULT '' ) ENGINE=TokuDB DEFAULT CHARSET=latin1 mysql> INSERT INTO create_test(`hoge`, `fuga`) VALUES(1,'foo'); Query OK, 1 row affected (0.04 sec) mysql> SELECT * FROM `create_test`; +------+------+ | hoge | fuga | +------+------+ | 1 | foo | +------+------+ mysql> show create table `create_test`\G;
できましたね!
複数のバージョンのMySQLを扱う為に
ダウンロードと解凍の時点で、違うディレクトリに設置
例) /usr/local/mysqls/mysql_tokudb_built
my.cnf設定の前にファイル書き換え
/usr/local/mysql -> /usr/local/mysqls/mysql_tokudb_built /tmp/mysql.sock -> /tmp/mysql_tokudb_built.sock
対象ファイルは/usr/local/mysqls/mysql_tokudb_built以下の
bin/mysqld_safe bin/msql2mysql bin/mysqlaccess bin/mysql_config bin/mysqld_multi docs/INFO_BIN include/my_config.h include/mysql_version.h support-files/my-large.cnf support-files/my-huge.cnf support-files/mysql.server support-files/my-innodb-heavy-4G.cnf support-files/my-medium.cnf support-files/mysql-log-rotate support-files/my-small.cnf
です。
まあこんな感じで書き換えて
cd /usr/local/mysqls/mysql_tokudb_built perl -pi -e 's!/usr/local/mysql!/usr/local/mysqls/mysql_tokudb_built!g;s!/tmp/mysql.sock!/tmp/mysql_tokudb_built.sock!g' \ bin/mysqld_safe \ bin/msql2mysql \ bin/mysqlaccess \ bin/mysql_config \ bin/mysqld_multi \ docs/INFO_BIN \ include/my_config.h \ include/mysql_version.h \ support-files/my-large.cnf \ support-files/my-huge.cnf \ support-files/mysql.server \ support-files/my-innodb-heavy-4G.cnf \ support-files/my-medium.cnf \ support-files/mysql-log-rotate \ support-files/my-small.cnf
他には、my.cnfのserver-id変更やポート番号変更、
MySQL初期化作業の際に
/usr/local/mysqls/mysql_tokudb_built/scripts/mysql_install_db \ --basedir=/usr/local/mysqls/mysql_tokudb_built \ --user=mysql
とする位であとは同様の流れです。
なお、/usr/local/mysqls/mysql_tokudb_built/bin/mysqlで起動する場合、毎回socketファイルを指定してあげる必要があります。
/usr/local/mysqls/mysql_tokudb_built/bin/mysql --socket=/tmp/mysql_tokudb_built.sock
CentOS 5.8にcmakeインストール
はじめに
cmakeは設定しないからyumで入れようと思ったけど2.6.4と古いのでソースからインストール
- バージョン切り替えてく上でもインストール先は/usr/local/cmake/<各バージョン>
- /usr/local/cmake/default(主に使うバージョンのシンボリックリンク)
- /usr/local/cmake/default/binにPATHを通す
という方針。
参照したのは
仕事で使える魔法のLAMP(45):MySQLのビルドに欠かせないCMakeを準備する - @IT
インストール環境
# cat /etc/redhat-release CentOS release 5.8 (Final) # uname -a Linux hogehoge 2.6.18-308.13.1.el5 #1 SMP Tue Aug 21 17:10:18 EDT 2012 x86_64 x86_64 x86_64 GNU/Linux
ソースダウンロード
# cd /usr/local/src/ # wget http://www.cmake.org/files/v2.8/cmake-2.8.12.2.tar.gz # tar zxvf cmake-2.8.12.2.tar.gz # cd cmake-2.8.12.2
make
# ./configure --prefix=/usr/local/cmake/2.8.12.2 |& tee configure_log.txt # vi ./CMakeCache.txt > CMAKE_BUILD_TYPE:STRING= < CMAKE_BUILD_TYPE:STRING=Release # make VERBOSE=1 |& tee make_log.txt
make test
make testするも
# make test |& tee make-test_log.txt 25 - FindPackageTest (Failed) 254 - RunCMake.include_directories (Failed)
こける
個別にテスト
# ./bin/ctest -VV -R FindPackageTest # ./bin/ctest -VV -R RunCMake.include_directories
こけるこける
調べてみるものの
0013237: 25 - FindPackageTest (Failed) - MantisBT
Sending old, never assigned issues to the backlog.
あばば、解決してない…
あきらめてmake installしてみる
make install
# make install |& tee make-install_log.txt
切換しやすいように
# ln -s /usr/local/cmake/2.8.12.2 /usr/local/cmake/default
で、
/usr/local/cmake/default/bin
にPATHを通す
これで使えてます。
数字6桁パスワードのハッシュ値の総当たり、Perlでも約0.25秒で終わるよ
タイトルウソです。もっとかかりましたすみません。
徳丸浩の雑記帳: 数字6桁パスワードのハッシュ値の総当たり、PHPなら約0.25秒で終わるよ
を読んで、Perlでも実装してみた。
まあPHPとほとんど変わらないんですけれども。
今回はマルチプロセスの復習がてら実装。
環境
# OS FreeBSD 9.1-RELEASE-p9 amd64 # CPU Intel Xeon E312xx (Sandy Bridge) # Perl 5.8.9
さくらのスタンダードプランです。はい。
コード
#!/usr/bin/perl use common::sense; use Getopt::Long; use Digest::MD5 qw/md5_hex/; use Parallel::ForkManager; use Time::HiRes qw/time/; GetOptions( 's|salt=s' => \my $salt, 'hs|hash=s' => \my $hash, 'p|process=i' => \my $process, 'verbose' => \my $verbose, ); my $max_num = 1000000; $process ||= 2; my $start_time = time; main(); my $exec_time = time - $start_time; print 'TOTAL_EXEC_TIME: ' . $exec_time . "\n"; exit; sub main { my $current = 0; my $pm = Parallel::ForkManager->new( $process ); do { warn sprintf("parallel: %s process\n", $process); $pm->run_on_start( sub { my ($pid, $ident) = @_; warn sprintf("%s starts\n", $ident); } ); $pm->run_on_finish( sub { my ($pid, $exit_code, $ident, $exit_signal, $core_dump, $data) = @_; $current++; warn sprintf("%s completes.(%d/%d)\n", $ident, $current, $process); warn sprintf(" sec : %s\n", $$data) if defined $data;# must Parallel::ForkManager over v0.7.6 } ); } if $verbose; for (my $start = 0; $start < $process; $start++) { $pm->start($start) and next;# parent go next my $child_start_time = time; _search_hash($start, $process); my $child_exec_time = time - $child_start_time; $pm->finish(0, \$child_exec_time); } $pm->wait_all_children; return undef; } sub _search_hash { my ($start, $step) = @_; for ( my $i = $start; $i < $max_num; $i += $step) { my $pass = sprintf("%06d", $i); next if md5_hex($salt . '$' . $pass) ne $hash; # match my $time = time - $start_time; print sprintf("Solved: %s %s\n", $pass, $time); } return undef; } 1;
Parallel::ForkManager 使って並行ダウンローダ作った - 理系学生日記
のコードを丸コピ…。
実行
[sv] $ perl ./jal.pl -p 4 -s hoge -hs 4b364677946ccf79f841114e73ccaf4f -v parallel: 4 process 0 starts 1 starts 2 starts 3 starts Solved: 567890 0.186630010604858 2 completes.(1/4) sec : 0.386913061141968 1 completes.(2/4) sec : 0.523470878601074 3 completes.(3/4) sec : 0.457498073577881 0 completes.(4/4) sec : 0.597269058227539 TOTAL_EXEC_TIME: 0.604266166687012
ぐはっ、思ったよりかかるな…共用サーバだから仕方ないか。
同じサーバで徳丸先生のコードを実行してみる。
おんなじぐらいか、Perlのがちょい遅いぐらいか。
同じようなコードの書き方でやったら同じぐらいになるかな?
という感じでした。
6桁の数字なら
パスワード忘れたよ!>キューに入れる>ワーカーが総当り>メールでパスワードを送信(この間わずか1秒)
が可能ですね!
Q4MにてSELECT COUNTで件数がとれるがSELECT *もdequeueもできない場合の強引な対処
某日Q4Mが動いているサーバがダウンしまして。
再起動後、Q4Mを立ち上げなおした所、Worker(Perl製。参照 http://perl-users.jp/articles/advent-calendar/2009/data-model/22.html)がQueueを受け取れなくなってました。
mysql> SELECT COUNT(*) FROM queue_table; +----------+ | COUNT(*) | +----------+ | 365474 | +----------+ 1 row in set (0.00 sec)
と件数がとれるんですが、
mysql> SELECT * FROM queue_table LIMIT 2; Empty set (0.01 sec)
と中身がとれないという、おかしなことに。
もちろんqueue_wait()もできません。
ただ、enqueueはできています。
今回の環境は
CentOS 6.2 + MySQL 5.1.48 + Q4M 0.9.4 ※Q4Mコンパイル時のconfigureはディレクトリ指定以外デフォルト
です。
今回は、消えても復旧できるログだったので力技で解決する事に。
同じ構成でテーブル作って、実データであるQ4Mファイルをコピーすれば同様に動くんですよ…
対応方法1
対象テーブルは
queue_table
- Worker停止、enqueueも停止
- 移行先テーブル作成
CREATE TABLE `queue_table_` ( `id` char(255) DEFAULT NULL, `job_data` blob, `priority` tinyint(4) unsigned DEFAULT '10' ) ENGINE=QUEUE DEFAULT CHARSET=sjis;
- ファイル確認
cd /usr/local/mysql_q4m/var/project ls -la queue_table.Q4M queue_table_.Q4M
- 実データコピー
cp -ap queue_table.Q4M queue_table_.Q4M
- MySQLからのアクセス確認
mysql> SELECT * FROM queue_table_ LIMIT 2; mysql> SELECT COUNT(*) from queue_table_; mysql> SELECT queue_wait('queue_table_'); mysql> SELECT * FROM queue_table_; mysql> SELECT queue_abort(); mysql> SELECT COUNT(*) FROM queue_table_; ※データが取得できればOK
- テーブルリネーム
ALTER TABLE `queue_table` RENAME `queue_table_bak`; ALTER TABLE `queue_table_` RENAME `queue_table`;
- 確認できたら古いテーブルを消す
DROP TABLE `queue_table_bak`;
- Worker開始、問題なければenqueueも開始
対応方法2
対象テーブルは
queue_table2
こちらは
- 対応1やっても無理(表題の事象が起こる)
- select count(*)は取れるがselect *は取れない
- Workerを回している間はselect *投げて帰ってきたり返ってこなかったりする
どうもWorkerのqueue_runningで1件dequeueしている間は、select *でとれるようだ!?
そんなバカな。だが目の前にある現実。
- enqueue停止
- Workerを動かす
ただし、挙動的にはqueue_wait()、queue_abort()を繰り返している
- 移行先テーブル作成
CREATE TABLE `queue_table2_` ( `id` char(255) DEFAULT NULL, `job_data` blob, `priority` tinyint(4) unsigned DEFAULT '10' ) ENGINE=QUEUE DEFAULT CHARSET=sjis;
- 実データコピー
mysql> INSERT INTO `queue_table2_` (`id`,`job_data`,`priority`) SELECT * FROM `queue_table2`; 0件ならもう一度試す
- MySQLからのアクセス確認
mysql> SELECT * FROM queue_table2_ LIMIT 2; mysql> SELECT COUNT(*) from queue_table2_; mysql> SELECT queue_wait('queue_table2_'); mysql> SELECT * FROM queue_table2_; mysql> SELECT queue_abort(); mysql> SELECT COUNT(*) FROM queue_table2_; ※データが取得できればOK
ただし、
mysql> SELECT COUNT(*) FROM queue_table2; +----------+ | COUNT(*) | +----------+ | 365474 | +----------+ 1 row in set (0.00 sec) mysql> SELECT COUNT(*) FROM queue_table2_; +----------+ | COUNT(*) | +----------+ | 365473 | +----------+ 1 row in set (0.00 sec)
多分Workerでdequeueしている分がないんだと思う。
データが1件欠損する。
- Worker停止
- テーブルリネーム
ALTER TABLE `queue_table2` RENAME `queue_table2_bak`; ALTER TABLE `queue_table2_` RENAME `queue_table2`;
- 確認できたら古いテーブルを消す
DROP TABLE `queue_table2_bak`;
- Worker開始、問題なければenqueueも開始
とまあ、力技で解決しました。
テーブル構造が壊れてたのかなあ。
オススメできない対処方法です。
kumofsを利用する上での注意点
ぼくのかんがえたさいきょうの高ディスクI/Oマシン
という記事の続き。
上記記事でセットアップした仮想マシンで何やってたかというと、今回障害が発生したプロダクトではkumofsというKVSを利用しておりまして
The Kumofs Project
HAHAHA、見事に更新が止まってますね。
事象としては
kumo-serverが3台以上ダウンした
に当たります。
この際、full-replaceサブコマンドを発行しろと書いてあるのですが、いかんせんサーバスペック的に時間がかかりすぎる、と。
なので、kumomergedbというコマンドを使って、複数サーバに分散させているデータベースファイルを1つにマージさせる手法を取りました。
full-replaceは分散されているデータの再配置を行っており(という理解をしている)、データを全部マージして1つのデータベースファイルにして、各サーバに配置すれば同様の結果になりますので(ファイルサイズはともかく)。
そもそも「バックアップとるだろJK」という声も聞こえますが、データベースファイルが肥大化しすぎて、バックアップするとサービス止まるという悲惨な状況に。
サーバを追加しようとしても、attachコマンド発行すると追加したサーバにデータを配置しようとしてトラフィックがえらいことになりパフォーマンスが低下、結果サービスが止まるという。
初期設計のミスでした。ほんとごめんなさいごめんなさいごめんなさい。
ここでkumomergedbコマンドを使う上での注意点があります。
kumofsを利用した事のある人には常識ですが、kumofsが利用しているTokyoCabinetには64GBの壁というものが存在します。
TokyoCabinet 64GBの壁
http://ameblo.jp/cyberx-engineer/entry-10688375059.html
64bit環境で容量64GB以上のTokyoCabinetのデータファイルを扱うには、
HDBTLARGEオプションを指定する必要があるようです。
この壁、実はkumomergedbする際に出力するファイルが64GB超えた場合にも存在します。
公式ドキュメントには
$ kumomergedb backup.tch-20090101 \ server1.tch-20090101 server2.tch-20090101 server3.tch-20090101
と書いてありますが、この
backup.tch-20090101
が64GBを超えると、データが書き込めなくなり、その先処理がいつまでたっても進まなくなります。
この場合、
$ tchmgr create -tl backup.tch-20090101 400000000 $ kumomergedb backup.tch-20090101 \ server1.tch-20090101 server2.tch-20090101 server3.tch-20090101
と、事前にHDBTLARGEオプションをつけて空の出力ファイルを作っておくか、
$ cp -ap server1.tch-20090101 backup_tenuki.tch-20090101 # server1.tch-20090101があらかじめHDBTLARGEオプションを指定して作られたデータファイルならここでoptimizeの必要多分なし $ tchmgr optimize -nl -tl backup_tenuki.tch-20090101 400000000 $ kumomergedb backup_tenuki.tch-20090101 \ server2.tch-20090101 server3.tch-20090101 # deleteフラグ立ってるけど消えてないデータとか?余計なデータが混ざるようなのでもう一度optimizeすると前者と同じファイルになるよ $ tchmgr optimize -nl -tl backup_tenuki.tch-20090101 400000000
とmergeする前にoptimizeかけて、そのファイルを出力先にするという、横着するのもありですね。
両方試して、できたファイルに対しsha512sumでハッシュを計算、チェックサムを比較したところ同じでした)
$ sha512sum backup.tch-20090101 d6328ab93e1638f74d5c8c61c3f16894e83c6fbe8b31f226e0aa7765a72f886c2c2764c7572a44543119320d3917a48b6671cf5733b29ca1d05e234e800af3a8 $ sha512sum backup_tenuki.tch-20090101 d6328ab93e1638f74d5c8c61c3f16894e83c6fbe8b31f226e0aa7765a72f886c2c2764c7572a44543119320d3917a48b6671cf5733b29ca1d05e234e800af3a8
他注意点。
kumofsはCentOS 6には普通にやってはインストールできません。
kumofs on CentOS6
http://blog.developerlabs.net/2013/02/kumofs-on-centos6.html
0.5.0 から msgpack の executeメソッドが使えず
/usr/local/bin/kumoctl:61:in `receive_message': undefined method `execute' for # (NoMethodError)
が出てくるので 0.4.7が必須です
どはまりした際、本当に助かりました…
こんな感じでインストールしました。
yum -y install libtool.x86_64 openssl.x86_64 openssl-devel.x86_64 zlib.x86_64 zlib-devel.x86_64 bzip2-devel.x86_64 cd /usr/local/src tar zxvf ncurses-5.6.tar.gz cd ncurses-5.6 ./configure --with-shared --without-normal --without-debug make make install ldconfig cd /usr/local/src tar zxfv ruby-1.9.3-p125.tar.gz cd ruby-1.9.3-p125 ./configure --prefix=/usr/local/ruby make make install echo /usr/local/ruby/lib > /etc/ld.so.conf.d/ruby.conf ldconfig cd /usr/local/src tar zxfv rubygems-1.8.24.tgz /usr/local/src/rubygems-1.8.24 /usr/local/ruby/bin/ruby setup.rb cd /usr/local/src tar zxfv msgpack-0.5.0.tar.gz cd /usr/local/src/msgpack-0.5.0 ./configure --prefix=/usr/local/msgpack make make install echo /usr/local/msgpack/lib > /etc/ld.so.conf.d/msgpack.conf ldconfig /usr/local/ruby/bin/gem install msgpack -v=0.4.7 cd /usr/local/src tar zxfv tokyocabinet-1.4.45.tar.gz cd /usr/local/src/tokyocabinet-1.4.45 ./configure --prefix=/usr/local/tokyocabinet make make install echo /usr/local/tokyocabinet/lib > /etc/ld.so.conf.d/tokyocabinet.conf ldconfig cd /usr/local/src tar zxfv ragel-6.6.tar.gz cd /usr/local/src/ragel-6.6 ./configure --prefix=/usr/local/ragel make make install ln -s /usr/local/ragel/bin/ragel /usr/bin/ragel mkdir /usr/local/kumofs cd /usr/local/src tar zxvf kumofs-0.4.13.tar.gz cd kumofs-0.4.13 ./configure --prefix=/usr/local/kumofs/kumofs0413 --with-msgpack=/usr/local/msgpack --with-tokyocabinet=/usr/local/tokyocabinet make make install ln -s /usr/local/kumofs/kumofs0413 /usr/local/kumofs/default
他に、サーバは生きているけどネットワークに障害が起こったケースも注意が必要です。
下記のようなkumo-managerが関わる障害が発生したと仮定
--------------- ネットワーク1 KMGR-1 KSV-1 KSV-2 KSV-3 KSV-4 --------------- ネットワーク2 KMGR-2 KSV-5 KSV-6 ---------------
というようにネットワークが分かれていて、スイッチ等が故障してネットワーク1からネットワーク2に接続できなくなった場合
--------------- ネットワーク1 KMGR-1 KSV-1 KSV-2 KSV-3 KSV-4 KMGR-1「あれ、KSV-5、KSV-6の2台死んだぞ?だがまだいける!」 --------------- ネットワーク2(死亡) KMGR-2 KSV-5 KSV-6 KMGR-2「あれ、KSV-1からKSV-4まで4台死んだぞ?full-replace必要だわー!」 ---------------
という状態になります。
で、このまま復旧、ネットワーク1からネットワーク2につながるようになり、replaceサブコマンドを発行すると、
--------------- ネットワーク1 KMGR-1 KSV-1 KSV-2 KSV-3 KSV-4 KMGR-1「あれ、KSV-1からKSV-4まで4台死んだぞ?full-replace必要だわー!」(<- KMGR-2から同期) --------------- ネットワーク2 KMGR-2 KSV-5 KSV-6 KMGR-2「あれ、KSV-1からKSV-4まで4台死んだぞ?full-replace必要だわー!」 ---------------
という事も起きえます。
ドキュメントには「まずダウンしたkumo-managerを再起動してください」と書いてありますが、ネットワーク障害が復旧してからkumo-managerを再起動させるか、プロセスを殺しておいて復旧してから起動、replaceサブコマンドを発行しょう。
なかなかこんな事ないとは思いますが。
以下、要参照。
kumofs - がしまっくす
kumofsを使うならここを熟読すべし。
@tmtms のメモ
attach、detachの動作の解説など
多分もうkumofs使うことないだろうなあ。
ぼくのかんがえたさいきょうの高ディスクI/Oマシン
ようやくトラウマから覚め、まとめる気になりました(その話はまた後日)。
数ヶ月前の事を当時のメモを参考にしつつ、思い出しながら書きます。
ここ数年、某所に旅行に行く度にサーバがぶっ飛んで(多分ヤンデレ)、復旧作業が発生します。
(最近は旅行先からsshで入って構ってあげるようにしてます。やれやれだぜ)
今年は、合計600GB強のデータ(今回のプロダクトで利用しているデータストア8台分)をマージしなければならないという事態になりました。
さすがに震えた。
今回のマージ作業の性質として、
- データストア数台分のデータの中から、ユニークな部分を検索し、1つのファイルに書き出し
- 過去同様の作業経験より、ボトルネックは書き出し部分(ディスクI/Oの書き込み性能)
- マージ作業でメモリはほとんど使わない
という点があげられます。
どうやら勤め先のサーバのスペックだとマージだけで1週間以上かかりそうで、とにかく高速なディスクI/Oを持つマシンが必要に。
- 最終的にマージ結果のファイルサイズは100GBぐらいに落ち着く
- gzで圧縮すれば、元データは1ファイルあたり約15GB、合計120GB程度になる
- 作業用ファイルだけ解凍すれば良いので、同時に必要となるストレージサイズは最低400GB程度(約120+約80*2+約100GB)
以上の点を頭におきつつ、amazon Web services(AWS)のインスタンス一覧を見ていた所、あるではないですか、素敵なインスタンスが!
最終的に利用したのはストレージに特化したインスタンスではなく、メモリに特化したインスタンスである
High Memory Cluster Eight Extra Large (cr1.8xlarge) instance
米国西海岸(オレゴン)リージョン(us-west-2)
(毎時$3.500かかる…!)
です。
※当時東京リージョンで使えませんでした
これは
「単一ディスクならメモリをマウントしてRAMディスクとして使うのが一番速いんや!」
という思想だった為です。
※無検証
このcr1.8xlargeインスタンス、スペックとしては
244GBメモリ
となっております。うーんメモリお化け。
どうせインスタンスは揮発性、SSD2つはなりふり構わずRAID 0で組みます。
結果
18GBメモリ
226GB RAMディスク
という構成に。ひいっ化物!
※18GB残したのは適当です(なんで16GBにしなかったんだろう…記憶なし)。
このスペックなら、東京->西海岸、西海岸->東京と、ファイルの転送に多少時間がかかっても、十分お釣りが来る、と読みました。
トータル466GBあるので、うまくやれば(gzファイルとマージ先ファイルをRAMディスク上に、gzファイルを解凍した元データをSSDに)手間がかかりますがなんとかなりますし。
結果、1週間かかりそうだった作業が、作業自体は1日程度で終わりました…
(途中、高速転送ツールであるTsunami UDPを使用しようとしてうまく動かず、普通にrsyncで送ったり、OSのバージョン違いでデータストアのインストールに手間取ったりして、結局2日近くかかった)
2ファイルマージするのに40分かからなかったのを見て、ブヒィィィってなりましたもんね。
ちなみにTsunami UDPについては下記参照。使ってみたいんですよねーこれ。
リージョン間高速データ転送
http://ijin.github.io/blog/2013/04/03/accelerating-cross-region-data-transfer/
cr1.8xlargeを単一インスタンスでこんな使い方したのは珍しいんじゃないかなーと…
ありがとう、そしてありがとうAWS!
以下作業手順です。
今回一般的に配布されているイメージを利用しました。
AMIはCentOS 6.4の「ami-503bae60」を使用。
CentOS 6.4 AMI available
インスタンスの立ちあげ、セットアップは省略。
Instance Store(Ephemeral Store)を全て付けるのを忘れずに。
まずは必要となるものをインストール
$ sudo yum update -y $ sudo yum install mdadm xfsprogs -y
マウントを外す
$ umount /dev/xvdb $ sudo blockdev --setra 65536 /dev/xvdb $ sudo mkfs.xfs -f -l version=2 -l size=64m -l lazy-count=1 /dev/xvdb $ umount /dev/xvdc $ sudo blockdev --setra 65536 /dev/xvdc $ sudo mkfs.xfs -f -l version=2 -l size=64m -l lazy-count=1 /dev/xvdc
RAID 0作成
$ yes | sudo mdadm --create --verbose /dev/md0 --level=0 -c256 --raid-devices=2 /dev/xvdb /dev/xvdc $ sudo echo 'DEVICE /dev/xvdb /dev/xvdc' > /etc/mdadm.conf $ sudo mdadm --detail --scan >> /etc/mdadm.conf
ファイルシステムを作成
$ sudo blockdev --setra 65536 /dev/md0 $ sudo mkfs.xfs -f -l version=2 -l size=64m -l lazy-count=1 /dev/md0 $ sudo mkdir -p /mnt/md0 $ sudo mount -t xfs -o discard,nobarrier,relatime /dev/md0 /mnt/md0 $ cd /mnt/md0
以上参照)
訳:エフェメラルディスクでRAID0
http://understeer.hatenablog.com/entry/2012/03/22/080938
Amazon EC2でEphemeral StoreをRAID0構成にしてディスクI/O性能を上げる
http://dev.classmethod.jp/cloud/amazon-ec2-ephemeral-store-raid0/
メモリマウント(/zなのは趣味)
umount /dev/shm mount -t tmpfs -o size=226G tmpfs /z df -ih /z
参照)
tmpfs は本当に容量が動的なのか
http://d.hatena.ne.jp/naoya/20060217/1140176470
これで環境完成!
PerlのmapをPerlで実装(車輪の再発明)
聞かれて答えられなかったので調べて書いた。
キモは関数で受け取る引数の制限(プロトタイプ)を利用。
&を第一引数として指定した場合には、ブロックごと受け取れるとのこと。
ブロックを受け取れるのは第一引数だけね。
プロトタイプ使うことないなーと思って読み飛ばしてたわ。
参照
第140回 ブロックを渡せるのはRubyだけじゃない! Perlだって渡せるんだ! - bingo_nakanishiの他言語出身者のためのPerl入門
以下ソース
#!/usr/bin/perl use strict; use warnings; use Data::Dumper; $Data::Dumper::Indent = 1; $Data::Dumper::Sortkeys = 1; $Data::Dumper::Terse = 1; my @base_arr = (1 .. 5); print 'all_incr ' , '-'x33 , "\n"; print Dumper all_incr(@base_arr); print 'all_incr_own ' , '-'x33 , "\n"; print Dumper all_incr_own(@base_arr); sub all_incr { my @arr = @_; map { my $num = $_; ++$num } @arr; } sub own_map (&@); sub all_incr_own { my @arr = @_; own_map { my $num = $_; ++$num } @arr; } sub own_map (&@) { my $code = shift; my @return_arr; foreach (@_) { push @return_arr, $code->(); } return @return_arr; } 1;
結果
all_incr --------------------------------- 2 3 4 5 6 all_incr_own --------------------------------- 2 3 4 5 6