Serverless rješenja za EdTech na AWS Lambda
Alphazed pokreće cijeli svoj backend — koji opslužuje više od 95.000 učenika u preko 50 zemalja — na AWS Lambda uz Serverless Framework. Arhitektura koristi Flask na Lambda funkcijama iza API Gateway-a, MySQL 8 na RDS-u, S3 za distribuciju sadržaja i prilagođeni analytics lake (SQS → Kinesis Firehose → S3 → Glue → Athena). Tanke Lambda funkcije optimiziraju latenciju hladnog starta, a sistem servisira više od 7 aplikacija iz jedinstvene baze koda sa runtime konfiguracijom.
Zašto Serverless za EdTech?
Upotreba edukativnih aplikacija je nepredvidiva:
- Jutra radnih dana: roditelji preuzimaju aplikaciju prije škole (nagli skok prometa)
- Popodne radnih dana: vježbe poslije škole (stalni promet)
- Vikendi: intenzivni maratonski termini (2-3 puta veće opterećenje)
- Tijekom Ramazana: večernja upotreba raste (porodične kur'anske sesije)
- Školski praznici: potpuno drugačiji obrasci korištenja
Prednosti serverless pristupa:
- Naplata po zahtjevu: plaćate samo za stvarnu upotrebu, bilo da je 10 ili 100.000 korisnika u jednoj sekundi
- Nulti hladni startovi za frekventne dijelove: „Uvijek tople“ Lambda slojeve koristimo za često pozivane endpoint-e
- Automatsko skaliranje: od 10 do 10.000 korisnika bez promjena infrastrukture
- Nema održavanja servera: tim se fokusira na nastavni sadržaj i AI, a ne na klastere ili load balancere
Detaljna arhitektura
API Gateway → Lambda → RDS
[Klijentska aplikacija] (iOS, Android, Web)
↓
[API Gateway] (HTTP usmjeravanje, kontrola saobraćaja)
↓
[Lambda handleri] (Flask aplikacija, 512MB memorije, 28s timeout)
├── /app/* (mobilni endpointi)
├── /user/* (autentifikovani korisnici)
└── /boss/* (admin dashboard)
↓
[MySQL 8 na RDS] (postojani podaci)
↓
[Odgovor] (JSON nazad klijentu)
Tanki Lambda handleri za brzinu
Većina Lambda funkcija je minimalna i brza:
# Tanak handler (~100KB)
import json
import pymysql
def get_user_progress(event, context):
user_id = event['pathParameters']['user_id']
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])
}
Bez Flask uvoza, ORM-a ili middleware-a. Rezultat: oko 500ms hladni start u odnosu na 5-10 sekundi za potpun Flask app.
Teški endpointi (generisanje sadržaja, analitika) koriste pun Flask:
# Težak handler (~30MB sa 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()
# ... generiše personalizovanu sesiju ...
return jsonify(session_data)
Rizik: sporiji hladni startovi, ali se pozivaju rjeđe.
Prefiksi tabela po aplikaciji
Jedan RDS instanca opslužuje 7+ aplikacija s izolacijom na nivou baza podataka:
-- 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 (...)
-- Druge aplikacije: qais_*, kidelite_*, itd.
Tijekom deploy-a, varijabla okruženja APP_NAME bira prefiks:
app_name = os.getenv('APP_NAME', 'amal') # 'amal', 'thurayya', 'qais', itd.
# Dinamički upiti
table_name = f'{app_name}_users'
cursor.execute(f'SELECT * FROM {table_name} WHERE id = %s', (user_id,))
Analitički lake
Problem: direktni upiti za analitiku usporavaju produkciju i zaključavaju tabele.
Rješenje: asinkroni pipeline za analitiku
[Mobilna aplikacija]
↓ (šalje događaj)
[API Endpoint] → [SQS Queue] (asinkrono)
↓ (odmah vraća odgovor)
↓ (ne čeka analitiku)
[Kinesis Firehose] (grupisanje svakih 5 minuta ili 100MB)
↓
[S3] (particionirano: s3://analytics-lake/amal/2026/03/28/events.parquet)
↓
[AWS Glue] (indeksira i prepoznaje šemu)
↓
[Athena] (SQL upiti preko Presto engine-a)
↓
[Dashboard] (prikazuje real-time uvide)
Dead Letter Queue (DLQ) mehanizam
U slučaju grešaka u analitici:
SQS → [Firehose greška]
↓
[DLQ prima greške]
↓
[Obavještava operativni tim]
↓
[API u produkciji nije pogođen]
Analitika nikada ne blokira korisničke zahtjeve. Djeca mogu učiti čak i ako pipeline nije dostupan.
Strategije optimizacije troškova
1. Tanki Lambda handleri: prosječni korisnik zove API 15 puta po sesiji, 95.000 korisnika × 3 sesije × 15 poziva = 4.275.000 poziva dnevno. Lambda košta oko $0.0000002 po pozivu — ukupno $0.86 dnevno. Smanjenjem hladnog starta za 10 sekundi ušteda do $500 mjesečno.
2. Rezervisani RDS instance: trogodišnje rezervacije smanjuju troškove za ~60% u odnosu na na-demand.
3. Cache: često korišteni podaci (nastavni sadržaj, bajtovi sadržaja) keširani u ElastiCache (Redis), smanjujući broj upita prema RDS za 70%.
Jedna baza koda za 7+ aplikacija
| Aplikacija | Prefiks | Baze podataka | Lambda stack | Status |
|---|---|---|---|---|
| Amal | amal_ | 40+ tabela | Zajednički | Produkcija |
| Thurayya | thurayya_ | 40+ tabela | Zajednički | Produkcija |
| Qais | qais_ | 35+ tabela | Zajednički | Beta |
| KidElite | kidelite_ | 40+ tabela | Zajednički | Produkcija |
| Alphazed School | school_ | 50+ tabela | Zajednički | Beta |
| Alphazed Montessori | montessori_ | 45+ tabela | Zajednički | Interno |
Jedan backend i pipeline, šest simultanih aplikacija — novi projekti se lansiraju za sedmice, ne mjesece.
Česta pitanja (FAQ)
P: Lambda ima limit od 15 minuta timeouta, kako se nosite s tim?
O: Rijetko treba duže trajanje. Za težak workload (generisanje sadržaja, veliki eksporti) koristimo asinkrone zadatke s SQS i Step Functions.
P: Šta ako baza padne?
O: RDS koristi Multi-AZ failover (primarni + standby replika). Failover traje oko 60 sekundi, sa kratkim prekidima koje klijenti osjete.
P: Kako radite connection pooling u bezdržavnim Lambda funkcijama?
O: Svaka Lambda instanca održava pool konekcija za višestruke pozive dok je „topla“, hladni start koristi nove konekcije. RDS Proxy je posrednik između Lambda i RDS-a za upravljanje limitima konekcija.



