Alphazed کل بخش بکاند خود را — که به بیش از ۹۵ هزار دانشآموز در بیش از ۵۰ کشور سرویس میدهد — روی AWS Lambda با استفاده از Serverless Framework اجرا میکند. معماری شامل Flask روی Lambda پشت API Gateway، MySQL 8 روی RDS، S3 برای ارائه محتوا و یک دریاچه تحلیل سفارشی (SQS → Kinesis Firehose → S3 → Glue → Athena) است. هندلرهای کمحجم Lambda زمان راهاندازی سرد را بهینه میکنند و سیستم از یک کدبیس برای بیش از ۷ اپ با پیکربندی پویا در زمان اجرا پشتیبانی میکند.
چرا سرورلس برای آموزش فناوری؟
الگوهای استفاده اپهای آموزشی پیشبینیناپذیر است:
- صبحهای روزهای هفته: والدین قبل از فرستادن کودک به مدرسه اپ را دانلود میکنند (افزایش ترافیک)
- بعدازظهر روزهای هفته: جلسات تمرینی پس از مدرسه (بار مداوم)
- آخر هفتهها: جلسات فشرده چند ساعته (۲ تا ۳ برابر بار عادی)
- ماه رمضان: استفاده در شبها افزایش شدید دارد (جلسات قرآنی خانوادگی)
- تعطیلات مدرسه: الگوی کاملاً متفاوت
مزایای سرورلس:
- پرداخت به ازای درخواست: فقط برای استفاده واقعی هزینه میکنید. اگر ۱۰ کاربر به API وصل شوند، هزینه ۱۰ فراخوانی است. اگر ۱۰۰,۰۰۰ کاربر در لحظه ویروسی شوند، فوراً مقیاس میدهد.
- آغاز سرد صفر برای نقاط پرتکرار: از لایههای Lambda همواره گرم برای نقاط پرتکرار استفاده میکنیم
- مقیاسپذیری خودکار: از ۱۰ تا ۱۰,۰۰۰ کاربر همزمان بدون تغییر زیرساخت پاسخگو است
- نگهداری صفر سرور: تیم روی محتوا و هوش مصنوعی تمرکز دارد، نه کلاسترهای Kubernetes یا توازن بار
بررسی معماری
API Gateway → Lambda → RDS
[برنامه کاربر] (iOS، Android، وب)
↓
[API Gateway] (مسیریابی HTTP، محدودیت نرخ درخواست)
↓
[هندلرهای Lambda] (اپ Flask، ۵۱۲ مگابایت حافظه، محدودیت ۲۸ ثانیه)
├── مسیرهای اپ: /app/* (نقاط پایانی موبایل)
├── مسیرهای کاربر: /user/* (نقاط پایانی احراز هویتشده)
└── مسیرهای ادمین: /boss/* (داشبورد مدیریت)
↓
[MySQL 8 روی RDS] (دادههای دائمی)
↓
[پاسخ] (JSON به کلاینت)
هندلرهای کمحجم برای سرعت
اکثر Lambdaها به عمد کوچک هستند:
# هندلر کمحجم (~100کیلوبایت)
import json
import pymysql
def get_user_progress(event, context):
user_id = event['pathParameters']['user_id']
# اتصال مستقیم به دیتابیس (بدون سربار ORM)
conn = pymysql.connect(host='rds.aws.com', user='app', password='...', database='amal')
cursor = conn.cursor()
cursor.execute(
'SELECT concept_id, accuracy FROM user_memory WHERE user_id = %s',
(user_id,)
)
rows = cursor.fetchall()
conn.close()
return {
'statusCode': 200,
'body': json.dumps([{'concept': r[0], 'accuracy': r[1]} for r in rows])
}
بدون import فریمورک Flask، بدون ORM SQLAlchemy و بدون middleware. نتیجه: زمان شروع سرد ~۵۰۰ میلیثانیه در مقابل ۵ تا ۱۰ ثانیه برای اپ کامل Flask.
نقاط سنگین (تولید محتوا، پردازش تحلیلها) از Flask کامل استفاده میکنند:
# هندلر سنگین (~۳۰ مگابایت با Flask، SQLAlchemy، numpy)
from flask import Flask, jsonify
from models import UserMemory
import numpy as np
app = Flask(name)
@app.route('/content_duo/generate', methods=['POST'])
def generate_content_duo():
# منطق پیچیده با ORM
user = UserMemory.query.filter_by(user_id=request.json['user_id']).first()
# ... تولید جلسه سفارشی ...
return jsonify(session_data)
معامله: شروع سرد کندتر ولی کمتر فراخوانی میشوند.
پیشوند جداول جداگانه برای هر اپ
یک نمونه RDS بیش از ۷ اپ را با جداسازی سطح دیتابیس سرویس میدهد:
-- اپ Amal
CREATE TABLE amal_users (...)
CREATE TABLE amal_content_bytes (...)
CREATE TABLE amal_user_memory (...)
-- اپ Thurayya
CREATE TABLE thurayya_users (...)
CREATE TABLE thurayya_content_bytes (...)
CREATE TABLE thurayya_user_memory (...)
-- اپهای دیگر: qais_, kidelite_, و غیره
در زمان استقرار، متغیر محیطی APP_NAME پیشوند را انتخاب میکند:
app_name = os.getenv('APP_NAME', 'amal') # 'amal', 'thurayya', 'qais' و غیره
کوئریها پیشوند را بهصورت داینامیک استفاده میکنند
table_name = f'{app_name}_users'
cursor.execute(f'SELECT * FROM {table_name} WHERE id = %s', (user_id,))
دریاچه تحلیل دادهها
مشکل: کوئری مستقیم در دیتابیس برای تحلیل باعث کندی تولید و قفل شدن جداول میشود.
راهحل: پایپلاین تحلیل غیرهمزمان
[اپ موبایل]
↓ (ارسال رویداد)
[نقطه پایانی API] → [صف SQS] (غیرهمزمان)
↓ (پاسخ فوری به اپ)
↓ (منتظر تحلیل نمیماند)
[Kinesis Firehose] (رویدادها را هر ۵ دقیقه یا ۱۰۰ مگابایت دستهبندی میکند)
↓
[S3] (بخشبندیشده: s3://analytics-lake/amal/2026/03/28/events.parquet)
↓
[AWS Glue] (اسکیمای S3 را پیمایش و استنتاج میکند)
↓
[Athena] (کوئری SQL با میزبان Presto)
↓
[داشبورد] (نمایش نکات لحظهای)
الگوی صف نامه مرده (DLQ)
اگر تحلیل شکست خورد:
SQS → [شکست Firehose]
↓
[DLQ پیامهای ناموفق را میگیرد]
↓
[هشدار به عملیات ارسال میشود]
↓
[API تولید بدون تاثیر]
تحلیل هرگز روی درخواستهای کاربران تاثیر نمیگذارد. کودکان حتی اگر پایپلاین تحلیل قطع باشد، میتوانند ادامه دهند.
استراتژیهای بهینهسازی هزینه
استراتژی ۱: هندلرهای کمحجم برای نقاط پرتکرار
- هر اپ موبایل معمولاً ۱۰-۲۰ درخواست API در هر جلسه ارسال میکند
- ۹۵,۰۰۰ کاربر فعال × ۳ جلسه در روز × ۱۵ درخواست در هر جلسه = ۴.۲۷۵ میلیون درخواست در روز
- قیمت هر درخواست حدود ۰.۰۰۰۰۰۰۲ دلار است که برابر ۰.۸۶ دلار در روز میشود
- کاهش زمان شروع سرد به اندازه ۱۰ ثانیه صرفهجویی ۵۰۰ دلار در ماه دارد
استراتژی ۲: رزرو RDS
- رزرو سهساله با تخفیف حدود ۶۰٪ نسبت به پرداخت لحظهای
- از نمونه
db.r6i.xlargeبا ۴ هسته CPU و ۳۲ گیگابایت رم استفاده میکنیم: ماهانه ۲۸۰۰ دلار رزرو در مقابل ۶۵۰۰ دلار پرداخت لحظهای - صرفهجویی سالانه حدود ۵۰,۰۰۰ دلار
استراتژی ۳: کشینگ
- دادههای پرتکرار (برنامه درسی، محتوا) در ElastiCache (Redis) کش میشود
- تقریباً ۷۰٪ کوئریهای RDS را کاهش میدهد
- هزینه کش ماهانه ۸۰۰ دلار و صرفهجویی ۲۰۰۰ دلار در هزینه RDS
ارائه بیش از ۷ اپ از یک کدبیس واحد
| اپ | پیشوند | جدولهای دیتابیس | ستاپ Lambda | وضعیت |
|---|---|---|---|---|
| Amal | amal_ | ۴۰+ جدول | مشترک | تولید |
| Thurayya | thurayya_ | ۴۰+ جدول | مشترک | تولید |
| Qais | qais_ | ۳۵+ جدول | مشترک | نسخه بتا |
| KidElite | kidelite_ | ۴۰+ جدول | مشترک | تولید |
| Alphazed School | school_ | ۵۰+ جدول | مشترک | نسخه بتا |
| Alphazed Montessori | montessori_ | ۴۵+ جدول | مشترک | داخلی |
یک بکاند، یک خط لوله استقرار، ۶ اپ همزمان. راهاندازی اپ جدید در هفتهها به جای ماهها انجام میشود.
سؤالات متداول
س: آیا Lambda محدودیت توقف ۱۵ دقیقهای ندارد؟
ج: Lambda حداکثر ۱۵ دقیقه توقف دارد، اما ما به ندرت نیاز به درخواست طولانی داریم. بارهای سنگین (تولید محتوا، خروجیهای بزرگ) با کارهای غیرهمزمان SQS + Step Functions کار میکنند.
س: اگر دیتابیس قطع شود چی؟
ج: RDS دارای Multi-AZ با Failover خودکار (نسخه اصلی + ذخیره) است. تغییر حدود ۶۰ ثانیه طول میکشد و کلاینتها فقط تاخیر کوتاه میبینند.
س: چگونه با Lambda بدون حالت، اتصالهای دیتابیس مدیریت میشود؟
ج: هر نمونه Lambda استخر اتصال دارد که در فراخوانیهای گرم دوباره استفاده میشود. شروع سرد اتصال تازه میگیرد. در بین Lambda و RDS، RDS Proxy محدودیت اتصال را کنترل میکند.



