فين اقدر احفظ الملفات؟

TLDR - بالمختصر

هذا المقال راح اذكر ايش هي الحلول المتوفرة لتخزين الملفات في السيرفر وايش هي الاشياء اللي لازم تاخذها بعين الاعتبار قبل ما تختار الحل اللي يناسبك. راح نتكلم عن:

  • تخزين الملفات على الخادم (Server Storage)
  • تخزين الملفات في قاعدة البيانات (Database Storage)
  • خدمات التخزين السحابي (Cloud Storage)
  • استخدام خدمات متخصصة مثل Cloudinary
  • شبكة توصيل المحتوى (CDN)

مقدمة

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

# مثال على الفورم
@app.route('/upload', methods=['POST'])
async def upload_file(file: UploadFile = File(...)):
    # ايش الخطوات اللي تحتاج تسويها هنا؟
    pass

طيب حتى نفهم احنا ايش قاعدين نشرح او ايش قاعدين نقيم هذا التشارت المفروض يوضح احنا فين:

Intro
  1. المفروض المستخدم يرسل الملف إلى السيرفر
  2. السيرفر يستقبل الملف
  3. السيرفر يتواصل مع مكان التخزين المستخدم
  4. مكان التخزين المفترض يرجع لك مرجع للملف هذا
  5. تخزن المرجع هذا في الداتابيس (حتى تقدر تحدد لاحقًا كيف تستعرضها او تشاركها لاحقًا)

1. التخزين على السيرفر مباشرة

File System storage

ايش الفكرة هنا؟ ببساطة،هذه الطريقة تعني تخزين الملفات مباشرة على السيرفر اللي يستضيف موقعك أو تطبيقك.

متى ممكن تستخدمها؟ هذه الطريقة مفيدة جدًا للمشاريع الصغيرة والمتوسطة التي لا تحتاج إلى تكامل مع خدمات تخزين خارجية.

عيوبها؟

العيوب
قابلية توسع محدودة: مع زيادة المستخدمين والملفات، ممكن يصير ضغط على الخادم.
مخاطر فقدان البيانات: في حال حدوث مشكلة في الخادم، ممكن تفقد الملفات إذا ما عندك نسخ احتياطية.
لما تستخدم Containers Environment، راح تحتاج تسوي Configurations خاصة لتخزين الملفات
أمان أقل: تحتاج لإعدادات إضافية لتأمين الملفات وحمايتها من الوصول غير المصرح به.

مثال على كيفية تخزين الملفات على الخادم:

FILE_UPLOAD_FOLDER = '/Uploads'
@app.route('/upload', methods=['POST'])
async def upload_file(file: UploadFile = File(...)):
    with open(os.path.join(FILE_UPLOAD_FOLDER, file.filename), 'wb') as f:
        f.write(file.read())
    # تخزين المرجع في قاعدة البيانات

    save_to_db(file.filename, FILE_UPLOAD_FOLDER)
    return 'File uploaded successfully'

نلاحظ هنا اننا نستخدم متغير FILE_UPLOAD_FOLDER لتحديد مكان تخزين الملفات و نلاحظ ان المرجع الي نخزنه في قاعدة البيانات هو اسم الملف فقط ممكن كمان نسوي ملفات لكل مستخدم او نحفظها في مجلدات مختلفة حسب نوع الملف المرفوع

اسئلة مهمة

  • طيب ايش بتسوي لو كنت تستخدم Containerized Deployment?
  • في هذه الحالة، ممكن تستخدم Volume لتخزين الملفات على الـ Container نفسه. هذا يسهل عملية النقل والنسخ الاحتياطي للملفات مع الـ Container.
  • ليش؟
  • لأن الContainers ephemeral، يعني إذا مسحت الـ Container، ممكن تفقد الملفات اللي عليه. بالتالي، تخزين الملفات على Volume يضمن استمرارية البيانات حتى بعد حذف الـ Container.
  • طيب لو كنت استخدم Kubernetes ؟
  • تقدر تستخدم NFS Server منفصل لتخزين الملفات ومشاركتها بين الـ Pods. هذا يسهل توزيع الملفات والوصول إليها من أي Pod في الـ Cluster.
  • طيب لو كنت تستخدم Serverless Deployment؟
  • المفروض ماتخزن الملفات بهذه الطريقة لأن الـ Serverless Functions مؤقتة وممكن تحذف بعد انتهاء الطلب. بدلًا من ذلك، استخدم خدمات تخزين السحابية مثل Amazon S3 أو Google Cloud Storage.

تخزين الملفات في قاعدة البيانات

Database Storage

ايش الفكرة هنا؟ كلنا نعرف ان الداتابيس تخزن البيانات النصية وهذا الهدف الأساسي منها، ولكن بعض قواعد البيانات تعطيك مساحة انك تخزن BLOB او بطريقة اسوء من كذا تقدر تحول الملفات إلى نص وتخزنها في الداتابيس كنصوص بس تكفى لاحد يسويها لأن هذا يزيد من حجم قاعدة البيانات ويبطئ أداء الاستعلامات و يخلي السيرفر يستهلك موارد CPU بشكل كبير خصوصا لو الملفات كبيرة

التخزين as Base64

@app.route('/upload', methods=['POST'])
async def upload_file(file: UploadFile = File(...)):
    # convert file to base64
    file_data = base64.b64encode(file.read()).decode('utf-8')
    insert_query = f"INSERT INTO files (name, data) VALUES ('{file.filename}', '{file_data}')"
    db.execute(insert_query)

    return 'File uploaded successfully :('

التخزين as BLOB

@app.route('/upload', methods=['POST'])
async def upload_file(file: UploadFile = File(...)):
    file_data = await file.read()
    insert_query = "INSERT INTO files (name, data) VALUES (%s, %s)"
    db.execute(insert_query, (file.filename, file_data))
    return 'File uploaded successfully'

طيب متى ممكن تستخدم هذه الطريقة؟

  • في حال ماعندك اي خيار غير هذا لمدة مؤقتة
  • في حال كانت الملفات صغيرة الحجم وقليلة العدد
  • في حال كنت بتستخدم IOT و تحتاج تخزين صور او ملفات صغيرة

خدمات التخزين السحابية

Cloud Storage

ايش الفكرة هنا؟ هذه الطريقة تعني استخدام خدمات تخزين سحابية مثل Amazon S3 أو Google Cloud Storage لتخزين الصور والملفات.

فكرة الBuckets تمثل الفكرة الأساسية لتخزين الملفات كل Bucket يمثل مجلد كبير يحتوي على الملفات الخاصة به ويعطيك المساحة للتوزيع او التنظيم بين الملفات بالطريقة الي تناسبك

مميزات الخدمات السحابية:

  • مقاومة للأعطال: توفر نسخ احتياطية واستعادة للبيانات.
  • قابلية التوسع: توفر مساحة تخزين غير محدودة.
  • أمان عالي: توفر طبقات حماية متعددة للبيانات.
  • تكلفة منخفضة: توفر خطط مجانية ومدفوعة بأسعار معقولة.

عيوب الخدمات السحابية:

  • ماتقدر تستخدمها لو عندك قيود امنية او قوانين تمنعك من استخدام السحابية
  • تكلفة: الخطط المدفوعة قد تكون باهظة الثمن للمشاريع الكبيرة.
  • تعقيد التكامل: قد تحتاج لبعض الجهد لدمجها مع تطبيقك.

طيب ايش الحل لو ابغا استخدم السحابية بس تكون مستضافة عندي؟

self-hosted cloud storage

تقدر تستخدم خدمات مثل MinIO لتشغيل خدمة تخزين سحابية على السيرفر الخاص بك و بيعطيك نفس الخصائص الي تحصل عليها من خدمات التخزين السحابية بس بشكل محلي

مثال على كيفية تخزين الملفات في Amazon S3:

import boto3

s3 = boto3.client('s3')
@app.route('/upload', methods=['POST'])
async def upload_file(file: UploadFile = File(...)):
    ref = s3.upload_fileobj(file.file, 'my-bucket', file.filename)
    # تخزين المرجع في قاعدة البيانات

    save_to_db(ref, 'my-bucket')

    return 'File uploaded successfully'

نلاحظ هنا اننا نستخدم مكتبة boto3 للتواصل مع Amazon S3 boto3 هو عبارة عن مكتبة جاهزة للتواصل مع AWS Services و رفعنا الملف في الBucket الخاص بنا و حفظنا المرجع في قاعدة البيانات


  1. استخدام خدمات متخصصة Cloudinary الوصف: منصة متخصصة في تخزين وإدارة وتحسين الصور والفيديوهات.
المميزاتالعيوب
تحسين الصور تلقائيًا: تغيير الحجم والجودة والتنسيقات بسهولة.تكلفة: الخطط المجانية محدودة، والميزات المتقدمة تحتاج اشتراك مدفوع.
شبكة CDN مدمجة: لتحميل أسرع من أقرب خادم للمستخدم.تعقيد التكامل: قد يحتاج لبعض الجهد لدمجها مع تطبيقك.

  1. شبكة توصيل المحتوى (CDN) الوصف: استخدام CDN مثل Cloudflare أو AWS CloudFront لتسريع تحميل الصور.
المميزاتالعيوب
سرعة تحميل أعلى: توصيل المحتوى من أقرب خادم للمستخدم.تكلفة إضافية: بعض خدمات CDN مدفوعة.
تقليل الحمل على الخادم الأصلي: يقلل من الطلبات المباشرة على خادمك.إعدادات إضافية: تحتاج لتكوين صحيح.

ايش فيه اشياء ثانية لازم تاخذها بعين الاعتبار؟

دائما الملفات المرفوعة تحتاج إلى اهتمام خاص بالأمان. ليش؟ لأن الملفات المرفوعة ممكن تحتوي على فيروسات أو برمجيات ضارة، وإذا ما تم التحقق منها بشكل صحيح، ممكن تتسبب في اختراق الموقع أو تلف البيانات.

الأمان أولاً:

  • التحقق من الملفات:
  • تحقق من نوع وحجم الملفات المرفوعة لمنع الملفات الضارة.
  • تأكد من Mimetype وحجم الملفات قبل حفظها.

نهاية المقال

تخزين الملفات يختلف عن تخزين البيانات النصية، ويحتاج إلى اهتمام خاص بالأمان والأداء اختيار الطريقة المناسبة يعتمد على حجم الملفات ونوع التطبيق والمتطلبات الأمنية في كل طريقة لها مميزات وعيوب، ويجب مراعاتها قبل اتخاذ القرار النهائي

هذا المقال يعتبر مقدمة للموضوع، ويمكنك البحث عن كل طريقة بشكل أعمق لفهم كيفية تطبيقها بشكل أفضل

تطوير الويب
تخزين الملفات
File Storage