web-dev-qa-db-ja.com

PostgreSQLデータベースへの変更を防ぐにはどうすればよいですか?

私のステップ:

  1. サーバーで最後のpg_dumpallを実行するprod-server-old
  2. prod-server-oldを永久にシャットダウンします。
  3. 出力を別のサーバーにコピーする(prod-server-new
  4. そこでdbを復元します。
  5. すべてのトラフィックはprod-server-newに今行きます

pg_dumpall(step1とstep2の間)の間にデータベースへの変更を回避して、この間の変更が失われないようにするにはどうすればよいですか?

私の場合、ダウンタイムが短いことは100%OKです。

「クラスター」にはいくつかのデータベースがあります(ところで、「クラスター」という言葉は好きではありません。「クラスター」は複数のコンピューターのグループだと思う人が多いと思いますが、この場合、1つのPostgresサーバーがいくつかのデータベース)。

私の質問は「Postgresデータベースを一時的に読み取り専用にする(ボリュームスナップショットを実行するため)」と重複する可能性があるとマークされました。一時的な読み取り専用の状態を要求しないため、私の場合は異なるため、それは重複しているとは思わない。

8
guettli

1つの回避策:

prod-server-oldでPostgreSQLのポートを変更します。この方法では、クライアントがpg_dumpall --port=OTHER_PORT中にDBに接続することはほとんどありません。

2
guettli

それを行う2つの方法:

  • ダウンタイムを気にしない場合(簡単な方法):

connectグループに対するpublic特権を取り消します。これにより、スーパーユーザー以外の全員が接続できなくなります。次に、サーバーを再起動するか、 すべての接続を終了 し、スーパーユーザーアカウントを使用してバックアップを続行します。

REVOKE CONNECT TO DATABASE (database) FROM public
  • ダウンタイムを気にする場合:

データベースを読み取り専用モードにします。

ALTER DATABASE (database) SET default_transaction_read_only = true;

を進めます pg_dumpall。再起動は必要なく、ダウンタイムもありません。

もちろん、「ロック」したいすべてのデータベースでこれを繰り返す必要があります。かなりの数のデータベースがある場合は、クラスター全体を読み取り専用にすることができます:set default_transaction_read_only = on; postgresql.confで、postgresサービスをリロードします。

これらのコマンドはまだテストしていません。自己責任で進めてください。

3
anto418

私はSQL Server管理者(Postgresではありません)なので、100%確実ではありませんが、ダウンタイムが問題にならない場合は、次のことができます。

  • すべての接続を殺す
  • リモートログオンを防止する
  • dbサーバーにログオンし、スーパーユーザーとしてdbにログインします。
  • pg_dumpallを実行します
  • リモートログオンを再度有効にする

2
SEarle1986

トリガーの使用:

create function __fn_db_readonly() returns event_trigger language plpgsql as $$
begin
  raise exception '%', 'Database is in read-only mode';
end $$;

create function _fn_db_readonly() returns trigger language plpgsql as $$
begin
  raise exception '%', TG_ARGV[0];
end $$;

create function set_db_readonly(amessage text) returns void language plpgsql as $$
declare
  t record;
  tbl_name text;
  stm text;
begin
  if coalesce(amessage, '') = '' then
    -- Database
    drop event trigger __tg_ro_database1;
    drop event trigger __tg_ro_database2;
    drop event trigger __tg_ro_database3;
    -- Data
    for t in (select * from pg_tables where not schemaname in ('pg_catalog', 'information_schema')) loop
      tbl_name := format('%I.%I', t.schemaname, t.tablename);
      stm := 'drop trigger if exists _tg_ro on ' || tbl_name;
      execute stm;
    end loop;
  else
    -- Data
    for t in (select * from pg_tables where not schemaname in ('pg_catalog', 'information_schema')) loop
      tbl_name := format('%I.%I', t.schemaname, t.tablename);
      stm := format('create trigger _tg_ro before insert or update or delete on %s execute procedure _fn_db_readonly(%L)', tbl_name, amessage);
      execute stm;
    end loop;
    -- Database
    create event trigger __tg_ro_database1 on ddl_command_start execute procedure __fn_db_readonly();
    create event trigger __tg_ro_database2 on table_rewrite execute procedure __fn_db_readonly();
    create event trigger __tg_ro_database3 on sql_drop execute procedure __fn_db_readonly();
  end if;
  return;
end $$;

次に、データベースを読み取り専用にするには:

select set_db_readonly('Database is in read-only mode due to maintance.');

もう一度編集可能にするには:

select set_db_readonly('');
0
Abelisto