Arabic EdTech на AWS Lambda: масштабируемый безсерверный бэкенд
5 мин. чтенияMohammad Shaker

Arabic EdTech на AWS Lambda: масштабируемый безсерверный бэкенд

Alphazed использует AWS Lambda для обслуживания 95,000+ учеников. Архитектура с Flask, MySQL и аналитическим озером для отслеживания результатов обучения.

Engineering

Короткий ответ

Alphazed использует AWS Lambda для обслуживания 95,000+ учеников. Архитектура с Flask, MySQL и аналитическим озером для отслеживания результатов обучения.

Безсерверная масштабируемость: запуск EdTech для изучения арабского на AWS Lambda

Alphazed полностью обслуживает бэкенд — более 95 000 учеников из 50+ стран — используя AWS Lambda с Serverless Framework. Архитектура включает Flask на Lambda за API Gateway, MySQL 8 на RDS, S3 для доставки контента и собственное аналитическое озеро (SQS → Kinesis Firehose → S3 → Glue → Athena). Тонкие обработчики Lambda уменьшают задержки холодного старта, и система обслуживает более 7 приложений из одного кода с переключением конфигураций во время выполнения.

Почему безсерверная архитектура подходит для EdTech?

Образовательные приложения имеют непредсказуемую нагрузку:

  • Утром в будни: родители скачивают приложение перед школой детей (всплеск трафика)
  • Днем в будни: занятия после школы (постоянная нагрузка)
  • В выходные: интенсивные марафонские сессии (2-3х обычной нагрузки)
  • Во время Рамадана: вечерний пик (семейное чтение Корана)
  • Школьные каникулы: совсем другой шаблон

Преимущества безсерверности:

  • Оплата за вызов: платите только за фактические запросы. 10 вызовов — 10 оплат, 100,000 — мгновенное масштабирование.
  • Нулевые задержки холодного старта для часто вызываемых функций — используем «всегда горячие» слои Lambda.
  • Автомасштабирование: обслуживаем от 10 до 10 000 одновременно без изменений инфраструктуры.
  • Отсутствие поддержки серверов: команда фокусируется на учебных планах и ИИ, а не на Kubernetes или балансировщиках нагрузки.

Глубокий обзор архитектуры

API Gateway → Lambda → RDS

[Клиентское приложение] (iOS, Android, Web)
    ↓
[API Gateway] (маршрутизация HTTP, ограничение запросов)
    ↓
[Lambda-обработчики] (Flask, 512MB, timeout 28с)
    ├── Маршруты приложения: /app/* (мобильные)
    ├── Пользовательские: /user/* (с авторизацией)
    └── Админские: /boss/* (админ-панель)
    ↓
[MySQL 8 на RDS] (устойчивое хранилище)
    ↓
[Ответ] (JSON клиенту)

Тонкие Lambda для скорости

Большинство 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])
}

Без Flask, без SQLAlchemy, без middleware — холодный старт около 500 мс против 5-10 с для полного Flask приложения.

Тяжелые эндпоинты (генерация контента, аналитика) используют полный Flask:

# Тяжёлый обработчик (~30MB с 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 обслуживает 7+ приложений с изоляцией на уровне базы:

-- Amal app
CREATE TABLE amal_users (...)
CREATE TABLE amal_content_bytes (...)
CREATE TABLE amal_user_memory (...)

-- Thurayya app 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 Endpoint] → [SQS очередь] (асинхронно)
    ↓ (быстрый ответ приложению)
    ↓ (аналитика в фоне)
[Kinesis Firehose] (пакетирует события каждые 5 мин или по 100Мб)
    ↓
[S3] (разбиение: s3://analytics-lake/amal/2026/03/28/events.parquet)
    ↓
[AWS Glue] (сканирует S3, определяет схему)
    ↓
[Athena] (SQL-запросы на Presto)
    ↓
[Дашборд] (показывает аналитику в реальном времени)

Обработка ошибок (Dead Letter Queue)

Если обработка аналитики падает:
SQS → [Firehose error]
  ↓
  [DLQ принимает ошибки]
  ↓
  [Оповещение команде]
  ↓
  [Основной API не влияет]

Аналитика не блокирует пользователей — дети могут учиться даже при сбое аналитики.

Стратегии оптимизации затрат

Стратегия 1: Тонкие Lambda для часто используемых эндпоинтов

  • Обычно мобильное приложение делает 10-20 вызовов за сессию
  • 95,000 активных пользователей × 3 сессии в день × 15 вызовов = 4,275,000 вызовов в день
  • При цене $0.0000002 за вызов — около $0.86 в день
  • Сокращение задержки холодного старта на 10 секунд экономит ~$500 в месяц

Стратегия 2: Резервирование RDS

  • 3-летнее резервирование даёт ~60% скидку по сравнению с по требованию
  • Используем db.r6i.xlarge (4 vCPU, 32GB RAM): $2,800/мес. по резерву против $6,500/мес. on-demand
  • Годовая экономия около $50,000

Стратегия 3: Кэширование

  • Кэшируем часто запрашиваемые данные (учебный план, контент) в ElastiCache (Redis)
  • Уменьшает количество запросов к RDS на 70%
  • Стоимость $800/мес. за кэш, экономия $2,000/мес. на RDS

Обслуживание 7+ приложений из одного кода

ПриложениеПрефиксТаблицы базыLambda стекСтатус
Amalamal_40+ таблицОбщийВ продакшене
Thurayyathurayya_40+ таблицОбщийВ продакшене
Qaisqais_35+ таблицОбщийБета
KidElitekidelite_40+ таблицОбщийВ продакшене
Alphazed Schoolschool_50+ таблицОбщийБета
Alphazed Montessorimontessori_45+ таблицОбщийВнутренний

Один бэкенд, одна конвейерная сборка, 6 одновременных приложений. Запуск нового приложения занимает недели, а не месяцы.

Часто задаваемые вопросы

Вопрос: Не ограничивает ли Lambda таймаут в 15 минут?

Ответ: Да, 15 минут — максимум, но мы редко запускаем такие долгие запросы. Тяжелые задачи (генерация контента, крупные экспорты) выполняются асинхронно через SQS и Step Functions.

Вопрос: Что если БД упадёт?

Ответ: RDS использует Multi-AZ с автоматическим переключением на резервную копию за ~60 секунд. Клиенты видят кратковременные таймауты, но восстановление быстрое.

Вопрос: Как управляется пул подключений к базе с безсостоянием Lambda?

Ответ: Каждый экземпляр Lambda поддерживает пул подключений, который переиспользуется при «тёплых» вызовах. Холодные старты получают свежие подключения. RDS Proxy стоит между Lambda и БД, чтобы контролировать лимиты подключений.

ПоделитьсяTwitterLinkedInWhatsApp

Похожие статьи