PostgreSQL
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> PostgreSQL

Sao lưu gia tăng PostgreSQL và phục hồi điểm trong thời gian

PostgreSQL đi kèm với khả năng thực hiện sao lưu gia tăng và thu hồi từng thời điểm ngay lập tức. Đọc tiếp để tìm hiểu thêm về các cài đặt và quy trình để đạt được điều này.

Nó bắt đầu với tệp WAL

WAL là viết tắt của Write Ahead Log . WAL được sử dụng trong gần như tất cả các hệ thống RDBMS hiện đại để cung cấp các giao dịch nguyên tử và lâu dài.

Các thay đổi đối với dữ liệu có trong cụm cơ sở dữ liệu PostgreSQL được quản lý bởi quy trình máy chủ PostgreSQL duy nhất chỉ có thể thực hiện được thông qua các giao dịch. Các sửa đổi được thực hiện đối với dữ liệu bằng các giao dịch được ghi lại như một thứ tự có thứ tự của bản ghi WAL . Các bản ghi này được viết thành các tệp có độ dài cố định được gọi là tệp phân đoạn WAL hoặc đơn giản là tệp WAL .

Tệp WAL tồn tại trong $PGDATA/pg_wal , trong đó $PGDATA là thư mục dữ liệu cho cụm cơ sở dữ liệu. Ví dụ trên cài đặt Debian mặc định, thư mục lưu trữ WAL cho cụm chính là /var/lib/postgresql/10/main/pg_wal . Đây là cách nó trông như thế này:

# pwd
/var/lib/postgresql/10/main/pg_wal
# ls -l
total 278532
-rw------- 1 postgres postgres 16777216 May  7 08:48 00000001000000000000000B
-rw------- 1 postgres postgres 16777216 May  7 10:08 00000001000000000000000C
-rw------- 1 postgres postgres 16777216 May  7 10:08 00000001000000000000000D
-rw------- 1 postgres postgres 16777216 May  7 10:08 00000001000000000000000E
-rw------- 1 postgres postgres 16777216 May  7 10:08 00000001000000000000000F
-rw------- 1 postgres postgres 16777216 May  7 10:08 000000010000000000000010
-rw------- 1 postgres postgres 16777216 May  7 10:08 000000010000000000000011
-rw------- 1 postgres postgres 16777216 May  7 10:08 000000010000000000000012
-rw------- 1 postgres postgres 16777216 May  7 10:08 000000010000000000000013
-rw------- 1 postgres postgres 16777216 May  7 10:08 000000010000000000000014
-rw------- 1 postgres postgres 16777216 May  7 10:08 000000010000000000000015
-rw------- 1 postgres postgres 16777216 May  7 10:08 000000010000000000000016
-rw------- 1 postgres postgres 16777216 May  7 10:08 000000010000000000000017
-rw------- 1 postgres postgres 16777216 May 16 20:52 000000010000000000000018
-rw------- 1 postgres postgres 16777216 May 16 20:56 000000010000000000000019
-rw------- 1 postgres postgres 16777216 May 26 08:52 00000001000000000000001A
-rw------- 1 postgres postgres 16777216 Jun  2 09:59 00000001000000000000001B
drwx------ 2 postgres postgres     4096 Mar 30 10:06 archive_status

Các tệp WAL được tạo dần dần, theo trình tự, bắt đầu từ quá trình xử lý. Chúng tiếp tục được tạo miễn là các sửa đổi xảy ra với cụm từ. Cơ chế tệp WAL cần thiết cho hoạt động của PostgreSQL và không thể tắt.

Sau khi các thay đổi được ghi lần đầu tiên dưới dạng bản ghi WAL, chúng phải được áp dụng cho việc biểu diễn trên đĩa của chính dữ liệu. Quá trình này được gọi là điểm kiểm tra và diễn ra trong nền tự động (nó cũng có thể được thực hiện theo cách thủ công). Điểm cho đến khi điểm kiểm tra được thực hiện được gọi là điểm REDO . Checkpointing cũng là một phần thiết yếu của kiến ​​trúc Postgres và không thể tắt.

Lưu giữ Tệp WAL

Trong quá trình hoạt động bình thường của máy chủ PostgreSQL, các tệp WAL sẽ tiếp tục được ghi vào pg_wal danh mục. Nhưng tại sao lại có họ?

Một lý do là khôi phục sự cố. Nếu máy chủ PostgreSQL gặp sự cố và khởi động lại, nó sẽ bắt đầu áp dụng các thay đổi từ bản ghi WAL vào tệp dữ liệu (điểm kiểm tra) kể từ điểm REDO cuối cùng. Điều này đảm bảo rằng các tệp dữ liệu nhất quán với giao dịch hoàn thành cuối cùng.

Một lý do khác là liên quan đến nhân rộng phát trực tuyến. Tính năng sao chép truyền trực tuyến hoạt động bằng cách gửi các bản ghi WAL sang chế độ chờ máy chủ lưu trữ các điểm kiểm tra cục bộ và hoạt động tốt này. Standbys có thể tụt hậu so với máy chủ mà chúng đang nhân bản (được gọi là chính ). Ví dụ:nếu thiết bị chính đã tạo ra 100 WALrecords và chế độ chờ đã nhận và áp dụng 80 từ đầu tiên, thì 20 gần đây nhất bắt buộc phải có để chế độ chờ có thể nhận và áp dụng từrecord 81 trở đi.

Nhưng chắc chắn các tệp WAL rất cũ có thể bị xóa? Đúng. PostgreSQL có thể được cấu trúc để giữ lại các tệp WAL mới nhất và xóa các tệp cũ hơn. Có ba tùy chọn cấu hình liên quan:

  • wal_keep_searies - đặt số lượng tệp WAL tối thiểu gần đây nhất được lưu trong thư mục tệp WAL
  • max_wal_size - chỉ định tổng kích thước tối đa của các tệp WAL trong thư mục WAL. Nếu vượt quá mức này, những cái cũ hơn sẽ bị xóa. Tuy nhiên, có thể có những lý do (bao gồm cả giá trị cao cho wal_keep_segments ) có thể ngăn cài đặt này được thực hiện.
  • min_wal_size - chỉ định tổng kích thước tối thiểu cho các tệp WAL. Miễn là kích thước thực vẫn ở dưới giá trị này, thì sẽ không có tệp nào bị xóa.

Trong cuộc sống thực, không thể hoặc bắt buộc phải lưu trữ tất cả các tệp WAL trước đó dưới pg_wal thư mục.

Lưu trữ tệp WAL

Giá trị thực của các tệp WAL là chúng là một dòng các thay đổi có thể được ghi lại và phát lại để có được một bản sao nhất quán của một cụm PostgreSQL. đã tạo - archive_command tùy chọn cấu hình.

Tùy chọn này chỉ định một chuỗi lệnh shell được gọi sau mỗi tệp WAL được tạo. Dưới đây là một số ví dụ:

# Copy the file to a safe location (like a mounted NFS volume)
archive_command = 'cp %p /mnt/nfs/%f'

# Not overwriting files is a good practice
archive_command = 'test ! -f /mnt/nfs/%f && cp %p /mnt/nfs/%f'

# Copy to S3 bucket
archive_command = 's3cmd put %p s3://BUCKET/path/%f'

# Copy to Google Cloud bucket
archive_command = 'gsutil cp %p gs://BUCKET/path/%f'

# An external script
archive_command = '/opt/scripts/archive_wal %p'

Ngoài ra còn có 2 tùy chọn khác, phải được đặt:

# this must be "on" to enable WAL archiving
archive_mode = on

# has to be "replica" (default) or "logical" for WAL archiving
wal_level = replica

Nén WAL

Bạn có thể nén các tệp WAL trước khi sao chép chúng vào một vị trí lưu trữ lâu dài / an toàn. Tuy nhiên, có một tùy chọn được gọi là wal_compression . Việc bật tính năng này sẽ khiến PostgreSQL nén các bản ghi WAL riêng lẻ trong WALfiles. Bản thân các tệp WAL sẽ có cùng kích thước (thường là 16 MB), nhưng sẽ chứa một chuỗi các bản ghi nén thay vì các bản ghi thuần túy.

Lưu trữ Liên tục

Lưu trữ WAL còn được gọi là lưu trữ liên tục và đang có hiệu lực, sao lưu gia tăng .

Trước khi bắt đầu quá trình sao lưu gia tăng này, cần phải có một bản sao lưu đầy đủ. Điều này thiết lập đường cơ sở để các tệp WAL có thể được khôi phục từng bước. Có thể thực hiện sao lưu đầy đủ bằng cách:

  • tắt quy trình máy chủ Postgres và sao chép thư mục dữ liệu cụm (trong khi vẫn bảo toàn quyền) hoặc
  • sử dụng pg_basebackup trên máy chủ Postgres đang chạy.

Point-In-Time-Recovery (PITR)

PITR đề cập đến khả năng của PostgreSQL để bắt đầu từ việc khôi phục một bản sao lưu đầy đủ, sau đó tìm nạp dần dần và áp dụng các tệp WAL đã lưu trữ lên đến một dấu tối ưu được chỉ định.

Để thực hiện việc này, chúng ta phải tạo một tệp có tên “recovery.conf” trong thư mục dữ liệu restorecluster và khởi động máy chủ Postgres cho thư mục dữ liệu đó. Tệp recovery.conf chứa dấu thời gian đích và trông giống như sau:

restore_command = 'cp /tmp/demo/archive/%f "%p"'
recovery_target_time = '2019-06-04 14:10:00'

restore_command chỉ định cách tìm nạp tệp WAL theo yêu cầu của PostgreSQL. Nó là nghịch đảo của archive_command. recovery_target_time chỉ định thời gian cho đến khi chúng tôi cần thay đổi.

Khi quy trình máy chủ PostgreSQL khởi động và phát hiện ra recovery.conf tệp trong thư mục dữ liệu, nó khởi động ở một chế độ đặc biệt gọi là “chế độ khôi phục”. Khi ở chế độ khôi phục, các kết nối máy khách bị từ chối. Postgres tìm nạp các tệp WAL và áp dụng chúng cho đến khi đạt được mục tiêu khôi phục (trong trường hợp này là các thay đổi đối với dấu thời gian đã chỉ định). Khi đạt được mục tiêu, mặc định máy chủ tạm dừng phát lại WAL (có thể thực hiện các hành động khác). Tại thời điểm này, bạn được hỗ trợ để kiểm tra trạng thái khôi phục và nếu mọi thứ có vẻ ổn, hãy thoát khỏi chế độ khôi phục và tiếp tục hoạt động bình thường.

Hợp nhất tất cả

Tất cả chỉ là một mớ lý thuyết và văn bản, hãy thử dùng để xem nó hoạt động như thế nào trong thực tế.

Trước tiên, hãy khởi tạo một cụm mới:

/tmp/demo$ pg_ctl -D clus1 initdb
The files belonging to this database system will be owned by user "postgres".
This user must also own the server process.

The database cluster will be initialized with locale "C.UTF-8".
The default database encoding has accordingly been set to "UTF8".
The default text search configuration will be set to "english".

Data page checksums are disabled.

creating directory clus1 ... ok
creating subdirectories ... ok
selecting default max_connections ... 100
selecting default shared_buffers ... 128MB
selecting dynamic shared memory implementation ... posix
creating configuration files ... ok
running bootstrap script ... ok
performing post-bootstrap initialization ... ok
syncing data to disk ... ok

WARNING: enabling "trust" authentication for local connections
You can change this by editing pg_hba.conf or using the option -A, or
--auth-local and --auth-host, the next time you run initdb.

Success. You can now start the database server using:

    /usr/lib/postgresql/10/bin/pg_ctl -D clus1 -l logfile start

Chúng tôi cũng sẽ tạo một thư mục dùng làm vị trí lưu trữ an toàn của chúng tôi. Hãy gọi đây là “kho lưu trữ”.

/tmp/demo$ mkdir archive
/tmp/demo$ ls -l
total 8
drwxr-xr-x  2 postgres postgres 4096 Jun  4 14:02 archive
drwx------ 19 postgres postgres 4096 Jun  4 14:02 clus1

Chúng ta cần định cấu hình cài đặt lưu trữ mà chúng ta đã thảo luận trước đó, trước khi khởi động máy chủ. Vì vậy, hãy thêm phần sau vào cuối clus1/postgres.conf :

port = 6000
wal_level = logical
archive_mode = on
archive_command = 'cp %p /tmp/demo/archive/%f'
archive_timeout = 60

Lệnh lưu trữ của chúng tôi chỉ cần sao chép tệp WAL vào thư mục lưu trữ đã được tạo trước đó.

Chúng tôi cũng đã thêm archive_timeout thiết lập. Thông thường, tệp WAL chỉ được tạo khi có đủ bản ghi WAL để lấp đầy tệp WAL 16 MB. Điều này có nghĩa là đối với các máy chủ có ít lần ghi, bạn có thể phải đợi một thời gian dài để tệp WAL được tạo. Cài đặt archive_timeout cho Postgres biết rằng nó phải tạo tệp aWAL cứ sau nhiều giây, bất kể tệp đó đã đầy hay chưa.

Ở đây chúng tôi đã đặt giá trị này thành 60 (giây), nhưng điều này chỉ dành cho bản demo! Thông thường, bạn không bao giờ muốn giữ nó ở mức thấp như thế này.

Chúng ta cũng hãy tạo một bản sao của “clus1”. Điều này tương đương với một bản sao lưu đầy đủ.

/tmp/demo$ cp -Rp clus1 clus2
/tmp/demo$ ls -l
total 12
drwxr-xr-x  2 postgres postgres 4096 Jun  4 14:02 archive
drwx------ 19 postgres postgres 4096 Jun  4 14:03 clus1
drwx------ 19 postgres postgres 4096 Jun  4 14:03 clus2

Bây giờ chúng ta có thể bắt đầu cụm:

/tmp/demo$ pg_ctl -D clus1 -l log1 start
waiting for server to start.... done
server started

Hãy thêm vào một số dữ liệu.

/tmp/demo$ psql -h /var/run/postgresql -p 6000 postgres
psql (10.8 (Ubuntu 10.8-0ubuntu0.18.04.1))
Type "help" for help.

postgres=# create database demo;
CREATE DATABASE
postgres=# \c demo
You are now connected to database "demo" as user "postgres".
demo=# create table tbl1 (col1 int);
CREATE TABLE
demo=# insert into tbl1 (col1) select generate_series(1, 10000);
INSERT 0 10000
demo=# select count(*) from tbl1;
 count
-------
 10000
(1 row)

demo=# select now();
              now
-------------------------------
 2019-06-04 14:05:05.657871+00
(1 row)

demo=# \q

Lưu ý rằng hiện tại là 14:05. Hãy kiểm tra xem lệnh lưu trữ của chúng ta có hoạt động không:

/tmp/demo$ ls -l archive/
total 16384
-rw------- 1 postgres postgres 16777216 Jun  4 14:04 000000010000000000000001

Có, chúng tôi có một tệp lưu trữ duy nhất. Lần thay đổi cuối cùng của chúng tôi là lúc 14:05, bây giờ chúng ta hãy chờ đợi trong vài phút và sau đó thực hiện một số thay đổi khác.

/tmp/demo$ psql -h /var/run/postgresql -p 6000 demo
psql (10.8 (Ubuntu 10.8-0ubuntu0.18.04.1))
Type "help" for help.

demo=# select now();
              now
-------------------------------
 2019-06-04 14:16:06.093859+00
(1 row)

demo=# select count(*) from tbl1;
 count
-------
 10000
(1 row)

demo=# insert into tbl1 (col1) select generate_series(1, 100);
INSERT 0 100
demo=# select count(*) from tbl1;
 count
-------
 10100
(1 row)

demo=# \q

Vì vậy, bây giờ chúng tôi đã thêm 100 hàng nữa, lúc 14:16. Hãy dừng máy chủ:

/tmp/demo$ pg_ctl -D clus1 stop
waiting for server to shut down.... done
server stopped
/tmp/demo$

và kiểm tra lại kho lưu trữ của chúng tôi:

/tmp/demo$ ls -l archive/
total 65536
-rw------- 1 postgres postgres 16777216 Jun  4 14:04 000000010000000000000001
-rw------- 1 postgres postgres 16777216 Jun  4 14:05 000000010000000000000002
-rw------- 1 postgres postgres 16777216 Jun  4 14:09 000000010000000000000003
-rw------- 1 postgres postgres 16777216 Jun  4 14:16 000000010000000000000004

Có vẻ tốt. Bây giờ, chúng tôi sẽ cố gắng thực hiện khôi phục PITR của clus2 cho đến thời điểm 14:10.

Trước tiên, hãy chỉnh sửa postgres.conf của clus2 và thêm những dòng này vào cuối:

port = 6001
archive_mode = off

Để phát lại các tệp WAL, chúng tôi phải đặt máy chủ PostgreSQL cho clus2 (mà chúng tôi chưa khởi động) vào chế độ khôi phục. Để thực hiện việc này, hãy tạo tệp có tên là “recovery.conf” trong clus2:

/tmp/demo$ cat clus2/recovery.conf
restore_command = 'cp /tmp/demo/archive/%f "%p"'
recovery_target_time = '2019-06-04 14:10:00'

Điều này chứa restore_command điều này ngược lại với archive_command trước đó , cụ thể là sao chép tệp được yêu cầu từ thư mục lưu trữ vào thư mục pg_wal.

Chúng tôi cũng đã đặt recovery_target_time đến 14:10.

Bây giờ chúng ta bắt đầu clus2:

/tmp/demo$ pg_ctl -D clus2 -l log2 start
waiting for server to start.... done
server started

Để xem điều gì đã xảy ra, hãy kiểm tra tệp nhật ký:

/tmp/demo$ cat log2
2019-06-04 14:19:10.862 UTC [10513] LOG:  listening on IPv4 address "127.0.0.1", port 6001
2019-06-04 14:19:10.864 UTC [10513] LOG:  listening on Unix socket "/var/run/postgresql/.s.PGSQL.6001"
2019-06-04 14:19:10.883 UTC [10514] LOG:  database system was shut down at 2019-06-04 14:02:31 UTC
2019-06-04 14:19:10.883 UTC [10514] LOG:  starting point-in-time recovery to 2019-06-04 14:10:00+00
2019-06-04 14:19:10.903 UTC [10514] LOG:  restored log file "000000010000000000000001" from archive
2019-06-04 14:19:10.930 UTC [10514] LOG:  consistent recovery state reached at 0/16383E8
2019-06-04 14:19:10.930 UTC [10514] LOG:  redo starts at 0/16383E8
2019-06-04 14:19:10.931 UTC [10513] LOG:  database system is ready to accept read only connections
2019-06-04 14:19:11.037 UTC [10514] LOG:  restored log file "000000010000000000000002" from archive
2019-06-04 14:19:11.079 UTC [10514] LOG:  restored log file "000000010000000000000003" from archive
2019-06-04 14:19:11.122 UTC [10514] LOG:  restored log file "000000010000000000000004" from archive
2019-06-04 14:19:11.141 UTC [10514] LOG:  recovery stopping before commit of transaction 559, time 2019-06-04 14:16:24.875517+00
2019-06-04 14:19:11.141 UTC [10514] LOG:  recovery has paused
2019-06-04 14:19:11.141 UTC [10514] HINT:  Execute pg_wal_replay_resume() to continue.

Quá trình khôi phục diễn ra nhanh chóng (trong thực tế, có thể mất vài giờ hoặc vài ngày) và các logstates rằng nó đã dừng trước một giao dịch cụ thể (có dấu thời gian> 14:10). Nó cũng cho biết rằng quá trình khôi phục bị tạm dừng và phải được tiếp tục theo cách thủ công.

Hãy kiểm tra dữ liệu:

/tmp/demo$ psql -h /var/run/postgresql -p 6001 demo
psql (10.8 (Ubuntu 10.8-0ubuntu0.18.04.1))
Type "help" for help.

demo=# select count(*) from tbl1;
 count
-------
 10000
(1 row)

Chúng tôi thấy rằng chỉ có 10000 hàng. Vào lúc 14:16, chúng tôi đã thêm 100 cái nữa nhưng chưa xuất hiện trong bảng.

Điều này có vẻ ổn, vì vậy hãy tiếp tục:

demo=# select pg_wal_replay_resume();
 pg_wal_replay_resume
----------------------

(1 row)

Tệp nhật ký hiện báo cáo rằng quá trình khôi phục đã hoàn tất và các hoạt động bình thường được lưu trữ:

2019-06-04 14:20:26.219 UTC [10514] LOG:  redo done at 0/4002160
2019-06-04 14:20:26.219 UTC [10514] LOG:  last completed transaction was at log time 2019-06-04 14:05:28.813325+00
cp: cannot stat '/tmp/demo/archive/00000002.history': No such file or directory
2019-06-04 14:20:26.228 UTC [10514] LOG:  selected new timeline ID: 2
2019-06-04 14:20:26.272 UTC [10514] LOG:  archive recovery complete
cp: cannot stat '/tmp/demo/archive/00000001.history': No such file or directory
2019-06-04 14:20:26.388 UTC [10513] LOG:  database system is ready to accept connections

Và chúng tôi đã khôi phục thành công cụm cho đến một thời gian cụ thể!

Đọc thêm

Dưới đây là một số điểm bắt đầu để khám phá thêm về lưu trữ WAL, mã khôi phục và PITR:

  • Tài liệu:RecoveryConfiguration
  • Tài liệu:Lưu trữ Liên tục và PITR
  • Chương 9 từ sách “Nội bộ củaPostgreSQL”
  • Công cụ:WAL-E, WAL-G, Barman

  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Postgres sql chèn lỗi cú pháp truy vấn từ phpPgAdmin

  2. Điều cần kiểm tra xem Khả năng sử dụng bộ nhớ PostgreSQL có cao không

  3. sự khác biệt giữa localhost và postgres cho máy chủ trong docker

  4. Truy vấn JSON lồng nhau PostgreSQL

  5. Hàm STRING_AGG () trong PostgreSQL