TTからCassandraへのインポート
Cassandra-0.6にもsstable2json, json2sstableというimport/exportするコマンドがあるが、
これは内部用のものなので、他のDBからのインポート用にはそのまま使えない。
しかも実際使ってみたけど1G程度のJSONインポートでヒープが足らんと言われてしまった。。。
仕方ないのでThrift経由でデータを入れるPerlスクリプトを書く。
参考にしてください。
tchmgr list -pv > tt_data.tsv # TTからのTSVエクスポート
#!/usr/bin/perl use strict; use warnings; use Net::Cassandra; use Coro; use Coro::Semaphore; $|=1; open IN, $ARGV[0] or die "cant open" . $ARGV[0]; # tt_data.tsv my @hosts = qw/127.0.0.1/; # hostを記述 my $keyspace = 'keyspace1'; my @clients; push @clients, Net::Cassandra->new(hostname => $_)->client for @hosts; my $coro_num = 2000; my $count = 0; my @coros; my $semaphore = Coro::Semaphore->new($coro_num); while(<IN>) { $count++; my $line = $_; push(@coros, async { chomp $line; my ($ttkey, $value) = split /\t/ , $line; my ($tt, $key, $column) = split /:/ , $ttkey; my $client = $clients[$count % scalar @clients]; $semaphore->up; eval { $client->insert( $keyspace, $key, Net::Cassandra::Backend::ColumnPath->new( { column_family => 'COLUMNFAMILY', column => $column} ), $value, time, Net::Cassandra::Backend::ConsistencyLevel::ALL ); }; # print $key . "\t" . $column . "\t" . $value . "\n"; }); $semaphore->down; } close(IN);
MySQL6.0アップデートのやりかた
fedora13で動作中のMySQL5.1からMySQL6.0にアップデートしたのでメモ。
作業
- 最新版のmysqlを取得
su - root cd /usr/local/src/ wget http://dev.mysql.com/get/Downloads/MySQL-6.0/mysql-6.0.11-alpha.tar.gz/from/http://ftp.jaist.ac.jp/pub/mysql tar xvzf mysql-6.0.11-alpha.tar.gz cd mysql-6.0.11-alpha
- configure -helpでオプションをcheckして適切なオプションを指定。
./configure --with-charset=utf8 --with-extra-charsets=all --with-mysqld-user=root --with-innodb \ --with-falcon --with-maria --with-heap --with-myisam --enable-local-infile --prefix=/usr/local/mysql \ --with-plugins=innobase,partition --with-unix-socket-path=/tmp/mysql.sock
- make,make install
- makeは少し時間かかった
make make install
/etc/init.d/mysql stop yum -y remove mysql-server
- mysqld(MySQL6.0)の起動
- my.cnfは5.1のままでいけたの楽ちん。
/usr/local/mysql/bin/mysqld_safe --user=root &
カンタンでしたね
mysql -u root -p mysql> select version(); +--------------+ | version() | +--------------+ | 6.0.11-alpha | +--------------+
MySQLメモ
参考にした本
- 実践ハイパフォーマンスMySQL
サーバーアーキテクチャ
最適化と実行
並行性の制御
- サーバレベルとストレージエンジンレベルの2つのレベルで行う必要あり
Read/Write Lock
- Read Lock: 共有ロックで相互にノンブロッキング
- Write Lock: 排他ロックで、Read Lockと他のWrite Lockをブロック
トランザクション
分離レベル(ACIDのI)
- SQL規格では4つの分離レベルを定義
- 分離レベルが低いほど並行性が高くなり、オーバヘッドが低くなる
- 4つの分離レベルまとめ
分離レベル | Dirty Read | Non-Repeatable Read | Phantom Read | Read Lock |
READ UNCOMMITED | ◯ | ◯ | ◯ | × |
READ COMMITED | × | ◯ | ◯ | × |
REPEATABLE READ | × | × | ◯ | × |
SERIALIZABLE | × | × | × | ◯ |
- READ UNCOMMITED
- READ COMMITED
- REPEATABLE READ
- SERIALIZABLE
- 競合しないようトランザクションを強制的に順序付けする
- 読み取る全ての行にロックを設定
トランザクションログ
マルチバージョンの並行性制御(MVCC)
- InnoDB,Falcon,PBXT
- ×:単純な行ロックメカニズム
- ◯:行レベルロック+MVCC
- MVCC
- MVCCのメリット
- 多くの場合でロックの必要性を完全排除し、オーバヘッドの多くを解消
- ロックを使用しない読み取りを許可し、かつ書き込み操作では必要なレコードのみをロックすることができる
- MVCCの実装
- ストレージエンジンごとに違う
- Optimistic/Pessimisticな実装がある
InnoDBのMVCC
- 行ごとに2つの隠れた値を格納
- 行が作成されたタイミング
- 行が期限切れ(削除)されたタイミング
- イベントが発生した実時間ではなく、システムバージョン番号を記録
- 新しいトランザクションの開始ごとにインクリメントされる番号
- 各トランザクションは開始時点でのシステムバージョン番号を記録
- クエリは、それぞれ、各行のバージョン番号とトランザクションのバージョンとを照合しなければならない。
- 照合条件は分離レベルで異なる
- MVCCはREPEATABLE READ/READ COMMITEDのみ対応
- 本にはREPEATABLE READの時のCRUDクエリそれぞれにおいて条件が書かれている
ロック方式 | 並行性 | オーバーヘッド | エンジン |
テーブルレベル | 最低 | 最低 | MyISAM,Merge,Memory |
行レベル | 高 | 高 | NDB Cluster |
MVCCを備えた行レベル | 最高 | 最高 | InnoDB,Falcon,PBXT,solidDB |
ストレージエンジン
- MySQL6.xの時点で13種類ある
Engine | MySQL Version | Transaction | Lock粒度 | usage | 使用すべきでない状況 |
MyISAM | ALL | × | 同時挿入可能なテーブル | SELECT,INSERT,一括READ | Read/Writeの混在 |
Memory | ALL | × | テーブル | 中間計算、静的lookup | 大きなデータセット、永続化 |
InnoDB | ALL | ◯ | MVCC+行レベル | Transaction | なし |
Falcon | 6.0 | ◯ | MVCC+行レベル | Transaction | なし |
Archive | 4.1 | ◯ | MVCC+行レベル | Log,集計 | ランダムアクセス,更新,削除 |
NDB Cluster | 5.0 | ◯ | 行レベル | 高可用性 | 典型的な用途 |
PBXT | 5.0 | ◯ | MVCC+行レベル | Transaction,Log | クラスタ化インデックスの必要性 |
solidDB | 5.0 | ◯ | MVCC+行レベル | Transaction | なし |
Hatena 2010 サマーインターンに採用されました。
去年の夏から「来年は絶対にどこかしらのインターンの参加しよう!!」と思い、どこがいいかなぁと探していて一番面白そう、というか一番情報源が豊富だなーと思って目をつけていたのが、このHatenaのインターン。
既に別のインターンの面接に落ちていて自信を無くしてたのですが、無事受かって良かったです。
僕のHatenaインターンへの志望動機は「大規模なリソースを使ってWebアプリケーションを書きたい!」というもの。
既にWebのベンチャーでアルバイトを4年間やっていて、小規模のWeb開発の経験はまぁあるといえばあるのですが、どうせなら、今専攻している「分散システム」の知識を生かしたWeb開発がやりたいなぁと前々から思ってたわけです。
Hatenaといえば、Perl。なんで中途半端にPerlなんだろうといつも思うのですが、きっと昔からのノウハウが豊富にあるからでしょう。
そういう僕はPerlについてはほぼ初心者同然なのですが(以前にMovalble Typeのソースを少しいじった程度)、これまでに幾つか言語を触った経験があるので、まぁ事前にある程度勉強すればたぶん大丈夫でしょう。(←甘い?)
夏が楽しみになってきました。ちょっと不安でもあるけど。。
MySQLのバルク処理は書かなきゃ駄目。
前回のYCSBのload phaseがMyCassandra(Cassandra+MySQL)ではめちゃくちゃ遅いという件でしたが、タイトル通りです。
さて大量のインサートをするときに、以下の3つの手法によってどれくらい差が出るのだろうか?
- singleインサートを何度もやる
- マルチプルインサート(複数レコードのインサートを1クエリで)
- バルクインサート(csvファイルでインサート)
答えは以下のサイトを参照あれ。
http://www.inter-office.co.jp/contents/194/
実行時間が1>>2>3というふうになっています。バルクインサートは単純インサートの800倍も早くなるという結果です。
バルク処理は書かなきゃ駄目。以上。
遅いのはSQLパーサー?
前述したYCSBを使ってCassandraとMyCassandraのベンチマークを取っているところ。
まだ途中なのでちゃんとした結果は公表出来ないのですが、とりあえず1ノードで1KBのレコードを100万件ロードして、ベンチをとったところ、基本的に予想通りな結果になってます。
具体的に言うと、
- 書き込み性能はCassandraの方が6.2倍速い
- 読み込み性能はMyCassandraの方が6.3倍速い
というようにちょうど性能が逆転した形になっています。(CassandraのMemTableサイズは64MB)
MyCassandraの方は読み込み性能が優れているわけですが、ストレージにMySQLを使っていることからレンジクエリについてもCassandraよりも最適化できそうな気がします。(今後実装してベンチマークEで測定してみる予定)
ただ本ベンチマークの実行とは関係ないのですが、
MyCassandraのデータロードが数十倍遅いという問題が...。
更新では問題ありません。あくまで新規データの追加(INSERT)の問題があるようです。
Cassandra/InnoDBの書き込み手順は以下のようになってます。
- Cassandra
- CommiLog(HDD)=>MemTable(Memory)=>SSTable(HDD)
- MemTable=>SSTableへの書き出しは非同期
- InnoDB
- log_buffer(HDD)=>buffer_pool(Memory)=>HDD
- innodb_flush_log_at_trx_commitが2ならbuffer_poolからHDDへの書き出しは非同期(0,1は同期)
と、見た目は両方とも同じ構造になっていることが分かります。
なのに、性能がこんなに遅いのはどこに問題があるのでしょう。
考えられるのはSQLのパース処理とコミット処理が遅いこと。またはMySQLの非同期の実装方法が良くないのではないかと。1秒周期でシステムコール`fdatesync()`を実行するんだとか。