mnesiaのレプリケーションがどうなっているのかちょっと調べてみた

  • 問題
    • N-act構成にしたとき、ネットワークが切れてまたつながった場合にデータ不整合が起きるか。復旧の方法はあるか。
  • 結論
    • 起きる。簡単な復旧方法はなさげ。
    • Mnesiaレプリカのあるノードが一時的に通信不能になり、その間にMnesiaオリジナル*1が不整合の起きるレコード更新を行うと、Mnesiaレプリカが復帰できない。
  • set_master_nodes/2は微妙(ざっとリファレンスを見た限りでは、不整合を解決する方法はこれくらいしかなさげ)
  • 使ったマシン
    • dom0 -> -name a@192.168.0.72
    • domU -> -name a@192.168.0.31
    • どちらもdebian lenny@linux-2.6.26-xen/ xen 3.2(要はlenny最新版)

まずは準備。
dom0側

[kuenishi@] $ erl -name a@192.168.0.72 -setcookie hoge 
Erlang (BEAM) emulator version 5.6.3 [source] [64-bit] [smp:4] [async-threads:0] [kernel-poll:false]

Eshell V5.6.3  (abort with ^G)
(a@192.168.0.72)1> mnesia:start().
ok

domU

kuenishi@domU1debian:~$ erl -name a@192.168.0.31 -setcookie hoge
Erlang (BEAM) emulator version 5.6.3 [source] [64-bit] [async-threads:0] [kernel
-poll:false]

Eshell V5.6.3  (abort with ^G)
(a@192.168.0.31)1> net_adm:ping('a@192.168.0.72').
pong
(a@192.168.0.31)2> mnesia:create_schema([node(), 'a@192.168.0.72']).
ok
(a@192.168.0.31)3> rd( user, {id, age}).
user
(a@192.168.0.31)5> mnesia:start().
ok
(a@192.168.0.31)6> mnesia:create_table( user, [
(a@192.168.0.31)6> {ram_copies, [node(), 'a@192.168.0.72']},
(a@192.168.0.31)6> {attributes, record_info( fields, user )}
(a@192.168.0.31)6> ]).
{atomic,ok}

これでmnesiaが準備できたので、両方のノードでひとつずつレコード作成。

domU

(a@192.168.0.31)7> mnesia:transaction(fun()-> mnesia:write(#user{id=1,age=1}) en
d).
{atomic,ok}
(a@192.168.0.31)8> mnesia:dirty_read(user,1).
[#user{id = 1,age = 1}]

dom0

(a@192.168.0.72)5> rd(user, {id,age}).
user
(a@192.168.0.72)6> mnesia:transaction(fun()->mnesia:write(#user{id=2,age=2}) end).
{atomic,ok}
(a@192.168.0.72)7> mnesia:dirty_read(user,2). 
[#user{id = 2,age = 2}]
(a@192.168.0.72)9> mnesia:dirty_read(user,1).
[#user{id = 1,age = 1}]

これでどっちも見えている。ここで、両者を接続するネットワークを切断(domU側のeth0を止めた)。
結果は書かないけど、この時点でのdirty_readはどっちもできていた。

ネットワークが切断された状態で更新をかける。
domU

(a@192.168.0.31)12> mnesia:transaction(fun()-> mnesia:write(#user{id=1,age=231})
 end).

=ERROR REPORT==== 22-Nov-2008::12:11:03 ===
** Node 'a@192.168.0.72' not responding **
** Removing (timedout) connection **
{atomic,ok}

タイムアウト?まで少し時間かかるけど、コミットできちゃう。dom0でも同様にコミットできてしまった。ここでネットワークが切れたことを検出しているみたい。

で、ここでもっかいifup eth0してネットワークをつなぐ。ネットワークが繋がっても、明示的にbeam同士を接続しないといけないらしい。
dom0側で

(a@192.168.0.72)18> mnesia:change_config(extra_db_nodes, ['a@192.168.0.31']).

=ERROR REPORT==== 22-Nov-2008::12:23:42 ===
Mnesia('a@192.168.0.72'): ** ERROR ** mnesia_event got {inconsistent_database, running_partitioned_network, 'a@192.168.0.31'}

=ERROR REPORT==== 22-Nov-2008::12:23:42 ===
Mnesia('a@192.168.0.72'): ** ERROR ** mnesia_event got {inconsistent_database, starting_partitioned_network, 'a@192.168.0.31'}
{ok,['a@192.168.0.31']}
(a@192.168.0.72)19> 

げげっ。domU側でも何かでてる。

(a@192.168.0.31)21> 
=ERROR REPORT==== 22-Nov-2008::12:23:42 ===
Mnesia('a@192.168.0.31'): ** ERROR ** mnesia_event got {inconsistent_database, running_partitioned_network, 'a@192.168.0.72'}
(a@192.168.0.31)21> 

というわけで、問題がいくつか。

  • ネットワークが切れて、不整合を起こすコミットが成功して、ネットワークがまた繋がった場合に、不整合を解決する方法
  • ネットワークが切れて接続できないノードに対しても更新要求を送るので、タイムアウトまで待ってしまい、結果的に(多分)qpsが下がる

(追記)
mem_copiesだろうとdisc_copiesだろうと、不整合が起きたままの状態で同じテーブルを参照することはできるらしい。レコードを上書きすれば不整合はなくなる。

ram_copies <-> ram_copies と disc_copies <-> ram_copies は2つ目を後から起動しても上手くいくのですが disc_copies <-> disc_copies のレプリケーションは一度 mnesia を stop させないとダメっぽい

      • な、なんだってー(ry

*1:という言い方が合ってるかどうかは別にして