Wie verhindere ich Änderungen an meiner PostgreSQL-Datenbank?

8

Meine Schritte:

  1. Führen Sie das Finale pg_dumpallauf einem Server ausprod-server-old
  2. prod-server-oldFür immer herunterfahren .
  3. Kopieren Sie die Ausgabe auf einen anderen Server ( prod-server-new)
  4. Stellen Sie dort die Datenbank wieder her.
  5. Der gesamte Verkehr geht prod-server-newjetzt

Wie kann ich Änderungen an der Datenbank während pg_dumpall(zwischen Schritt 1 und Schritt 2) vermeiden, damit Änderungen während dieser Zeit nicht verloren gehen können?

In meinem Fall ist es 100% OK, eine kleine Ausfallzeit zu haben.

Es gibt mehrere Datenbanken im "Cluster" (übrigens mag ich das Wort "Cluster" nicht. Ich denke, die meisten Leute denken, ein "Cluster" ist eine Gruppe von mehreren Computern, aber in diesem Fall bedeutet dies einen Postgres-Server, der hält mehrere Datenbanken).

Meine Frage wurde als mögliches Duplikat für "Postgres-Datenbank vorübergehend schreibgeschützt machen (zum Durchführen von Volume-Snapshots)" markiert. Ich denke nicht, dass es ein Duplikat ist, da es in meinem Fall anders ist, da ich nicht nach einem temporären schreibgeschützten Zustand frage.

guettli
quelle
Sie können die logische Replikation ausprobieren . Die Quellendatenbank kann bis zur Umschaltung weiter schreiben.
Sahap Asci

Antworten:

3

Zwei Möglichkeiten, dies zu tun:

  • Wenn Ihnen Ausfallzeiten nichts ausmachen (einfacher Weg):

Widerrufen Sie das connectPrivileg für die publicGruppe. Dadurch wird verhindert, dass sich alle außer den Superusern verbinden. Starten Sie dann den Server neu oder beenden Sie alle Verbindungen . Fahren Sie dann mit der Sicherung mit einem Superuser-Konto fort.

REVOKE CONNECT TO DATABASE (database) FROM public
  • Wenn Sie sich für Ausfallzeiten interessieren:

Versetzen Sie Ihre Datenbank in den schreibgeschützten Modus:

ALTER DATABASE (database) SET default_transaction_read_only = true;

Fahren Sie fort mit pg_dumpall. Kein Neustart erforderlich und keine Ausfallzeiten.

Natürlich müssen Sie dies für jede Datenbank wiederholen, die Sie "sperren" möchten. Wenn Sie über eine signifikante Anzahl von Datenbanken verfügen, können Sie den gesamten Cluster schreibgeschützt machen: default_transaction_read_only = on;Legen Sie dies in Ihrer postgresql.conf fest und laden Sie den postgres-Dienst neu.

Bitte beachten Sie, dass ich keinen dieser Befehle getestet habe. Fahren Sie auf eigenes Risiko fort.

anto418
quelle
Beachten Sie, dass schreibgeschützte Transaktionen nur Standard sind . Eine App kann einfach eine Lese- / Schreibtransaktion anfordern. Stellen Sie sicher, dass Ihre App dies nicht tut.
Craig Ringer
Ich dachte noch einmal darüber nach. Gibt pg_dumpall diesen schreibgeschützten Status aus? Dies würde bedeuten, dass ich die Datenbank wieder in den Schreibmodus versetzen muss, nachdem ich den Speicherauszug wiederhergestellt habe prod-server-new. Oder werden die obigen Einstellungen nicht von pg_dumpall ausgegeben?
Guettli
2

Eine Umgehung:

Ändern Sie den Port von PostgreSQL auf prod-server-old. Auf diese Weise ist es unwahrscheinlich, dass Clients während eine Verbindung zur Datenbank herstellen pg_dumpall --port=OTHER_PORT.

guettli
quelle
2

Ich bin ein SQL Server-Administrator (nicht Postgres), daher bin ich mir nicht 100% sicher, aber wenn Ausfallzeiten kein Problem darstellen, können Sie:

  • alle Verbindungen beenden
  • Remote-Anmeldungen verhindern
  • Melden Sie sich beim Datenbankserver an und melden Sie sich als Superuser bei der Datenbank an
  • mach den pg_dumpall
  • Aktivieren Sie Remote-Anmeldungen erneut

?

SEarle1986
quelle
Bitte erläutern Sie "Remote-Anmeldungen verhindern"
guettli
0

Verwenden von Triggern:

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 $$;

Dann machen Sie die Datenbank schreibgeschützt:

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

und um es wieder bearbeitbar zu machen:

select set_db_readonly('');
Abelisto
quelle