Serverless su AWS Lambda per EdTech in Arabo
5 min di letturaMohammad Shaker

Serverless su AWS Lambda per EdTech in Arabo

Alphazed gestisce oltre 95.000 studenti con backend serverless su AWS Lambda, MySQL su RDS e un data lake per analisi personalizzate.

Engineering

Risposta rapida

Alphazed gestisce oltre 95.000 studenti con backend serverless su AWS Lambda, MySQL su RDS e un data lake per analisi personalizzate.

Alphazed esegue l'intero backend — servendo più di 95.000 studenti in oltre 50 Paesi — su AWS Lambda con Serverless Framework. L'architettura utilizza Flask su Lambda dietro API Gateway, MySQL 8 su RDS, S3 per la distribuzione dei contenuti e un data lake di analisi personalizzato (SQS → Kinesis Firehose → S3 → Glue → Athena). Handler Lambda minimalisti ottimizzano la latenza di cold-start e il sistema gestisce più di 7 app da un singolo codice con configurazioni runtime.

Perché il Serverless per l'EdTech?

Le app educative hanno modelli di utilizzo imprevedibili:

  • Mattine feriali: i genitori scaricano l’app prima di mandare i figli a scuola (picco di traffico)
  • Pomeriggi feriali: sessioni di pratica post-scuola (carico sostenuto)
  • Fine settimana: maratone intensive (2-3 volte il carico medio)
  • Durante il Ramadan: forte aumento serale (sessioni familiari di Corano)
  • Vacanze scolastiche: pattern totalmente diversi

Vantaggi del serverless:

  • Prezzi pay-per-request: paghi solo per l’utilizzo effettivo, da 10 a 100.000 richieste scalando istantaneamente
  • Zero cold start per endpoint ad alta frequenza: uso di Lambda layers "always warm" per richieste frequenti
  • Auto-scaling automatico: da 10 a 10.000 utenti contemporanei senza modifiche all’infrastruttura
  • Nessuna manutenzione server: il team si concentra su curriculum e AI, non su Kubernetes o bilanciatori

Dettagli sull'Architettura

API Gateway → Lambda → RDS

[Client App] (iOS, Android, Web)
    ↓
[API Gateway] (instradamento HTTP, limitazione richieste)
    ↓
[Lambda Handlers] (app Flask, 512MB RAM, timeout 28s)
    ├── Rotte app: /app/* (endpoint mobile)
    ├── Rotte utenti: /user/* (endpoint autenticati)
    └── Rotte admin: /boss/* (dashboard amministrazione)
    ↓
[MySQL 8 su RDS] (dati persistenti)
    ↓
[Risposta] (JSON al client)

Handler Lambda minimalisti per velocità

La maggior parte dei Lambda sono volutamente leggeri:

# Handler leggero (~100KB)
import json
import pymysql

def get_user_progress(event, context): user_id = event['pathParameters']['user_id']

# Connessione diretta al DB (senza overhead 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])
}

Niente import di Flask, SQLAlchemy o middleware. Risultato: cold start ~500ms contro 5-10s per un’app Flask completa.

Endpoint più pesanti (creazione contenuti, analisi) usano Flask completo:

# Handler pesante (~30MB con 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(): user = UserMemory.query.filter_by(user_id=request.json['user_id']).first() # ... logica complessa per sessioni personalizzate ... return jsonify(session_data)

Compromesso: cold start più lenti, ma meno richiesti.

Prefissi delle tabelle per app

Un’istanza RDS serve più di 7 app isolandole con prefissi a livello database:

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

-- App Thurayya CREATE TABLE thurayya_users (...) CREATE TABLE thurayya_content_bytes (...) CREATE TABLE thurayya_user_memory (...)

-- Altre app: qais_, kidelite_, ecc.

A deploy, la variabile d’ambiente APP_NAME seleziona il prefisso:

app_name = os.getenv('APP_NAME', 'amal')  # 'amal', 'thurayya', 'qais', ecc.

Query con prefisso dinamico

table_name = f'{app_name}_users' cursor.execute(f'SELECT * FROM {table_name} WHERE id = %s', (user_id,))

Il Data Lake per l'Analisi

Problema: interrogazioni dirette al database rallentano la produzione e bloccano le tabelle.

Soluzione: pipeline asincrona per analytics

[App Mobile]
    ↓ (invia evento)
[API Endpoint] → [Coda SQS] (asincrona)
    ↓ (risposta immediata)
    ↓ (non blocca analytics)
[Kinesis Firehose] (raggruppa eventi ogni 5 min o 100MB)
    ↓
[S3] (partizionato in s3://analytics-lake/amal/2026/03/28/events.parquet)
    ↓
[AWS Glue] (analizza e inferisce schema su S3)
    ↓
[Athena] (query SQL via motore Presto)
    ↓
[Dashboard] (dati in tempo reale)

Pattern Dead Letter Queue (DLQ):

Se falla l’analisi:
SQS → [Firehose fallisce]
  ↓
  [DLQ riceve messaggi falliti]
  ↓
  [Alert al team operativo]
  ↓
  [API di produzione non ne risente]

Gli analytics non bloccano mai l’esperienza utente. I bambini possono imparare anche se la pipeline è momentaneamente interrotta.

Strategie per ottimizzare i costi

Strategia 1: Lambdas leggere per endpoint ad alta frequenza

  • Un’app mobile tipica fa 10-20 chiamate API per sessione
  • 95.000 utenti attivi × 3 sessioni/giorno × 15 chiamate/sessione = 4,275 milioni chiamate/giorno
  • Costo approssimativo per chiamata: $0.0000002, cioè circa 0,86$ al giorno
  • Ridurre il cold start di 10s fa risparmiare circa $500 al mese

Strategia 2: RDS con Reserved Instances

  • Impegno 3 anni con circa 60% di sconto rispetto on-demand
  • Uso di db.r6i.xlarge (4 vCPU, 32GB RAM): $2.800 mese riservato vs $6.500 on-demand
  • Risparmio annuo stimato: circa $50.000

Strategia 3: Caching

  • Dati frequentemente richiesti (curriculum, contenuti) memorizzati in cache con ElastiCache (Redis)
  • Riduce le query su RDS del 70%
  • Costo della cache: $800 al mese, risparmio su RDS: $2.000/mese

7+ app da un unico codice backend

AppPrefissoTabelle DBStack LambdaStato
Amalamal_40+ tabelleCondivisoProduzione
Thurayyathurayya_40+ tabelleCondivisoProduzione
Qaisqais_35+ tabelleCondivisoBeta
KidElitekidelite_40+ tabelleCondivisoProduzione
Alphazed Schoolschool_50+ tabelleCondivisoBeta
Alphazed Montessorimontessori_45+ tabelleCondivisoInterno

Un backend, una pipeline di deploy, 6 app attive simultaneamente. Il lancio di una nuova app richiede settimane anziché mesi.

Domande Frequenti

D: Lambda ha un timeout massimo di 15 minuti?
A: Sì, ma noi raramente abbiamo richieste così lunghe. Carichi pesanti (generazione contenuti, esportazioni grandi) sono gestiti con job asincroni via SQS + Step Functions.

D: E se il database fallisce?
A: RDS usa failover Multi-AZ (replica primaria + standby). Il failover è automatico in circa 60 secondi. I client vedono timeout brevi ma il sistema si riprende velocemente.

D: Come gestite il pooling delle connessioni in Lambda senza stato?
A: Ogni istanza Lambda mantiene un pool di connessioni riutilizzato nelle invocazioni calde; alle cold start si crea una nuova connessione. RDS Proxy regola i limiti di connessioni tra Lambda e RDS.

Articoli correlati