WAL-G: النسخ الاحتياطية واستعادة PostgreSQL DBMS

من المعروف منذ فترة طويلة النسخ الاحتياطي إلى عمليات تفريغ SQL (باستخدام pg_dump أو pg_dumpall) ليست فكرة جيدة. لنسخ PostgreSQL DBMS احتياطيًا ، من الأفضل استخدام الأمر pg_basebackup، مما يؤدي إلى إنشاء نسخة ثنائية من سجلات WAL. ولكن عندما تبدأ في تعلم العملية الكاملة لإنشاء نسخة واستعادة ، ستفهم أنك بحاجة إلى كتابة دراجتين على الأقل من الدراجات ثلاثية العجلات حتى يعمل كل هذا ولا يسبب لك الألم من أعلى وأسفل. من أجل تخفيف المعاناة ، تم تطوير WAL-G.

وول جي هي أداة مكتوبة في Go لنسخ قواعد بيانات PostgreSQL احتياطيًا واستعادتها (ومؤخراً MySQL / MariaDB و MongoDB و FoundationDB). وهو يدعم العمل مع مخازن Amazon S3 (ونظائرها ، على سبيل المثال ، Yandex Object Storage) ، بالإضافة إلى Google Cloud Storage و Azure Storage و Swift Object Storage ومع نظام الملفات فقط. يتلخص الإعداد بأكمله في خطوات بسيطة ، ولكن نظرًا لحقيقة أن المقالات المتعلقة به مبعثرة على الإنترنت ، فلا يوجد دليل إرشادي كامل يتضمن جميع الخطوات من وإلى (هناك العديد من المنشورات على Habré ، ولكن هناك العديد من النقاط المفقودة).

WAL-G: النسخ الاحتياطية واستعادة PostgreSQL DBMS

هذه المقالة مكتوبة في المقام الأول لتنظيم معرفتي. أنا لست DBA ويمكنني التحدث بلغة الشخص العادي في مكان ما ، لذلك نرحب بأي تصحيحات!

بشكل منفصل ، ألاحظ أن كل شيء أدناه وثيق الصلة واختباره لـ PostgreSQL 12.3 على Ubuntu 18.04 ، يجب تنفيذ جميع الأوامر كمستخدم متميز.

تركيب

في وقت كتابة هذا التقرير ، كان الإصدار الثابت من WAL-G هو الإصدار 0.2.15 (مارس 2020). سوف نستخدمهولكن إذا كنت ترغب في بنائه بنفسك من الفرع الرئيسي ، فإن مستودع github يحتوي على جميع التعليمات الخاصة بذلك). للتنزيل والتثبيت ، يجب تشغيل:

#!/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/

بعد ذلك ، تحتاج إلى تهيئة WAL-G أولاً ، ثم PostgreSQL نفسها.

إعداد WAL-G

للحصول على مثال لتخزين النسخ الاحتياطية ، سيتم استخدام Amazon S3 (لأنه أقرب إلى الخوادم الخاصة بي وهو رخيص جدًا للاستخدام). للعمل معها ، تحتاج إلى "s3-bucket" ومفاتيح الوصول.

استخدمت جميع مقالات WAL-G السابقة التكوين مع متغيرات البيئة ، ولكن اعتبارًا من هذا الإصدار ، يمكن وضع الإعدادات في ملف .walg.json في الدليل الرئيسي لمستخدم postgres. لإنشائه ، قم بتشغيل البرنامج النصي التالي:

#!/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

اسمحوا لي أن أشرح قليلا عن كل شيء:

  • WALG_S3_PREFIX - المسار إلى دلو S3 الخاص بك حيث سيتم تحميل النسخ الاحتياطية (يمكنك إما إلى الجذر أو إلى المجلد) ؛
  • AWS_ACCESS_KEY_ID - مفتاح الوصول في S3 (في حالة الاستعادة على خادم اختبار - يجب أن تحتوي هذه المفاتيح على سياسة للقراءة فقط! تمت مناقشة هذا بمزيد من التفصيل في قسم الاسترداد.);
  • AWS_SECRET_ACCESS_KEY - المفتاح السري في تخزين S3 ؛
  • WALG_COMPRESSION_METHOD - طريقة الضغط ، من الأفضل استخدام Brotli (حيث أن هذا هو المتوسط ​​الذهبي بين الحجم النهائي وسرعة الضغط / فك الضغط) ؛
  • WALG_DELTA_MAX_STEPS - عدد "دلتا" قبل إنشاء نسخة احتياطية كاملة (يسمح لك بتوفير الوقت وحجم البيانات التي تم تنزيلها ، ولكن يمكن أن يبطئ قليلاً من عملية الاسترداد ، لذلك لا ينصح باستخدام قيم كبيرة) ؛
  • بيانات PGDATA - المسار إلى الدليل مع بيانات قاعدة البيانات الخاصة بك (يمكن العثور عليها عن طريق تشغيل الأمر pg_lsclusters);
  • شبح - الاتصال بقاعدة البيانات ، مع نسخة احتياطية محلية ، من الأفضل القيام بذلك من خلال مقبس يونيكس ، كما في هذا المثال.

يمكن العثور على خيارات أخرى في الوثائق: https://github.com/wal-g/wal-g/blob/v0.2.15/PostgreSQL.md#configuration.

تكوين PostgreSQL

لكي يقوم المحفوظات داخل قاعدة البيانات بتحميل سجلات WAL إلى السحابة والاسترداد منها (إذا لزم الأمر) ، تحتاج إلى تعيين العديد من المعلمات في ملف التكوين /etc/postgresql/12/main/postgresql.conf. فقط للمبتدئين تحتاج إلى التأكدأنه لم يتم تعيين أي من الإعدادات أدناه على أي قيم أخرى ، بحيث لا يسقط نظام DBMS عند إعادة تحميل التكوين. يمكنك إضافة هذه الخيارات مع:

#!/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

وصف المعلمات التي سيتم تعيينها:

  • wal_level - مقدار المعلومات المراد كتابتها في سجلات WAL ، "نسخة طبق الأصل" - اكتب كل شيء ؛
  • وضع_الأرشيف - تمكين تحميل سجلات WAL باستخدام الأمر من المعلمة أرشيف_الأمر;
  • أرشيف_الأمر - أمر لأرشفة سجل WAL المكتمل ؛
  • مهلة_الأرشيف - يتم تنفيذ أرشفة السجلات فقط عند اكتمالها ، ولكن إذا قام الخادم الخاص بك بتغيير / إضافة القليل من البيانات إلى قاعدة البيانات ، فمن المنطقي تعيين حد هنا في ثوانٍ ، وبعد ذلك سيتم استدعاء أمر الأرشفة بالقوة (لدي كتابة مكثفة في قاعدة البيانات كل ثانية ، لذلك رفضت تعيين هذه المعلمة في الإنتاج);
  • استعادة_الامر - سيتم استخدام الأمر لاستعادة سجل WAL من نسخة احتياطية إذا كانت "النسخة الاحتياطية الكاملة" (النسخة الاحتياطية الأساسية) تفتقر إلى أحدث التغييرات في قاعدة البيانات.

يمكنك قراءة المزيد عن كل هذه المعايير في ترجمة الوثائق الرسمية: https://postgrespro.ru/docs/postgresql/12/runtime-config-wal.

إعداد جدول النسخ الاحتياطي

شئنا أم أبينا ، ولكن الطريقة الأكثر ملاءمة لتشغيلها هي cron. هذا ما سنقوم بتكوينه لإنشاء نسخ احتياطية. لنبدأ بالأمر لإنشاء نسخة احتياطية كاملة: في wal-g ، هذه هي حجة الإطلاق دفع احتياطي. لكن أولاً ، من الأفضل تشغيل هذا الأمر يدويًا كمستخدم postgres للتأكد من أن كل شيء على ما يرام (ولا توجد أخطاء في الوصول):

#!/bin/bash

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

تحتوي وسائط الإطلاق على المسار إلى دليل البيانات - أذكرك أنه يمكنك العثور عليه عن طريق التشغيل pg_lsclusters.

إذا سارت الأمور دون أخطاء وتم تحميل البيانات في وحدة التخزين S3 ، فيمكنك حينئذٍ تهيئة الإطلاق الدوري في 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

في هذا المثال ، تبدأ عملية النسخ الاحتياطي يوميًا الساعة 4:15 صباحًا.

حذف النسخ الاحتياطية القديمة

ربما لا تحتاج إلى الاحتفاظ تمامًا بجميع النسخ الاحتياطية من حقبة الدهر الوسيط ، لذلك من الجيد "تنظيف" التخزين بشكل دوري ("النسخ الاحتياطية الكاملة" وسجلات WAL). سنفعل كل هذا أيضًا من خلال مهمة 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 هذه المهمة كل يوم في الساعة 6:30 صباحًا ، مع حذف كل شيء (النسخ الاحتياطية الكاملة ودلتا و WALs) باستثناء آخر 10 أيام ، مع ترك نسخة احتياطية واحدة على الأقل إلى التاريخ المحدد لأي نقطة بعد دخلت التواريخ في PITR.

استعادة من نسخة احتياطية

لا يخفى على أحد أن مفتاح قاعدة البيانات السليمة هو استعادة البيانات الموجودة بداخلها والتحقق منها بشكل دوري. كيفية الاسترداد باستخدام WAL-G - سأخبرك في هذا القسم ، وسنتحدث عن الشيكات لاحقًا.

يجب أن يلاحظ بشكل منفصل ذلك لاستعادته في بيئة اختبار (كل شيء ليس إنتاجًا) - تحتاج إلى استخدام حساب للقراءة فقط في S3 ، حتى لا تقوم بالكتابة فوق النسخ الاحتياطية عن طريق الخطأ. في حالة WAL-G ، تحتاج إلى تعيين مستخدم S3 على الحقوق التالية في نهج المجموعة (التأثير: السماح): s3: GetObject, s3:ListBucket, s3: GetBucketLocation. وبالطبع ، لا تنس النشر archive_mode = إيقاف في ملف الإعدادات postgresql.confحتى لا ترغب قاعدة الاختبار الخاصة بك في إجراء النسخ الاحتياطي بصمت.

تتم الاستعادة بحركة طفيفة لليد حذف جميع بيانات PostgreSQL (بما في ذلك المستخدمين) ، لذا يرجى توخي الحذر الشديد عند تشغيل الأوامر التالية.

#!/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

بالنسبة لأولئك الذين يرغبون في التحقق من عملية الاسترداد ، تم إعداد جزء صغير من سحر bash أدناه بحيث في حالة حدوث مشاكل في الاسترداد ، يتعطل البرنامج النصي برمز خروج غير صفري. في هذا المثال ، يتم إجراء 120 عملية تحقق مع مهلة مدتها 5 ثوانٍ (إجمالي 10 دقائق للاسترداد) لمعرفة ما إذا كان ملف الإشارة قد تم حذفه (سيعني هذا أن الاسترداد كان ناجحًا):

#!/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

بعد استعادة ناجحة ، لا تنس إعادة تشغيل جميع العمليات (pgbouncer / monit ، إلخ).

التحقق من البيانات بعد الاسترداد

تأكد من التحقق من سلامة قاعدة البيانات بعد الاسترداد ، حتى لا يكون هناك موقف مع وجود نسخة احتياطية معطلة / ملتوية. ومن الأفضل القيام بذلك مع كل أرشيف تم إنشاؤه ، ولكن الأمر متروك لخيالك أين وكيف (يمكنك إنشاء خوادم منفصلة على أساس كل ساعة أو إجراء فحص في CI). ولكن على الأقل ، من الضروري التحقق من البيانات والفهارس في قاعدة البيانات.

للتحقق من البيانات ، يكفي تشغيلها من خلال تفريغ ، ولكن من الأفضل أن يكون لديك المجموع الاختباري ممكّنًا عند إنشاء قاعدة البيانات (المجاميع الاختبارية للبيانات):

#!/bin/bash

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

للتحقق من الفهارس - موجود وحدة amcheck، sql-query نأخذ منه اختبارات WAL-G وابني القليل من المنطق حول:

#!/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

يلخص

أعرب عن امتناني لأندري بورودين لمساعدته في إعداد المنشور وشكرًا خاصًا لمساهمته في تطوير WAL-G!

هذا يختتم هذه المذكرة. آمل أن أكون قادرًا على نقل سهولة التخصيص والإمكانيات الهائلة لاستخدام هذه الأداة في شركتك. سمعت الكثير عن WAL-G ، لكن لم يكن هناك وقت للجلوس واكتشاف ذلك. وبعد أن قمت بتطبيقه في المنزل ، خرجت مني هذه المقالة.

بشكل منفصل ، تجدر الإشارة إلى أن WAL-G يمكنه أيضًا العمل مع نظم إدارة قواعد البيانات التالية:

المصدر: www.habr.com

إضافة تعليق