استعادة الملفات المحذوفة من S3: دليل عملي لاستخدام الإصدارات

حذفت ملفاً من S3 عن طريق الخطأ — هذا الموقف يحدث في الإنتاج أكثر مما يُعترف به. إذا كان لديك خاصية 'Versioning' مفعّلة على الـ Bucket، فالملف لم يُحذف فعلياً؛ بل أُضيف إليه علامة Delete Marker، والنسخة الأصلية لا تزال موجودة ويمكن استعادتها.

ملخص سريع (TL;DR): استعادة ملف محذوف من S3

الخطوة الإجراء الأداة
1 التحقق من تفعيل الإصدارات على الـ Bucket AWS CLI / Console
2 تحديد الـ Delete Marker وحذفه AWS CLI
3 التحقق من ظهور الملف مجدداً AWS CLI

كيف يعمل S3 Versioning عند حذف ملف

عندما تُفعّل Versioning على Bucket في S3، يحتفظ S3 بكل نسخة من كل كائن (Object). عند تنفيذ أمر حذف عادي (DELETE) بدون تحديد VersionId، لا يُحذف الكائن فعلياً — بل يُضاف كائن خاص يُسمى Delete Marker يحمل VersionId جديداً. هذا الـ Marker يجعل الكائن يبدو محذوفاً لأي طلب GET عادي، لكن النسخ السابقة لا تزال مخزّنة.

فكر في الأمر كأنك وضعت ورقة لاصقة على ملف في خزانة: الملف لا يزال هناك، لكن كل من يبحث يرى فقط 'محذوف'. إزالة الورقة اللاصقة (الـ Delete Marker) تُعيد الملف للظهور.
sequenceDiagram participant User as المستخدم participant S3 as Amazon S3 participant Storage as التخزين الداخلي User->>S3: DELETE object (بدون VersionId) S3->>Storage: إنشاء Delete Marker (VersionId جديد) S3-->>User: 204 No Content User->>S3: GET object (طلب عادي) S3->>Storage: البحث عن أحدث نسخة Storage-->>S3: Delete Marker (IsLatest=true) S3-->>User: 404 Not Found Note over User,Storage: عملية الاستعادة User->>S3: DELETE Delete Marker (بتحديد VersionId) S3->>Storage: حذف الـ Delete Marker S3-->>User: 204 No Content User->>S3: GET object (طلب عادي) S3->>Storage: البحث عن أحدث نسخة Storage-->>S3: النسخة الأصلية (IsLatest=true) S3-->>User: 200 OK + محتوى الملف
  1. طلب DELETE عادي: يُنشئ S3 كائن Delete Marker بـ VersionId جديد.
  2. طلب GET عادي: يرى S3 الـ Delete Marker ويُعيد خطأ 404.
  3. النسخ السابقة: لا تزال مخزّنة ويمكن الوصول إليها بتحديد VersionId.
  4. الاستعادة: حذف الـ Delete Marker يُعيد الكائن للظهور تلقائياً.

الخطوة 1: التحقق من تفعيل Versioning على الـ Bucket

قبل أي شيء، تأكد أن Versioning مفعّل فعلاً — وليس فقط في حالة 'Suspended'. الحالة Suspended تعني أن النسخ الجديدة لن تُحفظ، لكن النسخ القديمة التي حُفظت قبل الإيقاف لا تزال موجودة.

aws s3api get-bucket-versioning \
  --bucket YOUR_BUCKET_NAME

الناتج المتوقع عند التفعيل الكامل:

{
    "Status": "Enabled"
}

إذا كان الناتج فارغاً أو يحتوي على "Status": "Suspended"، فراجع قسم 'ماذا تفعل إذا لم يكن Versioning مفعّلاً' في نهاية هذا المقال.

الخطوة 2: عرض جميع نسخ الكائن المحذوف

الآن نحتاج لرؤية كل النسخ بما فيها الـ Delete Marker. الأمر list-object-versions يُظهر كل شيء — النسخ الحقيقية والـ Delete Markers معاً.

aws s3api list-object-versions \
  --bucket YOUR_BUCKET_NAME \
  --prefix YOUR_OBJECT_KEY

مثال على الناتج:

🔽 اضغط لعرض مثال الناتج الكامل
{
    "Versions": [
        {
            "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"",
            "Size": 1024,
            "StorageClass": "STANDARD",
            "Key": "reports/monthly-report.pdf",
            "VersionId": "abc123XYZ",
            "IsLatest": false,
            "LastModified": "2024-01-15T10:30:00.000Z"
        }
    ],
    "DeleteMarkers": [
        {
            "Owner": {
                "DisplayName": "myuser",
                "ID": "abc123"
            },
            "Key": "reports/monthly-report.pdf",
            "VersionId": "xyz789ABC",
            "IsLatest": true,
            "LastModified": "2024-01-16T08:00:00.000Z"
        }
    ]
}

ما يهمك هنا: الـ Delete Marker يحمل "IsLatest": true — هذا هو سبب ظهور الملف كمحذوف. النسخة الحقيقية موجودة في قسم Versions بـ VersionId مختلف.

الخطوة 3: حذف الـ Delete Marker لاستعادة الملف

استعادة الملف المحذوف من S3 تعني ببساطة حذف الـ Delete Marker. لحذفه يجب تحديد VersionId الخاص به تحديداً — وهو الـ VersionId الذي رأيته في قسم DeleteMarkers في الخطوة السابقة.

aws s3api delete-object \
  --bucket YOUR_BUCKET_NAME \
  --key YOUR_OBJECT_KEY \
  --version-id DELETE_MARKER_VERSION_ID

استبدل DELETE_MARKER_VERSION_ID بالقيمة من حقل VersionId في قسم DeleteMarkers (في المثال أعلاه: xyz789ABC).

الخطوة 4: التحقق من استعادة الملف

بعد حذف الـ Delete Marker، النسخة الأحدث في قسم Versions ستصبح هي الـ Latest تلقائياً. تحقق من ذلك:

aws s3api head-object \
  --bucket YOUR_BUCKET_NAME \
  --key YOUR_OBJECT_KEY

إذا نجحت الاستعادة، ستحصل على معلومات الكائن بدون خطأ. إذا ظهر خطأ 404، فهذا يعني وجود Delete Marker آخر أو أن الـ VersionId الذي حذفته لم يكن هو الـ Delete Marker الصحيح.

سيناريو متقدم: استعادة نسخة قديمة محددة (وليس آخر نسخة)

أحياناً لا تريد آخر نسخة — تريد نسخة من يوم بعينه. في هذه الحالة، بدلاً من حذف الـ Delete Marker فقط، تقوم بنسخ النسخة القديمة لتصبح هي الحالية.

aws s3api copy-object \
  --bucket YOUR_BUCKET_NAME \
  --copy-source YOUR_BUCKET_NAME/YOUR_OBJECT_KEY?versionId=TARGET_VERSION_ID \
  --key YOUR_OBJECT_KEY

هذا الأمر يُنشئ نسخة جديدة من النسخة القديمة المحددة، وتصبح هي الـ Latest. لا حاجة لحذف الـ Delete Marker أولاً — هذا الأمر يُنشئ نسخة جديدة فوق الـ Delete Marker.

تجربة حقيقية: التشخيص الخاطئ الشائع

المشكلة التي يقع فيها كثيرون: يُنفّذون أمر list-object-versions ويرون الـ Delete Marker، ثم يحذفون الـ Delete Marker بنجاح — لكن الملف لا يزال يُعطي 404.

السبب الفعلي في معظم الحالات: كان هناك أكثر من Delete Marker. هذا يحدث عندما يُحذف الكائن أكثر من مرة، أو عندما تُنفّذ عمليات حذف متعددة بسرعة. الأمر list-object-versions يُظهر كل الـ Delete Markers — تحقق من أن جميعها محذوفة وليس واحداً فقط.

aws s3api list-object-versions \
  --bucket YOUR_BUCKET_NAME \
  --prefix YOUR_OBJECT_KEY \
  --query 'DeleteMarkers[*].{Key:Key,VersionId:VersionId,IsLatest:IsLatest}'

إذا ظهر أكثر من Delete Marker، احذف كل واحد منهم بتحديد VersionId الخاص به.

الصلاحيات المطلوبة (IAM)

لتنفيذ عمليات الاستعادة، تحتاج الصلاحيات التالية على الـ Bucket:

🔽 اضغط لعرض سياسة IAM المطلوبة
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetBucketVersioning",
        "s3:ListBucketVersions",
        "s3:GetObjectVersion",
        "s3:DeleteObjectVersion",
        "s3:PutObject"
      ],
      "Resource": [
        "arn:aws:s3:::YOUR_BUCKET_NAME",
        "arn:aws:s3:::YOUR_BUCKET_NAME/*"
      ]
    }
  ]
}

لاحظ أن s3:DeleteObjectVersion مختلف عن s3:DeleteObject — الأول مطلوب لحذف نسخة بعينها (بما فيها الـ Delete Markers)، والثاني لعمليات الحذف العادية.

ماذا تفعل إذا لم يكن Versioning مفعّلاً

إذا لم يكن Versioning مفعّلاً وقت الحذف، فالكائن محذوف بشكل دائم من S3 ولا يمكن استعادته مباشرة. الخيارات المتاحة:

  • S3 Replication: إذا كان لديك Replication مُهيّأ لـ Bucket آخر، تحقق من الـ Destination Bucket.
  • AWS Backup: إذا كان الـ Bucket مُدرجاً في خطة Backup.
  • CloudTrail + S3 Access Logs: يمكنك تتبع من حذف الملف ومتى، لكن لا يمكن استعادته من هذه المصادر.

فعّل Versioning الآن على كل Bucket يحتوي بيانات مهمة — التكلفة الإضافية من تخزين النسخ أقل بكثير من تكلفة فقدان البيانات.

الخلاصة والخطوات التالية لاستعادة ملفات S3

استعادة ملف محذوف من S3 مع تفعيل Versioning عملية مباشرة: حدد الـ Delete Marker، احذفه بتحديد VersionId الخاص به، وتحقق من ظهور الملف. إذا أردت نسخة قديمة محددة، استخدم copy-object بدلاً من ذلك.

مسرد المصطلحات

المصطلح التعريف
Versioning خاصية في S3 تحتفظ بكل نسخة من كل كائن عند تعديله أو حذفه
Delete Marker كائن خاص يُضاف عند حذف كائن في Bucket مفعّل عليه Versioning، يجعل الكائن يبدو محذوفاً دون حذف النسخ السابقة
VersionId معرّف فريد لكل نسخة من الكائن في S3، يُستخدم للوصول لنسخة بعينها
IsLatest حقل يُشير إلى أن هذه النسخة هي الأحدث وستُعاد عند طلب GET عادي
copy-object عملية S3 API تنسخ كائناً (أو نسخة منه) لتصبح نسخة جديدة في نفس الـ Bucket أو مختلف

تعليقات

المشاركات الشائعة من هذه المدونة

استرجاع معرّف نسخة EC2 عبر خدمة البيانات الوصفية IMDSv2

أوضاع سعة DynamoDB: متى تختار On-Demand ومتى تختار Provisioned؟

فهم مهلة الرؤية في SQS: لماذا تُعالَج رسائلك مرتين؟