16

警告:背景情報はかなり長いです。背景情報の前に質問が必要だと思われる場合は、一番下までスキップしてください。これにかかる時間を感謝します!

私はウェブのいたるところにいて(グーグルを読んで)、良い答えを見つけられませんでした。はい、erlang.orgサイトにはMnesiaのドキュメントへのリンクや参照がたくさんありますが、それらのリンクでさえバージョン炎に悩まされています。

したがって、現在接続しているnode()がテーブルセットの所有者と同じである最も単純なケースでは、バックアップ/復元が機能します。例えば:

$ erl -sname mydatabase

> mnesia:start().
> mnesia:create_schema(...).
> mnesia:create_table(...).
> mnesia:backup("/tmp/backup.bup").
> mnesia:restore("/tmp/backup.bup", [{default_op, recreate_tables}]).

ねえ、これはうまくいきます!

ただし、データベースが実際にリモートノード()またはリモートメイティングのリモートノード()で実行されている場合は、次の方法でバックアップを開始する必要があります。

$ erl -sname mydbadmin

> rpc:call(mydatabase@host, mnesia, backup, ["/tmp/backup.bup"]).
> rpc:call(mydatabase@host, mnesia, restore, ["/tmp/backup.bup", [{default_op, recreate_tables}]]).

もちろん、これも簡単でした。今ここにトリッキーなものがあります....

  • 毎日バックアップを取っているとしましょう。そして、mnesiaデータベースサーバーが停止し、ハードウェアの交換を余儀なくされます。DBをそのまま復元する場合は、新しいハードウェアに以前と同じ名前を付ける必要があります。また、ノードにも同じ名前を付ける必要があります。
  • ハードウェアやnode()の名前を変更したい場合、または別のマシンで復元したい場合は、node_changeプロセスを実行する必要があります。(こことmnesiaドキュメントで説明されています)

しかし、ここで物事は複雑になります。erlangとmnesiaの専門家である私の知人は、mnesiaの複製には重大な欠陥があり、使用すべきではないと示唆しています(現在、私が知っている代替手段はなく、より良いバージョンを実装する可能性はありますが、そうではありません。おそらく)

したがって、RAMおよびディスクベースのテーブルを複製している2つのnodes()があります。デフォルトのBackupModを使用して、データベースを標準バックアップで定期的にバックアップするというポリシーを維持しています。そしてある日、マネージャーがバックアップを確認するように依頼します。データベースを復元しようとした場合にのみ、次のようになります。

{atomic,[]}

そして、ドキュメントによると、これはエラーがなかったことを意味します...それでもテーブルは復元されませんでした。

change_nodeプロシージャを実行したくない場合は、node()とホスト名が一致する必要があるため、データがバックアップされたマシンと一致するようにホスト名と-snameパラメータを変更することを覚えておいてください。ただし、今回は奇妙なエラーが発生します。

{aborted,{'EXIT',{aborted,{bad_commit,{missing_lock,mydatabase@otherhost}}}}}

それでもchange_nodeプロシージャを実行したくないので、サーバーをすばやくクローン復元して、2台の同様のマシンを使用します。次に、本番サーバーに合わせて適切な名前を付けます。そして、復元プロセスを開始します。ユーレカ!これで、復元サーバーに実際の作業データがあります。

これで道のりは終わりだと言いたいのですが…まだ質問はしていませんし、SOのポイントは……だからここにあるのでしょうか?

質問:複製されたMnesiaノードのクラスターから取得したバックアップを復元する場合、他のノードが無視されるかバックアップから削除されるようにファイルを変更するにはどうすればよいですか(change_nodeプロシージャと同様)。

少し違った質問:単一のnode()でレプリケートされたmulti-node()mnesiaデータベースを復元するにはどうすればよいですか?

4

2 に答える 2

12

この問題は、単純な質問に関連するMnesiaの質問のより広いカテゴリに分類されると思います。

Mnesiaノードの名前を変更するにはどうすればよいですか?

データベースが大きくない場合の最初の最も簡単な解決策は、mnesia:traverse_backup関数を使用することです(Mnesiaユーザーガイドを参照)。以下は、Mnesiaユーザーガイドの例です。

change_node_name(Mod, From, To, Source, Target) ->
    Switch =
        fun(Node) when Node == From -> To;
           (Node) when Node == To -> throw({error, already_exists});
           (Node) -> Node
        end,
    Convert =
        fun({schema, db_nodes, Nodes}, Acc) ->
                {[{schema, db_nodes, lists:map(Switch,Nodes)}], Acc};
           ({schema, version, Version}, Acc) ->
                {[{schema, version, Version}], Acc};
           ({schema, cookie, Cookie}, Acc) ->
                {[{schema, cookie, Cookie}], Acc};
           ({schema, Tab, CreateList}, Acc) ->
                Keys = [ram_copies, disc_copies, disc_only_copies],
                OptSwitch =
                    fun({Key, Val}) ->
                            case lists:member(Key, Keys) of
                                true -> {Key, lists:map(Switch, Val)};
                                false-> {Key, Val}
                            end
                    end,
                {[{schema, Tab, lists:map(OptSwitch, CreateList)}], Acc};
           (Other, Acc) ->
                {[Other], Acc}
        end,
    mnesia:traverse_backup(Source, Mod, Target, Mod, Convert, switched).

view(Source, Mod) ->
    View = fun(Item, Acc) ->
                   io:format("~p.~n",[Item]),
                   {[Item], Acc + 1}
           end,
    mnesia:traverse_backup(Source, Mod, dummy, read_only, View, 0).

ここで最も重要な部分は{schema, db_nodes, Nodes}、dbノードの名前を変更したり置き換えたりできるタプルの操作です。

ところで、私は過去にその関数を使用しましたが、バックアップ用語の形式がmnesiaバージョン間で変わることに気づきましたが、おそらくそれは単に私が悪いコードを書いただけでした。確認したい場合は、小さなMnesiaデータベースのバックアップログを印刷して、バックアップ用語の形式を確認してください。

お役に立てれば!

于 2012-04-15T20:28:48.927 に答える
2

これを機能させるのにかなり苦労したので、私が行った手順を共有します。

復元する分散システムのノードを(単一ノードに)バックアップすることから始めます。

> mnesia:backup("/path/to/backup").

change_node_name復元先のノードで、次の適応が利用可能であることを確認してください。

-module(move_backup).
-export([set_node_name/4]).                                                                                                    

set_node_name(From, To, Source, Target) ->
    Switch =
        fun (Nodes) ->
                case lists:member(From, Nodes) of
                    true -> [To];
                    false -> []
                end
        end,
    Convert =
        fun({schema, db_nodes, Nodes}, Acc) ->
                {[{schema, db_nodes, Switch(Nodes)}], Acc};
           ({schema, version, Version}, Acc) ->
                {[{schema, version, Version}], Acc};
           ({schema, cookie, Cookie}, Acc) ->
                {[{schema, cookie, Cookie}], Acc};
           ({schema, Tab, CreateList}, Acc) ->
                Keys = [ram_copies, disc_copies, disc_only_copies],
                OptSwitch =
                    fun({Key, Val}) ->
                            case lists:member(Key, Keys) of
                                true -> {Key, Switch(Val)};
                                false-> {Key, Val}
                            end
                    end,
                {[{schema, Tab, lists:map(OptSwitch, CreateList)}], Acc};
           (Other, Acc) ->
                {[Other], Acc}
        end,
    mnesia:traverse_backup(Source, Target, Convert, switched).

バックアップを変換します。

> move_backup:set_node_name('before@host', 'after@host', "/path/to/backup", "/path_to_backup_converted").

新しいノードは完全に空であると想定します(そうでない場合は、default_op引数を変更することをお勧めします)。2つのオプションがあります。1つはライブ復元用です。

> mnesia:restore("/path/to/backup_converted", [{default_op, recreate_tables}]).

これは素晴らしいですが、大規模なデータベースがある場合は大量のメモリを使用する可能性があります(私の場合は約10GBであったため、メモリ不足の例外が発生しました)。別の方法は、フォールバックをインストールして、シェルを再起動することです。

> mnesia:install_fallback("/path/to/backup_converted").
> q().

次に、シェルを再起動すると(正しいノード名を使用していると仮定して)、データベース全体がインポートされます。

于 2019-03-06T14:34:33.020 に答える