オープンソースカンファレンス関西@京都でセミナーします

7月9日、10日に開催される
オープンソースカンファレンス関西@京都で
okuyamaを題材にセミナーを開催させていただく
ことになりました。




OSC関西のページ
http://www.ospn.jp/osc2010-kyoto/


セミナーのページ
http://www.ospn.jp/osc2010-kyoto/modules/eguide/event.php?eid=54




当日は「なぜ今KVSなのか?」という簡単なおさらいから
okuyamaの特徴と内部構造、活用事例をご紹介させていただきます。
お時間ございましたら、是非おこしください。

okuyama-0.7.0リリースまとめ

okuyamaのバージョン0.7.0をリリースしたのでまとめを書きます。

今回のリリースは結構大きい機能追加をしました。

■1つ目
    従来のokuyamaはマスターノードを複数で稼動させて冗長化をすることは出来たんですが、
    その場合、どれか1つがメインマスターノードになって、各データノードの生存確認とかしてて、
    そのマスターノードが落ちた場合はクライアントからのリクエストは別のマスターノードで
    さばけるんですが、データノードの生存確認とか、再起動した場合にデータリカバーとかはできませんでした。
    従来の対応方法は稼働中の別のマスターノードの設定ファイルを変更して、あなたが
    次はメインのマスターノードですよって、してあげないとだめだったんです。
    でもこれって相当面倒で、運用負荷すごいので改修しました。


    どうなったかというと、メインのマスターノードがダウンしたら、別のマスターノードが自動的に
    メインに昇格します。で、元々メインだったマスターノードが再起動すると、また元に戻ります。
    これでマスターノード2インスタンス起動しとけば、運用は少し楽になったかな。


    絵で表すと



こんな感じです。




■2つ目
    従来のokuyamaは設定情報(マスターノードがどのマシンでどんなポートで起動してるとか、データノードの全ての情報とか)を
    全ての各マスターノードが設定ファイルで持ってたんですが、これだとデータノード1つ
    追加するにも、全てのマスターノードの設定ファイルを変更しなければいけないので、これは面倒なので
    改修しました。
    改修内容は設定情報をデータとしてデータノードに格納するようにしました。
    起動時だけは設定ファイルから読むしかないので、設定ファイルは不要にはなりませんが、起動後はデータノード内の情報を
    変更するだけで、全てのマスターノードに反映されます。




■3つ目
    2つ目の改修で設定をデータノードに格納するようになったんですが、じゃあどうやってその情報変えるのって事で、
    さすがに、コンソールからsetValue呼び出して更新するのもあれなんで、管理用のWeb画面作成しました。
    画面はこんな感じ

    それぞれの項目の横にある[UPDATE]ボタンで内容を更新出来て、
    各データノードとスレーブデータノードの状態を確認できます。ダウンしてる場合はステータス表示が変わります。
    基本的には設定ファイルの内容をそのままWebから一括変更できるようにした感じなので、
    設定内容とかは設定ファイルの説明内容がそのまま適応されいます。
    起動方法とかは、リリース物のReadMe.txtに書きましたのでそちらを参照ということで。
    デザインは相当ダサいですね。。。orz

分散キーバリューストアokuyamaバージョン0.6.6をリリース

okuyamaのバージョン0.6.6をリリースしました。
今回の変更点はokuyamaのデータノードを"データノード"、"スレーブデータノード"両方を
起動している場合に片側のノードがダウンして、起動してきた場合(ダウンしたノードと
同じIP、Portであれば当該ノードとみなす)にデータをリカバーするんですが、
その処理中は従来クライアントからの処理をキューイングして待ち状態にしていたんですが、
その部分の待ちのタイミングを大幅に削減しました。
実際にスペックの良くないマシンでそこそこのデータ量(1ノードのデータが100万件くらい)を
持たせて運用していた場合に、ノードがダウンして、その後リカバーが実行されるとその間の
待ち時間が使用側のアプリに結構悪影響を与えていたので、
"これでは無停止とは言わないな!!"ってことで改修しました。
それではやはり待ちになるタイミングはあるので、完全な"待ち無し"とはいかないですが、
かなりマシになるはずです。


最近の変更は基本的に"新機能"ではなく、"機能改善"ですね。
やっぱり実運用してると色々あります。
まあ、そこからのフィードバックでどんどん堅牢なものが出来るというのもあるので、
良い方向にすすんでるかと。

分散キーバリューストアokuyamaの性能をまともなマシンで測ってみた(続)

この前okuyamaの性能測定の結果を書きましたが、
そこで"トランザクションログ+データファイルでの永続化モード"での性能で
5万QPS出ていたのですが、これって本当にファイルReadしてるのかって
怪しかったので、再度検証してみました。


[測定時の構成]

そもそもこの測定時の構成では全てのDataNodeが1台のマシン上で稼動しています。
その構成でkeyとvalueを全てメモリで保持している"トランザクションログ永続化モード"よりも
"トランザクションログ+データファイルでの永続化モード"のほうが良いQPSが出るのはおかしいので少し考察を




考察前に少しokuyamaの仕組みを書きます。
okuyamaのDataNodeのコアであるデータ保持部分は
■org.imdst.util.KeyManagerValueMap
になります。
※okuyamaをダウンロードしていただいていればsrc/org/imdst/util/KeyManagerValueMap.javaになります。
このクラスはjava.util.concurrent.ConcurrentHashMapを継承したクラスとなっています。
データは全てこのクラスから出し入れしています。
実際には"トランザクションログ永続化モード"と"データファイルでの永続化モード"ではvalueの格納先が違うのですが、
内部で処理を切り替えることで、データを取り出す外部クラスからは、モードを意識せずにアクセスできます。


で、実際にこのクラスを使用しているのは、
■org.imdst.util.KeyMapManager
になります。
※okuyamaをダウンロードしていただいていればsrc/org/imdst/util/KeyMapManager.javaになります。


この2つのクラスを使用しokuyamaはデータの永続化を実現しています。


"トランザクションログ永続化モード"と"データファイルでの永続化モード"それぞれの詳細は

■"トランザクションログ永続化モード"

データ登録(set)、削除時(remove)の操作を全ての1つのファイルに追記で記録し続けます。
ファイル名は設定ファイルで任意に決めれます。ここではtransaction.logとします。
"transaction.log"ファイルの内容

"+,ZGF0YXNhdmVrZXlfMA==,c2F2ZWRhdGF2YWx1ZXN0cl8w,1275668116734,;"  <-set
"+,ZGF0YXNhdmVrZXlfMQ==,c2F2ZWRhdGF2YWx1ZXN0cl8x,1275668116750,;"  <-set
"+,ZGF0YXNhdmVrZXlfMg==,c2F2ZWRhdGF2YWx1ZXN0cl8y,1275668116765,;"  <-set
"-,ZGF0YXNhdmVrZXlfMA==, ,1275668125000,;"   <-remove
"+,a2V5MQ==,dmFsdWUx,1275668137109,;"   <-set
"+,a2V5Mg==,dmFsdWUy,1275668141984,;"   <-set
上記の内容をDataNode起動時に1行づつ実行していくと、データが復元できる仕組みです。


■"データファイルでの永続化モード"
"transaction.log"はデータの復元に使用します。復元後のデータと、以降の登録データをどこに持たせるかを
決定するモードが、"データファイルでの永続化モード"です。
このモードにしない場合は、メモリモードとなりorg.imdst.util.KeyManagerValueMapの継承している、ConcurrentHashMapにkeyとvalue
保持されます。すなわち起動後は全てインメモリで保持します。
この場合、もてるデータのサイズがメモリに依存するので、大きなサイズのデータを保持するのには向きません。
後、メモリ容量の小さい一昔前のサーバも同様です。
そこで、"データファイルでの永続化モード"の登場です。
このモードでは、valueは全て1つのファイルに保存されます。
KeyManagerValueMapはkey値とvalueの格納されているファイル上での行位置を
インメモリで持ちます。
データファイルはこんな感じです。

c2F2ZWRhdGF2YWx1ZXN0cl8w&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
c2F2ZWRhdGF2YWx1ZXN0cl8x&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
c2F2ZWRhdGF2YWx1ZXN0cl8y&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
dmFsdWUx&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
dmFsdWUy&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
固定長でファイルに記録されています。
固定長なので、データの行位置さえ持っていれば始点と終点を計算しread出来るという仕組みです。


では実際のKeyManagerValueMapのソースはどうなっているかというと
まずは登録処理である
KeyManagerValueMapのput(key, value)メソッド

1 public Object put(Object key, Object value) {
2 Object ret = null;
3 if (memoryMode) {
4
5 ret = super.put(key, value);
6 } else {
7
8 StringBuffer writeStr = new StringBuffer();
9 int valueSize = (value.toString()).length();
10 try {
11
12 if (readObjectFlg == true) {
13
14 writeStr.append((String)value);
15 // 渡されたデータが固定の長さ分ない場合は足りない部分を補う
16 // 足りない文字列は固定の"&"で補う(38)
17 byte[] appendDatas = new byte[oneDataLength - valueSize];
18
19 for (int i = 0; i < appendDatas.length; i++) {
20 appendDatas[i] = 38;
21 }
22
23 writeStr.append(new String(appendDatas));
24 writeStr.append("\n");
25 String write = writeStr.toString();
26
27 // 書き込む行を決定
28 synchronized (sync) {
29
30 if (vacuumExecFlg) {
31 // Vacuum中の差分データを登録
32 Object[] diffObj = {"1", key, value};
33 vacuumDiffDataList.add(diffObj);
34 }
35
36 this.bw.write(write);
37 this.bw.flush();
38 this.lineCount++;
39 super.put(key, new Integer(lineCount));
40 this.nowKeySize = super.size();
41 }
42 } else {
43 super.put(key, value);
44 }
45 } catch (Exception e) {
46 StatusUtil.setStatusAndMessage(1, "KeyManagerValueMap - put - Error [" + e.getMessage() + "]");
47 }
48 }
49 return ret;
50 }
まずはメモリモードかファイル永続化モードかを確認[3行目]し、メモリモードなら自身のConcurrentHashMapにputし終了です[5行目]。
ファイル永続化時は、固定長になるようにデータを補ってやり[14行目-21行目]、ファイルに書き出しています[36行目-37行目]。
その後、key値と行位置をConcurrentHashMapにput[38行目-39行目]し終了です。
※ファイルに書き出される値は全てbase64エンコードされた値です。効率悪いですね。。。


では取得処理である
KeyManagerValueMap.get(key)メソッドは

1 public Object get(Object key) {
2 Object ret = null;
3 if (memoryMode) {
4
5 ret = super.get(key);
6 } else {
7 try {
8
9 // Vacuum中はsyncを呼び出す
10 if (vacuumExecFlg) {
11
12 ret = syncGet(key);
13 } else {
14
15 int i = 0;
16 int line = 0;
17 Integer lineInteger = null;
18 byte[] buf = new byte[oneDataLength];
19 long seekPoint = 0L;
20
21 lineInteger = (Integer)super.get(key);
22
23 if (lineInteger != null) {
24 line = lineInteger.intValue();
25 } else {
26 return null;
27 }
28
29 // seek計算
30 seekPoint = new Long(seekOneDataLength).longValue() * new Long((line - 1)).longValue();
31
32 synchronized (sync) {
33 if (raf != null) {
34 raf.seek(seekPoint);
35 raf.read(buf,0,oneDataLength);
36 } else {
37 return null;
38 }
39 }
40
41 for (; i < buf.length; i++) {
42 if (buf[i] == 38) break;
43 }
44
45 ret = new String(buf, 0, i, ImdstDefine.keyWorkFileEncoding);
46 }
47 } catch (Exception e) {
48 StatusUtil.setStatusAndMessage(1, "KeyManagerValueMap - get - Error [" + e.getMessage() + "]");
49 }
50 }
51 return ret;
52 }
まずはメモリモードかファイル永続化モードかを確認[3行目]し、メモリモードなら自身のConcurrentHashMapからgetし終了です[5行目]。
ファイル永続化時は、ConcurrentHashMapからkey値でデータのファイル中での行位置情報を取り出し[21行目]、行位置からファイル中での
データの始点位置を計算し[30行目]、その位置までseekします[34行目]。seek後その位置から固定長分データを読み込み[35行目]、読み込んだ値を返します。
※ファイルのreadアクセスにはRandomAccessFileクラスを使用しています。


removeに関しては、ファイル永続モードに関係なく、ConcurrentHashMapからkey値でremoveしているだけです。
一部Vacuum処理のコードも入っていますが(Vacuumに関してはまた別のエントリー書こうと思います)おおむねこういう感じです。
基本的にはデータファイルも追記型で、登録、更新関係なく最新の行位置を更新していく構成になっています。




この仕組みから分かるように、永続化時はファイルをReadするのでインメモリ時よりの性能が出るのは考えられないのですが、
ひとつ可能性があるとすればOSのページキャッシュです。
プログラムではディスクを読んでいるつもりが、実はメモリ上のキャッシュページを読んでいる可能性です。
そこで以下の方法でOS上のページキャッシュから、okuyamaのデータファイルを追い出してやります。

cat 巨大なファイル > /dev/null
実行後、okuyamaのgetを実行すると、予想通り大幅に処理性能が落ちました。
前回は5万QPS出ていたのが、今回は2000QPSです。
その差25倍!!
しかも、DataNodeのiowaitが70%〜100%という高い値で推移しています。
topコマンドでDataNodeの状況を見ると

top - 19:57:27 up 5 days, 9:42, 2 users, load average: 2.44, 0.60, 0.20
Tasks: 131 total, 1 running, 130 sleeping, 0 stopped, 0 zombie
Cpu0 : 0.0%us, 0.0%sy, 0.0%ni,100.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Cpu1 : 0.0%us, 0.0%sy, 0.0%ni,100.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Cpu2 : 1.0%us, 0.0%sy, 0.0%ni, 14.9%id, 79.2%wa, 2.0%hi, 3.0%si, 0.0%st
Cpu3 : 1.0%us, 2.0%sy, 0.0%ni, 0.0%id, 90.0%wa, 0.0%hi, 7.0%si, 0.0%st
Mem: 4033988k total, 4003552k used, 30436k free, 4208k buffers
Swap: 8388600k total, 35956k used, 8352644k free, 1587284k cached
CPUは4コアで、DatNodeも8インスタンス稼動しているのに、実際にはiowaitのせいで、
2つのCPUしかまともに動けてません。
これはHDDが2つ且つ、Raid0の影響だと思います。
まさにディスクI/Oがボトルネックになっています。


今度は以下のコマンドで、okuyamaのデータをOSにキャッシュします。

cat okuyamaのデータファイル > /dev/null
そして同じようにレスポンスを測定。測定中の状態は

top - 20:04:32 up 5 days, 9:49, 2 users, load average: 0.66, 0.53, 0.35
Tasks: 131 total, 1 running, 130 sleeping, 0 stopped, 0 zombie
Cpu0 : 25.7%us, 10.9%sy, 0.0%ni, 58.4%id, 0.0%wa, 0.0%hi, 5.0%si, 0.0%st
Cpu1 : 18.8%us, 20.8%sy, 0.0%ni, 54.5%id, 0.0%wa, 0.0%hi, 5.9%si, 0.0%st
Cpu2 : 19.2%us, 19.2%sy, 0.0%ni, 57.6%id, 0.0%wa, 0.0%hi, 4.0%si, 0.0%st
Cpu3 : 24.8%us, 23.8%sy, 0.0%ni, 26.7%id, 0.0%wa, 1.0%hi, 23.8%si, 0.0%st
Mem: 4033988k total, 4003084k used, 30904k free, 4624k buffers
Swap: 8388600k total, 35956k used, 8352644k free, 1584616k cached
見事にCPUが全て動いていて、iowaitもなくなりました。
スループットは前回をさらに越えて6万6千QPSほど出ました。


この結果からOSのキャッシュが原因でインメモリモードよりもファイル永続化モードのほうが良い結果が
出たことがわかりました。
このことから、OSキャッシュから落ちてしまった場合を想定した取り組みが必要なことがわかりました。
その対応方法の検討はまた後日。
本日はここまで。

分散キーバリューストアokuyamaの性能をまともなマシンで測ってみた

いままで分散キーバリューストアのokuyamaの性能を計測していたのは
Dellのノートパソコンか、10年くらい前のPCか、AMD2Coreのデスクトップだった。
自由に触れるマシンがその程度しかなかったんだけど、今回DellXeon搭載のマシン(PowerEdgeT110)を
触る機会があったので、okuyamaの性能を測定してみました。

マシンスペックと構成は以下

本当はもう1台一番右のマシンと同スペックのマシンが用意できればDataNodeとSlaveDataNodeを
別々で配置したかったが、マシンがないので、同居させた。
後は、スイッチが100Mなのが残念。。。orz

key値は20〜25byte、valueは100byte〜105byteのスレッド単位でユニークな値
この構成でクライアントで1分間にset出来る値と、get出来る値を同時実行数(Thread)を
上げながら計測した。
okuyamaが持つ永続化の2モードそれぞれで計測
結果としては以下となった。


トランザクションログでの永続化モード(稼動中はインメモリ)
[set]
40スレッド同時実行と45スレッド同時実行で
ほぼ同様の結果となりそれ以上は総登録件数に伸びが見られなかった

■1分当たりの総登録件数
->登録数:1782000 件

■1秒当たりのクエリー実行数(QPS)
->QPS:29700 QPS


[get]
50スレッド同時実行と60スレッド同時実行で
ほぼ同様の結果となりそれ以上は総取得件数に伸びが見られなかった

■1分当たりの総取得件数
->登録数:2946000 件

■1秒当たりのクエリー実行数(QPS)
->QPS:49400QPS

上記の2つの場合は両方ともMasterNode、DataNode(Slave含む)ともCPUは約50%程度の使用状況であった。
クライアント側のCPUはほぼ100%のため、これ以上の計測は出来なかった。



トランザクションログ+データファイルでの永続化モード(稼動中はKey値のみインメモリ、Valueはファイル)
[set]
50スレッド同時実行と60スレッド同時実行で
ほぼ同様の結果となりそれ以上は総登録件数に伸びが見られなかった

■1分当たりの総登録件数
->登録数:1560000 件

■1秒当たりのクエリー実行数(QPS)
->QPS:26000 QPS


[get]
50スレッド同時実行と60スレッド同時実行で
ほぼ同様の結果となりそれ以上は総取得件数に伸びが見られなかった

■1分当たりの総取得件数
->登録数:3057000 件

■1秒当たりのクエリー実行数(QPS)
->QPS:50950PS

上記の場合はset,get共にMasterNodeの負荷はトランザクションモードとかわらずCPU使用率50%程度。
DataNode(Slave含む)はset時はCPUは約30%程度の使用状況であったが、ディスクのI/O状況がかなり高くなった。
topコマンドのiowaitがcpu単位で50%程度
get時はCPU負荷が50%程度、ディスクのI/Oがほとんどなくなった。
これはおそらく、OSのキャッシュにファイルイメージが乗ってしまっているので、起こる現象だと思われる。
そのことを示すかのように、QPS値がメモリ時を超えてしまっている。

set時の性能差が完全ファイルモードとインメモリモードで3000QPS程度なので、保存できるデータ容量を考えると、
完全ファイルモードの方がサーバリソースの効率化は図れそうです。
しかしメモリに乗り切らないファイルサイズになると、get性能が落ちる可能性がある。(後日試す予定)


こんな感じの性能になりました。
実際はDataNodeが1台のマシンに乗ってしまっているので、これを複数台に分けた場合の性能は調べたいな〜。
後は、スイッチはせめてギガが欲しい〜〜。欲を出すならSSDとかも!!

と夢は膨らみますが、実際は1台のクライアントマシンでスレッド数を増加させているので、これを複数台にした場合の性能を
まずは調べて見ないと一概にどこがネックなのかわかりません。
まあでも、8〜9万円程度のサーバ2台でこれだけの性能が出せたので、少し満足。

7月のOSC京都でセミナーもすることになったし、そのネタ(デモ??)にも使えるかな〜

okuyama-0.6.3リリース&KVSを業務システムに使用したフィードバック

okuyama-0.6.3をリリースしました。


今回の変更ポイントは
■データノードをmemcacheのノードとして利用可能に


  okuyamaはマスターノード、データノード、トランザクションノードで


  構成されているんですが、ただ単にデータをキャッシュとして保存する場合は


  マスターノードとトランザクションノードは不要で、データノードだけで可能です。


  なので、データノードもmemcacheプロトコルで会話出来るようにしました。


  対応メソッドはset,get,add,deleteです。


  ファイル永続化モード(トランザクションログでの永続化、データ完全ファイル保存での永続化を選べます)で


  起動できるのでノードを落としてもデータは消えません(どこかで聞いたことあるような機能ですね。。。)


  まあ、じつは前の日記(2010/03/30 memcache速っ!!)で書いたのですが、


  okuyamaの「マスターノード=>データノード」の構成でmemcacheに戦いを挑んだところボロ負けしたんですよね。。。


  ちょっと悔しかったんですよね。。。


  何とか単ノード、データ永続化の条件で勝ちたくて。。。








  memcacheはsetで6500QPS出てたので、okuyamaデータノード(永続化モード)は








  5500QPS!!!!!






  ・・・・
  負けてるやん。。。。orz


  まあこんなもんでしょ。
  やっぱmemcache速いですね。


 memcacheの変わりとして永続化可能なストレージとして使えるので良ければ使ってやってください。






  残りの変更点は


■Key値からHash値を求めるロジックを変更


  okuyamaは渡されたKey値をハッシュ値にして内部では扱っているのですが、ハッシュ値化する


  ロジックが衝突を生む可能が高かったので、変更しました。


  ただ今までのデータが使えなくなるので、変更せずに利用する場合はReadMe.txtをご覧ください。




■データ登録メソッドsetValue時の処理速度を20%向上


  従来の「マスターノード=>データノード」の構成時のsetValueの処理効率を20%向上しました。


  従来マスターノードはデータノードへ登録データ送信中は何もせずにデータノードの返答を待っていたのですが、


  この時間が無駄なので待ち時間を利用してスレーブデータノードへの送信準備をするように変更しました。




■バグFix
  いくつかのバグを修正






以上がリリース内容です。




やっぱり業務で使いはじめたのでそこからのフィードバックが大きいです。


いくつかのバグはそのフィードバックからでました。


業務システムではトランザクションはかなりの確率で


必要です。これがないと満足にデータの更新もできません。


okuyamaの場合は分散ロックが使えるのでこれで一意性を


確保しています。

後、良くない点としては小さなデータ(メタデータのような文字情報)から

大きなデータ(ファイル)まで全て1組のokuyamaに登録していますが、


あまり効率が良くないですね。


okuyamaは1データ当たりの登録可能なサイズが決まっています(ImdstDefine.javaのsaveDataMaxSize変数が保存可能なbyte数)


そのサイズを超えるデータは登録できないので、そのサイズを超えるようなデータ(長い文字列や、ファイルなど)は


分割して別キー値(このキー値はシステムが独自で生成しています)を付けて保存しています。


分割するので当然取得時は別々に取得しないといけないんですが、この効率が悪いです。


本来なら保存可能なサイズの最適値をあらかじめ予想してokuyamaを構成すればもっと効率良くなると思います。
(大きなファイルを登録するクラスターと、小さなメタデータを保存するクラスターなど)


でもそうなるとアプリ側で制御が煩雑になる可能性なんかも考えられて。。。


最適な配置問題は大きな課題ですね。
分散ファイルシステムにも注目が集まっているし、周りのお客さんで実際に求めているかたもいるので、
調査していきます。


 

okuyama ver0.6.2をリリース & Fuseでkvsファイルシステム作成中

久々に日記

分散KVS「okuyama」のVersion-0.6.2をリリースしました。
今回のリリース内容は主にmemcache対応と、データノードリカバリー時の
データ転送方式の変更です。


memcache対応は以下の3点です。
    1.memcacheのメソッドであるaddに対応
        未登録データの場合のみ登録可能なmemcacheのaddコマンドに対応


    2.memcacheのメソッドであるdeleteに対応
        memcacheコマンドであるデータ削除用コマンドdeleteに対応


    3.memcacheのflag登録に対応
        memcacheコマンドでset、add時に指定するflagに対応
        get時に登録flagを返却




リカバリー時の転送方式の変更は
従来はノードダウンからのリカバー時にレプリケーションノードから1通信で全ての登録データ取得していたのを、
分割して取得するように変更しました。これは大きなデータが登録されている場合に、送信側、受信側でメモリに
のりきらずにリカバーに失敗する場合があったためで、それを使用可能なメモリの残量を確認しながら、転送し
リカバリーするように変更しました。




リリース内容はこんなもので、


後はFuseで現在Linux用のファイルシステム作成中です。
Fuseは結構前から興味があったんですが、あまり触れてなくて、そろそろ真剣にやろうと決意。
とりあえずokuyamaをストレージにするような構成で作成中です。


うまくいけば、RAIDなしで冗長化された大規模なストレージを複数マシンで共有出来るかなと。
結構この手のプロダクトはあるようなので、その辺りもリサーチしながら進めます。




使用プロダクトはGreeの藤本さんというかたが作成されたPHP用のFuseプロダクトを使用させていただいております。


PHPなのでコンパイルいらずでスイスイ進めれるという利点を生かして実装中。
とりあえず簡単なディレクトリの閲覧、ファイルのReadまでは出来たので、また日記に書いていきます。