بتذكر هذاك اليوم منيح… كنا قاعدين في المكتب، فنجان القهوة بإيدي وأنا بفتح لوحة تحكم فواتير AWS. كانت الأرقام الشهرية قدامنا، وشعور بالغصة بدأ يتسلل إلينا كلنا. الفاتورة كانت أعلى من المتوقع، كالعادة. زميلي الشاب، أحمد، نظر إلي وقال بنبرة فيها إحباط: “يا عمي أبو عمر، إحنا بندفع على سيرفر شغال 24 ساعة عشان يعالج كم صورة بتنرفع باليوم؟ حاسس حالي برمي مصاري في الهوا!”.
كانت كلماته زي المي الباردة اللي صحتني. كان محق تمامًا. كان لدينا خادم (EC2 instance) قوي ومكلف، مهمته الوحيدة هي انتظار رفع المستخدمين لصورهم الشخصية، ليقوم بتغيير حجمها وحفظها. المشكلة؟ معظم عمليات الرفع كانت تحدث في ساعات الذروة، وباقي اليوم، كان الخادم “بتثاوب” بالمعنى الحرفي للكلمة – يستهلك موارد ومال وهو خامل تمامًا. من هنا بدأت رحلتنا للبحث عن حل، رحلة قادتنا إلى عالم غيّر طريقة تفكيرنا في البنية التحتية للأبد: عالم الحوسبة بدون خوادم أو الـ Serverless.
ما هي الحوسبة بدون خوادم (Serverless)؟ وهل هي حقًا “بدون خوادم”؟
أول ما تسمع كلمة “بدون خوادم”، ممكن تفكر إنه سحر! كيف لتطبيق أن يعمل بدون خوادم؟ الحقيقة، الاسم مضلل شوي. الخوادم لا تزال موجودة، لكن الفرق الجوهري هو أنك لم تعد مسؤولاً عنها. بدلًا من شراء أو استئجار خادم وتشغيله 24/7، أنت ببساطة تقوم برفع الكود الخاص بك إلى منصة سحابية (مثل AWS Lambda, Google Cloud Functions, Azure Functions)، وهذه المنصة هي التي تتكفل بتشغيل الكود فقط عند الحاجة إليه.
خليني أبسّطها بمثال من واقعنا:
تخيل أنك بحاجة لسيارة للذهاب إلى مشوار واحد في اليوم.
- الطريقة التقليدية (خادم مخصص): تشتري سيارة، وتدفع تأمينها، وصيانتها، وموقفها، وتظل السيارة واقفة أمام بيتك 24 ساعة، حتى لو استخدمتها لمدة 30 دقيقة فقط. هذا هو الخادم الذي تدفع ثمنه سواء كان يعمل أم لا.
- طريقة الـ Serverless: تطلب تاكسي (أو أوبر) عند الحاجة فقط. تدفع ثمن المشوار الذي قمت به بالضبط، وعندما تصل إلى وجهتك، يذهب التاكسي في طريقه. أنت لا تهتم بصيانة التاكسي أو تأمينه أو مكان وقوفه. هذا هو جوهر الـ Serverless.
في عالم الـ Serverless، أنت تدفع مقابل وقت التنفيذ الفعلي للكود الخاص بك بالمللي ثانية، وليس مقابل وقت الخمول.
رحلتنا من الـ EC2 إلى AWS Lambda: القصة بالتفصيل
حتى تكون الصورة أوضح، دعوني أشرح لكم بالتفصيل كيف كانت بنيتنا القديمة وكيف أصبحت مع الـ Serverless.
المشكلة: معالجة الصور عند الرفع (البنية القديمة)
كانت العملية تسير كالتالي:
- المستخدم يرفع صورته الشخصية عبر تطبيق الويب.
- التطبيق يقوم بحفظ الصورة الأصلية في مخزن سحابي (AWS S3).
- التطبيق يرسل رسالة إلى طابور (Queue) تحتوي على معلومات الصورة.
- لدينا خادم EC2 يعمل باستمرار، ومهمته الوحة هي فحص الطابور كل ثانية (Polling).
- عندما يجد رسالة، يقوم بتنزيل الصورة، وتغيير حجمها لعدة مقاسات (صورة مصغرة، متوسطة، كبيرة)، ثم يعيد رفعها إلى S3.
الكارثة كانت في النقطة رقم 4. كان لدينا خادم يعمل طوال الشهر (720 ساعة) ليقوم بعمل قد لا يستغرق في مجمله أكثر من 3-4 ساعات من المعالجة الفعلية. كنا ندفع ثمن 716 ساعة من “التثاؤب” والخمول كل شهر!
الحل مع Serverless: مرحبًا AWS Lambda
بعد البحث والقراءة، قررنا الانتقال إلى AWS Lambda، وهي خدمة الحوسبة بدون خوادم من أمازون. انظروا كيف أصبحت البنية الجديدة بسيطة وفعالة:
- المستخدم يرفع صورته الشخصية عبر تطبيق الويب مباشرة إلى AWS S3.
- مخزن S3 نفسه، عند استلامه لملف جديد، يقوم بتشغيل دالة Lambda (Lambda Function) تلقائيًا. هذا يسمى “Trigger” أو مُحفّز.
- دالة Lambda تحتوي على نفس الكود الذي كان على خادمنا القديم. تقوم بتنزيل الصورة، تغيير حجمها، وإعادة رفعها.
- تنتهي الدالة من عملها وتتوقف.
لاحظوا الفرق: لا يوجد خادم يعمل باستمرار، لا يوجد طابور، لا يوجد فحص مستمر. الكود يعمل فقط وفقط عند وقوع الحدث (رفع صورة جديدة). إذا تم رفع 1000 صورة في نفس اللحظة، ستقوم AWS تلقائيًا بتشغيل 1000 نسخة من دالتنا بالتوازي للتعامل مع الحمل. هذا هو التوسع التلقائي (Auto-scaling) في أبهى صوره، وبدون أي تدخل منا.
شوية كود يا جماعة: من النظرية للتطبيق
حتى لا يكون كلامنا نظريًا فقط، هذا مثال مبسط (باستخدام Python) لدالة Lambda يمكنها القيام بهذه المهمة. لا تخف من الكود، فكرته بسيطة جدًا.
import boto3
from PIL import Image
import io
s3_client = boto3.client('s3')
def resize_image_handler(event, context):
# 1. استخراج اسم الحاوية (Bucket) واسم الملف (Key) من الحدث
bucket_name = event['Records'][0]['s3']['bucket']['name']
key = event['Records'][0]['s3']['object']['key']
# تجنب الدوران اللانهائي (infinite loop)
if "thumbnail" in key:
return
# 2. تنزيل الصورة من S3 إلى الذاكرة
response = s3_client.get_object(Bucket=bucket_name, Key=key)
image_content = response['Body'].read()
image = Image.open(io.BytesIO(image_content))
# 3. تغيير حجم الصورة (مثال: إنشاء صورة مصغرة)
thumbnail_size = (128, 128)
image.thumbnail(thumbnail_size)
# 4. حفظ الصورة المصغرة في الذاكرة
buffer = io.BytesIO()
image.save(buffer, format="JPEG")
buffer.seek(0)
# 5. رفع الصورة المصغرة الجديدة إلى S3
new_key = f"thumbnails/{key.split('/')[-1]}"
s3_client.put_object(
Bucket=bucket_name,
Key=new_key,
Body=buffer,
ContentType='image/jpeg'
)
print(f"تم إنشاء الصورة المصغرة بنجاح: {new_key}")
return {'status': 'success'}
كل ما عليك فعله هو رفع هذا الكود إلى Lambda، ثم إعداد S3 ليقوم بتشغيله عند رفع أي ملف جديد. انتهى الأمر!
ما هو الـ FinOps؟ وكيف ساعدنا Serverless على تطبيقه؟
هذا التحول قادنا لا إراديًا لتبني مفهوم جديد علينا وقتها اسمه FinOps (اختصار لـ Financial Operations). الفكرة ببساطة هي دمج الوعي المالي في كل قرار تقني نتخذه. في عالم السحابة، حيث كل شيء هو عبارة عن فاتورة متغيرة، يصبح من الضروري فهم تكلفة كل ميزة (Feature) في نظامك.
الـ Serverless هو الحليف الأكبر للـ FinOps للأسباب التالية:
- فوترة دقيقة جدًا: بدلاً من فاتورة ضخمة لخادم واحد، أصبحت الفاتورة عبارة عن آلاف البنود الصغيرة: “دالة معالجة الصور كلفت 0.00001$ لهذه العملية”. هذا يعطيك رؤية واضحة لتكلفة كل جزء من تطبيقك.
- ربط التكلفة بالقيمة: أصبحنا قادرين على الإجابة على سؤال: “كم تكلفنا كل عملية رفع صورة؟”. هذا يساعد إدارة المنتج على اتخاذ قرارات أفضل.
- تحسين مستمر: عندما رأينا أن دالة معينة تستهلك وقتًا (ومالًا) أكثر من اللازم، أصبح لدينا دافع مباشر لتحسين الكود الخاص بها لجعله أسرع وأكثر كفاءة، لأن كل مللي ثانية نوفرها هي توفير حقيقي في الفاتورة.
نصائح من “أبو عمر”: متى تستخدم Serverless ومتى تبتعد عنه؟
بعد تجربتنا، أصبح لدي بعض القناعات حول متى تكون الحوسبة بدون خوادم هي الخيار الأمثل، ومتى يجب التفكير مرتين.
متى يكون Serverless هو الخيار الأمثل؟ ✅
- المهام المتقطعة والمُدارة بالأحداث (Event-driven): مثل حالتنا في معالجة الصور، أو إرسال إيميل ترحيبي عند تسجيل مستخدم جديد، أو معالجة بيانات من أجهزة إنترنت الأشياء (IoT).
- واجهات برمجة التطبيقات (APIs): بناء APIs باستخدام Lambda و API Gateway يعتبر نمطًا شائعًا جدًا. النظام يتوسع ويتقلص تلقائيًا مع عدد الطلبات، وتدفع فقط عند استدعاء الـ API.
- المهام المجدولة (Cron Jobs): بدلاً من حجز خادم لتشغيل سكربت كل ليلة، يمكنك استخدام “مُحفّز زمني” لتشغيل دالة Lambda في وقت محدد.
- الشركات الناشئة والمشاريع الجديدة (MVPs): إذا كنت تريد إطلاق منتجك بسرعة وبأقل تكلفة أولية ممكنة، فالـ Serverless يزيل عنك عبء إدارة البنية التحتية تمامًا.
“اسمع مني” – متى تفكر مرتين قبل استخدام Serverless؟ ⚠️
- العمليات طويلة الأمد جدًا: دوال Lambda لها حد أقصى للتشغيل (حاليا 15 دقيقة في AWS). إذا كانت لديك عملية تحتاج لساعات (مثل تدريب نماذج تعلم الآلة الكبيرة)، فقد لا تكون Lambda هي الخيار المناسب مباشرة (هناك حلول أخرى في عالم الـ Serverless مثل AWS Fargate أو Step Functions يمكنها التعامل مع هذا).
- حركة مرور ثابتة وعالية جدًا: إذا كان لديك خادم يعمل بنسبة 100% من طاقته على مدار 24/7، فقد يكون حجز خادم مخصص (Reserved Instance) أرخص لك من ناحية التكلفة الإجمالية. هنا يجب عمل الحسابات بدقة.
- مشكلة “البداية الباردة” (Cold Start): عندما لا يتم استدعاء دالتك لفترة، تقوم المنصة “بتجميدها”. عند أول استدعاء لها بعد فترة، تحتاج بضع مئات من المللي ثانية إضافية “للاستيقاظ”. هذا قد يكون مشكلة في التطبيقات شديدة الحساسية لزمن الاستجابة. (معلومة: هناك حلول لهذه المشكلة مثل Provisioned Concurrency).
الخلاصة: Serverless ليس مجرد تقنية، بل تغيير في العقلية 🚀
في النهاية، الانتقال إلى الحوسبة بدون خوادم لم يكن مجرد تغيير تقني، بل كان تحولًا في طريقة تفكيرنا. تحولنا من عقلية “توفير الموارد تحسبًا للذروة” (Provisioning for the peak) إلى عقلية “الدفع مقابل القيمة الفعلية” (Paying for value). تخلصنا من صداع إدارة الخوادم، تحديثاتها، وأمنها، وركزنا على ما يهم حقًا: كتابة كود يحل مشاكل حقيقية للمستخدمين.
نصيحتي لك: لا تخف من التجربة. ابدأ بمهمة صغيرة وغير حرجة في نظامك الحالي وحاول تحويلها إلى دالة Serverless. راقب التكاليف، وشاهد السهولة في الإدارة. الشعور الذي ستحصل عليه وأنت ترى فاتورتك السحابية تنخفض بينما خدمتك تتوسع وتخدم آلاف المستخدمين بسلاسة هو شعور، زي ما بنحكي عنا، “شي بيرفع الراس”.