الانتقال إلى المحتوى الرئيسي

الصيغة

-- core commands
BACKUP | RESTORE 
--- what to backup/restore (or exclude)
TABLE [db.]table_name           [AS [db.]table_name_in_backup] |
DICTIONARY [db.]dictionary_name [AS [db.]name_in_backup] |
DATABASE database_name          [AS database_name_in_backup] |
TEMPORARY TABLE table_name      [AS table_name_in_backup] |
VIEW view_name                  [AS view_name_in_backup] |
[EXCEPT TABLES ...] |
ALL [EXCEPT {TABLES|DATABASES}...] } [,...]
--- 
[ON CLUSTER 'cluster_name']
--- where to backup or restore to or from
TO|FROM 
File('<path>/<filename>') | 
Disk('<disk_name>', '<path>/') | 
S3('<S3 endpoint>/<path>', '<Access key ID>', '<Secret access key>', '<extra_credentials>') |
AzureBlobStorage('<connection string>/<url>', '<container>', '<path>', '<account name>', '<account key>')
--- additional settings
[SETTINGS ...]
[ASYNC]
راجع “ملخص الأوامر” لمزيد من التفاصيل عن كل أمر.

تهيئة وجهات النسخ الاحتياطي للقرص

إعداد وجهة النسخ الاحتياطي للقرص المحلي

في الأمثلة أدناه، ستظهر وجهة النسخ الاحتياطي بالشكل Disk('backups', '1.zip'). ولاستخدام محرك النسخ الاحتياطي Disk، يجب أولاً إضافة ملف يحدد وجهة النسخ الاحتياطي في المسار أدناه:
/etc/clickhouse-server/config.d/backup_disk.xml
على سبيل المثال، يحدّد الإعداد أدناه قرصًا باسم backups، ثم يضيف هذا القرص إلى قائمة allowed_disk الخاصة بـ backups:
<clickhouse>
    <storage_configuration>
        <disks>
            <backups>
                <type>local</type>
                <path>/backups/</path>
            </backups>
        </disks>
    </storage_configuration>
    <backups>
        <allowed_disk>backups</allowed_disk>
        <allowed_path>/backups/</allowed_path>
    </backups>
</clickhouse>

تهيئة وجهة نسخ احتياطي لقرص S3

يمكن أيضًا إجراء BACKUP/RESTORE إلى S3 عبر تهيئة قرص S3 ضمن إعدادات التخزين في ClickHouse. هيّئ القرص كما يلي، وذلك بإضافة ملف إلى /etc/clickhouse-server/config.d كما فُعل أعلاه للقرص المحلي.
<clickhouse>
    <storage_configuration>
        <disks>
            <s3_plain>
                <type>s3_plain</type>
                <endpoint></endpoint>
                <access_key_id></access_key_id>
                <secret_access_key></secret_access_key>
            </s3_plain>
        </disks>
        <policies>
            <s3>
                <volumes>
                    <main>
                        <disk>s3_plain</disk>
                    </main>
                </volumes>
            </s3>
        </policies>
    </storage_configuration>

    <backups>
        <allowed_disk>s3_plain</allowed_disk>
    </backups>
</clickhouse>
يُجرى BACKUP/RESTORE لقرص S3 بالطريقة نفسها كما هو الحال مع القرص المحلي:
BACKUP TABLE data TO Disk('s3_plain', 'cloud_backup');
RESTORE TABLE data AS data_restored FROM Disk('s3_plain', 'cloud_backup');
  • يجب عدم استخدام هذا القرص مع MergeTree نفسه، وإنما فقط مع BACKUP/RESTORE
  • إذا كانت جداولك تعتمد على تخزين S3 وكانت أنواع الأقراص مختلفة، فلن تُستخدَم استدعاءات CopyObject لنسخ الأجزاء إلى حاوية الوجهة، بل سيجري تنزيلها ثم إعادة رفعها، وهذا غير فعّال جدًا. في هذه الحالة، يُفضَّل استخدام الصيغة BACKUP ... TO S3(<endpoint>) لهذا الغرض.

أمثلة على استخدام النسخ الاحتياطي والاستعادة على القرص المحلي

أخذ نسخة احتياطية من جدول واستعادته

نفّذ الأوامر التالية لإنشاء قاعدة بيانات الاختبار والجدول اللذين سنُجري عليهما نسخة احتياطية واستعادة في هذا المثال:
أنشئ قاعدة البيانات والجدول:
CREATE DATABASE test_db;

CREATE TABLE test_db.test_table (
    id UUID,
    name String,
    email String,
    age UInt8,
    salary UInt32,
    created_at DateTime,
    is_active UInt8,
    department String,
    score Float32,
    country String
) ENGINE = MergeTree()
ORDER BY id;
أدرِج ألف صف من البيانات العشوائية:
INSERT INTO test_table (id, name, email, age, salary, created_at, is_active, department, score, country)
SELECT
    generateUUIDv4() as id,
    concat('User_', toString(rand() % 10000)) as name,
    concat('user', toString(rand() % 10000), '@example.com') as email,
    18 + (rand() % 65) as age,
    30000 + (rand() % 100000) as salary,
    now() - toIntervalSecond(rand() % 31536000) as created_at,
    rand() % 2 as is_active,
    arrayElement(['Engineering', 'Marketing', 'Sales', 'HR', 'Finance', 'Operations'], (rand() % 6) + 1) as department,
    rand() / 4294967295.0 * 100 as score,
    arrayElement(['USA', 'UK', 'Germany', 'France', 'Canada', 'Australia', 'Japan', 'Brazil'], (rand() % 8) + 1) as country
FROM numbers(1000);
بعد ذلك، ستحتاج إلى إنشاء ملف يحدّد وجهة النسخة الاحتياطية في المسار التالي:
/etc/clickhouse-server/config.d/backup_disk.xml
<clickhouse>
    <storage_configuration>
        <disks>
            <backups>
                <type>local</type>
                <path>/backups/</path> -- على MacOS اختر: /Users/backups/
            </backups>
        </disks>
    </storage_configuration>
    <backups>
        <allowed_disk>backups</allowed_disk>
        <allowed_path>/backups/</allowed_path> -- على MacOS اختر: /Users/backups/
    </backups>
</clickhouse>
إذا كان clickhouse-server قيد التشغيل، فستحتاج إلى إعادة تشغيله حتى تسري التغييرات.
لأخذ نسخة احتياطية من الجدول، يمكنك تشغيل:
Query
BACKUP TABLE test_db.test_table TO Disk('backups', '1.zip')
Response
   ┌─id───────────────────────────────────┬─status─────────┐
1. │ 065a8baf-9db7-4393-9c3f-ba04d1e76bcd │ BACKUP_CREATED │
   └──────────────────────────────────────┴────────────────┘
يمكن استعادة الجدول من النسخة الاحتياطية بالأمر التالي إذا كان الجدول فارغًا:
Query
RESTORE TABLE test_db.test_table FROM Disk('backups', '1.zip')
Response
   ┌─id───────────────────────────────────┬─status───┐
1. │ f29c753f-a7f2-4118-898e-0e4600cd2797 │ RESTORED │
   └──────────────────────────────────────┴──────────┘
سيفشل RESTORE أعلاه إذا كان الجدول test.table يحتوي على بيانات. يتيح الإعداد allow_non_empty_tables=true لـ RESTORE TABLE إدراج البيانات في الجداول غير الفارغة. سيؤدي ذلك إلى مزج البيانات الموجودة مسبقًا في الجدول مع البيانات المستخرجة من النسخة الاحتياطية. لذلك قد يتسبب هذا الإعداد في تكرار البيانات داخل الجدول، ويجب استخدامه بحذر.
لاستعادة الجدول مع وجود بيانات فيه مسبقًا، شغّل:
RESTORE TABLE test_db.test_table FROM Disk('backups', '1.zip')
SETTINGS allow_non_empty_tables=true
يمكن استعادة الجداول أو إنشاء نسخ احتياطية منها بأسماء جديدة:
RESTORE TABLE test_db.test_table AS test_db.test_table_renamed FROM Disk('backups', '1.zip')
يحتوي أرشيف هذه النسخة الاحتياطية على البنية التالية:
├── .backup
└── metadata
    └── test_db
        └── test_table.sql
يمكن استخدام تنسيقات أخرى غير zip. راجع “النسخ الاحتياطية كأرشيفات tar” أدناه لمزيد من التفاصيل.

النسخ الاحتياطية التزايدية إلى القرص

النسخة الاحتياطية الأساسية في ClickHouse هي النسخة الاحتياطية الكاملة الأولية التي تُنشأ انطلاقًا منها النسخ الاحتياطية التزايدية اللاحقة. ولا تخزّن النسخ الاحتياطية التزايدية سوى التغييرات التي أُجريت منذ إنشاء النسخة الاحتياطية الأساسية، لذلك يجب إبقاء النسخة الاحتياطية الأساسية متاحة لكي تتمكن من الاستعادة من أي نسخة احتياطية تزايدية. ويمكن تعيين وجهة النسخة الاحتياطية الأساسية باستخدام الإعداد base_backup.
تعتمد النسخ الاحتياطية التزايدية على النسخة الاحتياطية الأساسية. ويجب إبقاء النسخة الاحتياطية الأساسية متاحة حتى تتمكن من الاستعادة من نسخة احتياطية تزايدية.
لإنشاء نسخة احتياطية تزايدية لجدول، أنشئ أولاً نسخة احتياطية أساسية:
BACKUP TABLE test_db.test_table TO Disk('backups', 'd.zip')
BACKUP TABLE test_db.test_table TO Disk('backups', 'incremental-a.zip')
SETTINGS base_backup = Disk('backups', 'd.zip')
يمكن استعادة جميع البيانات من النسخة الاحتياطية التزايدية والنسخة الاحتياطية الأساسية إلى جدول جديد test_db.test_table2 باستخدام الأمر:
RESTORE TABLE test_db.test_table AS test_db.test_table2
FROM Disk('backups', 'incremental-a.zip');

تأمين نسخة احتياطية

يمكن تعيين كلمة مرور على ملفات النسخ الاحتياطية المكتوبة على القرص. يمكن تحديد كلمة المرور باستخدام الإعداد password.
لا تُدعَم الحماية بكلمة مرور إلا لأرشيفات ZIP (.zip, .zipx). يجب أن ينتهي مسار النسخة الاحتياطية بـ .zip أو .zipx حتى تُقبل كلمة المرور. سيؤدي استخدام كلمة مرور مع أي تنسيق آخر - بما في ذلك أرشيفات tar والمسارات غير المؤرشفة - إلى ظهور الخطأ BAD_ARGUMENTS:‏ Password is not applicable, backup cannot be encrypted.
BACKUP TABLE test_db.test_table
TO Disk('backups', 'password-protected.zip')
SETTINGS password='qwerty'
لاستعادة نسخة احتياطية محمية بكلمة مرور، يجب تحديد كلمة المرور مرة أخرى باستخدام الإعداد password:
RESTORE TABLE test_db.test_table
FROM Disk('backups', 'password-protected.zip')
SETTINGS password='qwerty'

النسخ الاحتياطية كأرشيفات tar

يمكن تخزين النسخ الاحتياطية ليس فقط كأرشيفات zip، بل أيضًا كأرشيفات tar. وتبقى الوظائف نفسها كما في zip، باستثناء أن الحماية بكلمة مرور غير مدعومة في أرشيفات tar. بالإضافة إلى ذلك، تدعم أرشيفات tar مجموعة متنوعة من طرق الضغط. لإنشاء نسخة احتياطية من جدول كأرشيف tar:
BACKUP TABLE test_db.test_table TO Disk('backups', '1.tar')
للاستعادة من أرشيف tar:
RESTORE TABLE test_db.test_table FROM Disk('backups', '1.tar')
لتغيير طريقة الضغط، يجب إضافة امتداد الملف الصحيح إلى اسم النسخة الاحتياطية. على سبيل المثال، لضغط أرشيف tar باستخدام gzip، شغّل:
BACKUP TABLE test_db.test_table TO Disk('backups', '1.tar.gz')
امتدادات ملفات الضغط المدعومة هي:
  • tar.gz
  • .tgz
  • tar.bz2
  • tar.lzma
  • .tar.zst
  • .tzst
  • .tar.xz

إعدادات الضغط

يمكن تحديد أسلوب الضغط ومستوى الضغط باستخدام الإعدادين compression_method وcompression_level، على التوالي.
BACKUP TABLE test_db.test_table
TO Disk('backups', 'filename.zip')
SETTINGS compression_method='lzma', compression_level=3

استعادة تقسيمات محددة

إذا كانت هناك حاجة إلى استعادة تقسيمات محددة مرتبطة بجدول، فيمكن تحديدها. لنُنشئ جدولًا بسيطًا مُقسّمًا إلى أربعة تقسيمات، ونُدرج بعض البيانات فيه، ثم نأخذ نسخة احتياطية من التقسيمين الأول والرابع فقط:
CREATE IF NOT EXISTS test_db;
       
-- إنشاء جدول مُقسّم
CREATE TABLE test_db.partitioned (
    id UInt32,
    data String,
    partition_key UInt8
) ENGINE = MergeTree()
PARTITION BY partition_key
ORDER BY id;

INSERT INTO test_db.partitioned VALUES
(1, 'data1', 1),
(2, 'data2', 2),
(3, 'data3', 3),
(4, 'data4', 4);

SELECT count() FROM test_db.partitioned;

SELECT partition_key, count() 
FROM test_db.partitioned
GROUP BY partition_key
ORDER BY partition_key;
   ┌─count()─┐
1. │       4 │
   └─────────┘
   ┌─partition_key─┬─count()─┐
1. │             1 │       1 │
2. │             2 │       1 │
3. │             3 │       1 │
4. │             4 │       1 │
   └───────────────┴─────────┘
شغّل الأمر التالي لأخذ نسخة احتياطية من التقسيمين 1 و4:
BACKUP TABLE test_db.partitioned PARTITIONS '1', '4'
TO Disk('backups', 'partitioned.zip')
نفّذ الأمر التالي لاستعادة التقسيمين 1 و4:
RESTORE TABLE test_db.partitioned PARTITIONS '1', '4'
FROM Disk('backups', 'partitioned.zip')
SETTINGS allow_non_empty_tables=true
آخر تعديل في ٢٩ يونيو ٢٠٢٦