WAL-G: sao lưu và phục hồi DBMS PostgreSQL

Từ lâu người ta đã biết rằng việc sao lưu thành các bản sao lưu SQL (sử dụng pg_dump hoặc pg_dumpall) không phải là một ý kiến ​​hay. Để sao lưu DBMS PostgreSQL, tốt hơn là sử dụng lệnh pg_basebackup, tạo bản sao nhị phân của nhật ký WAL. Nhưng khi bạn bắt đầu nghiên cứu toàn bộ quá trình tạo bản sao và khôi phục, bạn sẽ hiểu rằng bạn cần phải viết ít nhất một vài chiếc xe ba bánh để việc này hoạt động và không khiến bạn đau cả trên lẫn dưới. Để giảm bớt đau khổ, WAL-G đã được phát triển.

WAL-G là một công cụ được viết bằng Go để sao lưu và khôi phục cơ sở dữ liệu PostgreSQL (và gần đây hơn là MySQL/MariaDB, MongoDB và FoundationDB). Nó hỗ trợ làm việc với bộ lưu trữ Amazon S3 (và các chất tương tự, chẳng hạn như Yandex Object Storage), cũng như Google Cloud Storage, Azure Storage, Swift Object Storage và chỉ với hệ thống tệp. Toàn bộ quá trình thiết lập bao gồm các bước đơn giản, nhưng do các bài viết về nó nằm rải rác trên Internet nên không có hướng dẫn cách thực hiện đầy đủ bao gồm tất cả các bước từ đầu đến cuối (có một số bài đăng trên Habré, nhưng có nhiều điểm bị bỏ sót ở đó).

WAL-G: sao lưu và phục hồi DBMS PostgreSQL

Bài viết này được viết chủ yếu để hệ thống hóa kiến ​​thức của tôi. Tôi không phải là một DBA và tôi có thể thể hiện bản thân bằng ngôn ngữ của giáo dân ở đâu đó, vì vậy mọi sự sửa chữa đều được hoan nghênh!

Riêng biệt, tôi lưu ý rằng mọi thứ bên dưới đều có liên quan và đã được thử nghiệm cho PostgreSQL 12.3 trên Ubuntu 18.04, tất cả các lệnh phải được thực thi với tư cách là người dùng đặc quyền.

Cài đặt

Tại thời điểm viết bài này, phiên bản ổn định của WAL-G là v0.2.15 (Tháng 2020 năm XNUMX). Đây là những gì chúng tôi sẽ sử dụng (nhưng nếu bạn muốn tự xây dựng nó từ nhánh chính thì kho github có tất cả các hướng dẫn cho việc này). Để tải xuống và cài đặt, bạn cần làm:

#!/bin/bash

curl -L "https://github.com/wal-g/wal-g/releases/download/v0.2.15/wal-g.linux-amd64.tar.gz" -o "wal-g.linux-amd64.tar.gz"
tar -xzf wal-g.linux-amd64.tar.gz
mv wal-g /usr/local/bin/

Sau này, trước tiên bạn cần định cấu hình WAL-G và sau đó là chính PostgreSQL.

Thiết lập WAL-G

Để biết ví dụ về lưu trữ bản sao lưu, Amazon S3 sẽ được sử dụng (bởi vì nó gần máy chủ của tôi hơn và giá sử dụng nó rất rẻ). Để làm việc với nó, bạn cần có “thùng s3” và các phím truy cập.

Tất cả các bài viết trước đây về WAL-G đều sử dụng cấu hình sử dụng các biến môi trường, nhưng với bản phát hành này, các cài đặt có thể được đặt trong tập tin .walg.json trong thư mục chính của người dùng postgres. Để tạo nó, hãy chạy tập lệnh bash sau:

#!/bin/bash

cat > /var/lib/postgresql/.walg.json << EOF
{
    "WALG_S3_PREFIX": "s3://your_bucket/path",
    "AWS_ACCESS_KEY_ID": "key_id",
    "AWS_SECRET_ACCESS_KEY": "secret_key",
    "WALG_COMPRESSION_METHOD": "brotli",
    "WALG_DELTA_MAX_STEPS": "5",
    "PGDATA": "/var/lib/postgresql/12/main",
    "PGHOST": "/var/run/postgresql/.s.PGSQL.5432"
}
EOF
# обязательно меняем владельца файла:
chown postgres: /var/lib/postgresql/.walg.json

Hãy để tôi giải thích một chút về tất cả các tham số:

  • WALG_S3_PREFIX – đường dẫn đến nhóm S3 của bạn nơi các bản sao lưu sẽ được tải lên (bạn có thể vào thư mục gốc hoặc vào một thư mục);
  • AWS_ACCESS_KEY_ID – khóa truy cập trong S3 (trường hợp khôi phục trên máy chủ thử nghiệm thì các key này phải có ReadOnly Policy! Điều này được mô tả chi tiết hơn trong phần khôi phục.);
  • AWS_SECRET_ACCESS_KEY – khóa bí mật trong bộ lưu trữ S3;
  • WALG_COMPRESSION_METHOD – phương pháp nén, tốt hơn nên sử dụng Brotli (vì đây là giá trị trung bình vàng giữa kích thước cuối cùng và tốc độ nén/giải nén);
  • WALG_DELTA_MAX_STEPS – số lượng “delta” trước khi tạo bản sao lưu đầy đủ (chúng tiết kiệm thời gian và kích thước của dữ liệu đã tải xuống, nhưng có thể làm chậm quá trình khôi phục một chút, do đó không nên sử dụng các giá trị lớn);
  • PGDATA – đường dẫn đến thư mục chứa dữ liệu cơ sở dữ liệu của bạn (bạn có thể tìm hiểu bằng cách chạy lệnh pg_lscluster);
  • PGHOST – kết nối với cơ sở dữ liệu, với một bản sao lưu cục bộ, tốt hơn nên thực hiện điều đó thông qua unix-socket như trong ví dụ này.

Các thông số khác có thể được tìm thấy trong tài liệu: https://github.com/wal-g/wal-g/blob/v0.2.15/PostgreSQL.md#configuration.

Định cấu hình PostgreSQL

Để trình lưu trữ bên trong cơ sở dữ liệu tải nhật ký WAL lên đám mây và khôi phục chúng từ chúng (nếu cần), bạn cần đặt một số tham số trong tệp cấu hình /etc/postgresql/12/main/postgresql.conf. Chỉ dành cho người mới bắt đầu bạn cần phải chắc chắnrằng không có cài đặt nào bên dưới được đặt thành bất kỳ giá trị nào khác, để khi tải lại cấu hình, DBMS không gặp sự cố. Bạn có thể thêm các tham số này bằng cách sử dụng:

#!/bin/bash

echo "wal_level=replica" >> /etc/postgresql/12/main/postgresql.conf
echo "archive_mode=on" >> /etc/postgresql/12/main/postgresql.conf
echo "archive_command='/usr/local/bin/wal-g wal-push "%p" >> /var/log/postgresql/archive_command.log 2>&1' " >> /etc/postgresql/12/main/postgresql.conf
echo “archive_timeout=60” >> /etc/postgresql/12/main/postgresql.conf
echo "restore_command='/usr/local/bin/wal-g wal-fetch "%f" "%p" >> /var/log/postgresql/restore_command.log 2>&1' " >> /etc/postgresql/12/main/postgresql.conf

# перезагружаем конфиг через отправку SIGHUP сигнала всем процессам БД
killall -s HUP postgres

Mô tả các thông số cần thiết lập:

  • wal_level – bao nhiêu thông tin cần ghi vào nhật ký WAL, “bản sao” – viết mọi thứ;
  • archive_mode – cho phép tải xuống nhật ký WAL bằng lệnh từ tham số lưu trữ_command;
  • lưu trữ_command – lệnh lưu trữ nhật ký WAL đã hoàn thành;
  • archive_timeout – việc lưu trữ nhật ký chỉ được thực hiện khi hoàn thành, nhưng nếu máy chủ của bạn thay đổi/thêm ít dữ liệu vào cơ sở dữ liệu, thì việc đặt giới hạn ở đây tính bằng giây là hợp lý, sau đó lệnh lưu trữ sẽ được gọi bắt buộc (Tôi viết nhiều vào cơ sở dữ liệu mỗi giây, vì vậy tôi quyết định không đặt tham số này trong quá trình sản xuất);
  • khôi phục_command – lệnh khôi phục nhật ký WAL từ bản sao lưu sẽ được sử dụng nếu “sao lưu đầy đủ” (sao lưu cơ sở) thiếu những thay đổi mới nhất trong cơ sở dữ liệu.

Bạn có thể đọc thêm về tất cả các tham số này trong bản dịch tài liệu chính thức: https://postgrespro.ru/docs/postgresql/12/runtime-config-wal.

Thiết lập lịch trình sao lưu

Dù người ta có thể nói gì, cách thuận tiện nhất để chạy nó là cron. Đây là những gì chúng tôi sẽ cấu hình để tạo bản sao lưu. Hãy bắt đầu với lệnh tạo bản sao lưu đầy đủ: trong wal-g đây là đối số khởi chạy đẩy dự phòng. Nhưng trước tiên, tốt hơn hết bạn nên chạy lệnh này theo cách thủ công từ người dùng postgres để đảm bảo mọi thứ đều ổn (và không có lỗi truy cập):

#!/bin/bash

su - postgres -c '/usr/local/bin/wal-g backup-push /var/lib/postgresql/12/main'

Các đối số khởi chạy chỉ ra đường dẫn đến thư mục dữ liệu - Tôi nhắc bạn rằng bạn có thể tìm ra nó bằng cách chạy pg_lscluster.

Nếu mọi thứ không có lỗi và dữ liệu được tải vào bộ lưu trữ S3 thì bạn có thể định cấu hình khởi chạy định kỳ trong crontab:

#!/bin/bash

echo "15 4 * * *    /usr/local/bin/wal-g backup-push /var/lib/postgresql/12/main >> /var/log/postgresql/walg_backup.log 2>&1" >> /var/spool/cron/crontabs/postgres
# задаем владельца и выставляем правильные права файлу
chown postgres: /var/spool/cron/crontabs/postgres
chmod 600 /var/spool/cron/crontabs/postgres

Trong ví dụ này, quá trình sao lưu bắt đầu hàng ngày lúc 4:15 sáng.

Xóa bản sao lưu cũ

Rất có thể, bạn không cần phải giữ hoàn toàn tất cả các bản sao lưu từ thời Mesozoi, vì vậy sẽ rất hữu ích nếu bạn "dọn dẹp" bộ nhớ của mình định kỳ (cả "bản sao lưu đầy đủ" và nhật ký WAL). Chúng ta sẽ thực hiện tất cả điều này thông qua một tác vụ cron:

#!/bin/bash

echo "30 6 * * *    /usr/local/bin/wal-g delete before FIND_FULL $(date -d '-10 days' '+%FT%TZ') --confirm >> /var/log/postgresql/walg_delete.log 2>&1" >> /var/spool/cron/crontabs/postgres
# ещё раз задаем владельца и выставляем правильные права файлу (хоть это обычно это и не нужно повторно делать)
chown postgres: /var/spool/cron/crontabs/postgres
chmod 600 /var/spool/cron/crontabs/postgres

Cron sẽ chạy tác vụ này vào lúc 6:30 sáng hàng ngày, xóa mọi thứ (bản sao lưu đầy đủ, vùng đồng bằng và WAL) ngoại trừ các bản sao trong 10 ngày qua, nhưng để lại ít nhất một bản sao lưu để ngày được chỉ định sao cho bất kỳ điểm nào sau khi ngày đã được đưa vào PITR.

Khôi phục từ một bản sao lưu

Không có gì bí mật rằng chìa khóa cho một cơ sở dữ liệu lành mạnh là việc khôi phục định kỳ và xác minh tính toàn vẹn của dữ liệu bên trong. Tôi sẽ cho bạn biết cách khôi phục bằng WAL-G trong phần này và chúng ta sẽ nói về việc kiểm tra sau.

Cần lưu ý riêng để khôi phục trong môi trường thử nghiệm (mọi thứ không phải sản xuất), bạn cần sử dụng tài khoản Chỉ đọc trong S3 để không vô tình ghi đè lên các bản sao lưu. Trong trường hợp WAL-G, bạn cần đặt các quyền sau cho người dùng S3 trong Chính sách nhóm (Tác dụng: Cho phép): s3:GetObject, s3:Danh sách nhóm, s3:Nhận vị trí nhóm. Và tất nhiên, đừng quên thiết lập archive_mode=tắt trong tập tin cài đặt postgresql.conf, để cơ sở dữ liệu thử nghiệm của bạn không muốn được sao lưu một cách lặng lẽ.

Phục hồi được thực hiện với một chuyển động nhẹ của bàn tay xóa tất cả dữ liệu PostgreSQL (bao gồm cả người dùng), vì vậy hãy hết sức cẩn thận khi chạy các lệnh sau.

#!/bin/bash

# если есть балансировщик подключений (например, pgbouncer), то вначале отключаем его, чтобы он не нарыгал ошибок в лог
service pgbouncer stop
# если есть демон, который перезапускает упавшие процессы (например, monit), то останавливаем в нём процесс мониторинга базы (у меня это pgsql12)
monit stop pgsql12
# или останавливаем мониторинг полностью
service monit stop
# останавливаем саму базу данных
service postgresql stop
# удаляем все данные из текущей базы (!!!); лучше предварительно сделать их копию, если есть свободное место на диске
rm -rf /var/lib/postgresql/12/main
# скачиваем резервную копию и разархивируем её
su - postgres -c '/usr/local/bin/wal-g backup-fetch /var/lib/postgresql/12/main LATEST'
# помещаем рядом с базой специальный файл-сигнал для восстановления (см. https://postgrespro.ru/docs/postgresql/12/runtime-config-wal#RUNTIME-CONFIG-WAL-ARCHIVE-RECOVERY ), он обязательно должен быть создан от пользователя postgres
su - postgres -c 'touch /var/lib/postgresql/12/main/recovery.signal'
# запускаем базу данных, чтобы она инициировала процесс восстановления
service postgresql start

Đối với những người muốn kiểm tra quá trình khôi phục, một đoạn bash magic nhỏ đã được chuẩn bị bên dưới, để trong trường hợp có vấn đề trong quá trình khôi phục, tập lệnh sẽ gặp sự cố với mã thoát khác 120. Trong ví dụ này, 5 lần kiểm tra được thực hiện với thời gian chờ là 10 giây (tổng cộng XNUMX phút để khôi phục) để tìm hiểu xem tệp tín hiệu có bị xóa hay không (điều này có nghĩa là quá trình khôi phục đã thành công):

#!/bin/bash

CHECK_RECOVERY_SIGNAL_ITER=0
while [ ${CHECK_RECOVERY_SIGNAL_ITER} -le 120 ]
do
    if [ ! -f "/var/lib/postgresql/12/main/recovery.signal" ]
    then
        echo "recovery.signal removed"
        break
    fi
    sleep 5
    ((CHECK_RECOVERY_SIGNAL_ITER+1))
done

# если после всех проверок файл всё равно существует, то падаем с ошибкой
if [ -f "/var/lib/postgresql/12/main/recovery.signal" ]
then
    echo "recovery.signal still exists!"
    exit 17
fi

Sau khi khôi phục thành công, đừng quên khởi động lại tất cả các quy trình (pgbouncer/monit, v.v.).

Kiểm tra dữ liệu sau khi khôi phục

Điều bắt buộc là phải kiểm tra tính toàn vẹn của cơ sở dữ liệu sau khi khôi phục để không phát sinh tình trạng bản sao lưu bị hỏng/cong. Và tốt hơn hết bạn nên thực hiện việc này với từng kho lưu trữ đã tạo, nhưng vị trí và cách thức chỉ phụ thuộc vào trí tưởng tượng của bạn (bạn có thể nâng cấp các máy chủ riêng lẻ hàng giờ hoặc chạy kiểm tra CI). Nhưng tối thiểu cần phải kiểm tra dữ liệu và chỉ mục trong cơ sở dữ liệu.

Để kiểm tra dữ liệu, chỉ cần chạy dữ liệu qua kết xuất là đủ, nhưng tốt hơn là khi tạo cơ sở dữ liệu, bạn đã bật tổng kiểm tra (tổng kiểm tra dữ liệu):

#!/bin/bash

if ! su - postgres -c 'pg_dumpall > /dev/null'
then
    echo 'pg_dumpall failed'
    exit 125
fi

Để kiểm tra chỉ mục - tồn tại mô-đun amcheck, hãy lấy truy vấn sql cho nó từ Kiểm tra WAL-G và xây dựng một chút logic xung quanh nó:

#!/bin/bash

# добавляем sql-запрос для проверки в файл во временной директории
cat > /tmp/amcheck.sql << EOF
CREATE EXTENSION IF NOT EXISTS amcheck;
SELECT bt_index_check(c.oid), c.relname, c.relpages
FROM pg_index i
JOIN pg_opclass op ON i.indclass[0] = op.oid
JOIN pg_am am ON op.opcmethod = am.oid
JOIN pg_class c ON i.indexrelid = c.oid
JOIN pg_namespace n ON c.relnamespace = n.oid
WHERE am.amname = 'btree'
AND c.relpersistence != 't'
AND i.indisready AND i.indisvalid;
EOF
chown postgres: /tmp/amcheck.sql

# добавляем скрипт для запуска проверок всех доступных баз в кластере
# (обратите внимание что переменные и запуск команд – экранированы)
cat > /tmp/run_amcheck.sh << EOF
for DBNAME in $(su - postgres -c 'psql -q -A -t -c "SELECT datname FROM pg_database WHERE datistemplate = false;" ')
do
    echo "Database: ${DBNAME}"
    su - postgres -c "psql -f /tmp/amcheck.sql -v 'ON_ERROR_STOP=1' ${DBNAME}" && EXIT_STATUS=$? || EXIT_STATUS=$?
    if [ "${EXIT_STATUS}" -ne 0 ]
    then
        echo "amcheck failed on DB: ${DBNAME}"
        exit 125
    fi
done
EOF
chmod +x /tmp/run_amcheck.sh

# запускаем скрипт
/tmp/run_amcheck.sh > /tmp/amcheck.log

# для проверки что всё прошло успешно можно проверить exit code или grep’нуть ошибку
if grep 'amcheck failed' "/tmp/amcheck.log"
then
    echo 'amcheck failed: '
    cat /tmp/amcheck.log
    exit 125
fi

Tóm tắt

Tôi muốn bày tỏ lòng biết ơn tới Andrey Borodin vì sự giúp đỡ của anh ấy trong việc chuẩn bị xuất bản và cảm ơn đặc biệt vì sự đóng góp của anh ấy cho sự phát triển của WAL-G!

Điều này kết thúc ghi chú này. Tôi hy vọng rằng tôi có thể truyền đạt sự dễ dàng trong việc thiết lập và tiềm năng to lớn của việc sử dụng công cụ này trong công ty của bạn. Tôi đã nghe rất nhiều về WAL-G nhưng chưa bao giờ có đủ thời gian để ngồi xuống và tìm hiểu về nó. Và sau khi tôi thực hiện nó ở nhà, bài viết này đã ra đời trong tôi.

Riêng biệt, điều đáng chú ý là WAL-G cũng có thể hoạt động với DBMS sau:

Nguồn: www.habr.com

Thêm một lời nhận xét