Skip to content
DynamoDB single-table sau Postgres? Cum am ales, pe fiecare workload, și unde am greșit
← ← Înapoi la Idei Development

DynamoDB single-table sau Postgres? Cum am ales, pe fiecare workload, și unde am greșit

Dezbaterea DynamoDB versus Postgres e purtată de obicei ca o religie. O tabără spune că datele relaționale aparțin unei baze relaționale și că designul single-table e un puzzle pe care îl rezolvi o dată și îl regreți pentru totdeauna. Cealaltă spune că Postgres nu scalează fără un îngrijitor și că DynamoDB e singurul store care te lasă să nu te mai gândești la capacitate. Ambele au dreptate în cazurile la care se gândesc și greșesc că există un singur răspuns.

Noi le rulăm pe amândouă, pe aceeași platformă, pentru un client din SUA. Șase tabele DynamoDB și un cluster Aurora Serverless v2 Postgres, alese workload cu workload. Iată regula pe care o folosim, cele patru workload-uri pe care le-a produs, cel pe care l-am pus în store-ul greșit și l-am mutat, și costul fiecărei părți.

Regula

Pune două întrebări despre workload, și răspunsul iese singur.

1. Cunoști tiparele de acces, și sunt mai puțin de vreo zece? DynamoDB e un store key-value cu indecși secundari. Proiectezi tabela în jurul interogărilor. Dacă interogările sunt cunoscute și puține, designul ăla e o după-amiază plăcută și tabela le va servi la orice scară, cu un cost fix mic per cerere. Dacă interogările sunt necunoscute, în evoluție sau ad hoc (un admin care are nevoie de „toate comenzile clienților din Texas care au cumpărat produsul X în martie”), fiecare întrebare nouă e un index nou sau un scan, și într-un an vei construi o a doua copie a datelor undeva unde se pot interoga.

2. Ai nevoie de tranzacții pe multe rânduri, join-uri sau agregări? DynamoDB are tranzacții, până la 100 de elemente. Nu are join-uri sau GROUP BY. Dacă workload-ul e „suma veniturilor pe produs pe săptămână” sau „actualizează comanda, stocul și registrul atomic”, Postgres face asta într-o instrucțiune, iar DynamoDB o face în cod de aplicație pe care îl vei scrie subtil greșit cel puțin o dată.

Tipare de acces cunoscute și puține, fără join-uri sau agregări: DynamoDB. Orice altceva: Postgres. La egalitate câștigă Postgres, pentru că prețul greșelii e asimetric: o tabelă Postgres care se dovedește a avea un tipar key-value fierbinte poate primi un index sau un cache; o tabelă DynamoDB care se dovedește a avea nevoie de join-uri are nevoie de o migrare.

tipare de acces cunoscute,mai puțin de ~10? da join-uri, agregări sautranzacții peste 100 de elemente? nu DynamoDB nu da Postgres · Aurora Serverless v2egalitățile vin aici: o presupunere greșită primește un index; în DynamoDB o presupunere greșită e o migrare Două întrebări pe fiecare workload, nu un răspuns pe companie.

Cele patru workload-uri

Sesiuni și găleți de rate-limit → DynamoDB. Un tipar de acces fiecare: citește după cheie, scrie după cheie, expiră prin TTL. Milioane de elemente mici, trafic cu vârfuri, zero interes să le interogăm vreodată după altceva decât cheia. E workload-ul DynamoDB din manual și costă vreo 4 $ pe lună la volumul nostru, on-demand, fără capacitate la care să te gândești. Să le pui în Postgres ar însemna o tabelă care e 90 % din volumul de scriere pentru 0 % din valoarea de business, și un job de vacuum ca să n-o lași să se umfle.

Catalogul de produse și configurația per tenant → DynamoDB, single-table. Șapte tipare de acces, toate cunoscute: produs după id, produse după tenant, produse după tenant și categorie, config după tenant, încă câteva. Multe citiri, scrieri rare, iar forma unui produs e un document, nu un set de rânduri legate prin join. O tabelă cu cheie compusă și două GSI-uri le servește pe toate șapte. Exercițiul de restaurare a arătat capcana cu pierderea setărilor, dar tabela în sine n-a avut nevoie de nicio schimbare în optsprezece luni.

Comenzi, plăți, registru → Postgres. E workload-ul unde a doua întrebare spune nu. O comandă atinge comanda, liniile ei, rezervarea de stoc și intrarea în registru într-o singură tranzacție; finanțele vor venituri pe produs pe regiune pe săptămână; suportul vrea „fiecare comandă a acestui client cu un refund în ultimele 90 de zile”. Join-uri, agregări, întrebări ad hoc și o preferință puternică pentru invarianții pe care ți-i dau cheile străine și constrângerile. Aurora Serverless v2 la minimum 0,5 ACU, recenzat separat.

Log de evenimente pentru indexul de căutare → DynamoDB cu Streams. Doar adăugare, citit doar de consumatorul de stream, expiră după 30 de zile. Tipar cunoscut, fără join-uri, iar Streams îți dă feed-ul de schimbări gratis.

Cel pe care l-am greșit

Profilurile de clienți au început în DynamoDB. Tiparele de acces păreau cunoscute: profil după id, profil după email, profiluri după tenant. Trei tipare, o formă de document, potrivire evidentă.

Apoi produsul a crescut. Suportul voia clienți după data înregistrării. Marketingul voia clienți care n-au comandat în 60 de zile, adică un join cu comenzile. Finanțele voiau valoarea pe durata de viață a clientului, o agregare. Fiecare cerere a devenit fie un GSI nou (am adăugat trei), fie un scan cu filtru care dura minute și costa bani reali, fie un export nocturn în Postgres care era vechi până dimineața. La a patra cerere aveam două copii ale datelor de clienți, una dintre ele mereu puțin greșită.

Am mutat profilurile în Postgres. Migrarea a durat o săptămână: scriere dublă câteva zile, backfill, comutarea citirilor, eliminarea scrierilor în DynamoDB, ștergerea tabelei o lună mai târziu. Cele trei GSI-uri au dispărut. Exportul nocturn a dispărut. Fiecare întrebare pe care a pus-o cineva despre clienți de atunci a fost o interogare, nu un proiect.

Lecția e în prima întrebare. „Tipare de acces cunoscute” înseamnă cunoscute pe toată durata de viață a datelor, nu cunoscute azi. Profilurile sunt entitatea pe care toată lumea din business vrea până la urmă s-o felieze altfel. Sesiunile nu sunt. Store-ul ar trebui să urmeze asta.

Unde locuiește fiecare workload workloadstorede ce$/lună sesiuni · găleți de rate-limitDynamoDB1 tipar, TTL, vârfuri~4 catalog · config de tenantDynamoDB single-table7 tipare, 2 GSI-uri, multe citiri~6 comenzi · plăți · registruPostgrestranzacții, join-uri, agregări~45 log de evenimente pentru căutareDynamoDB + Streamsdoar adăugare, feed de schimbări gratis~3 profiluri de cliențiDynamoDB → Postgres3 GSI-uri + export nocturn = store greșitmutat „Tipare de acces cunoscute” înseamnă cunoscute pe toată viața datelor, nu azi.

Cât costă fiecare parte, sincer

DynamoDB (4 tabele) Aurora Serverless v2 Postgres
Factura lunară ~13 $ on-demand ~45 $ la pragul de 0,5 ACU, mai mult sub sarcină
Planificarea capacității Niciuna Setezi ACU min și max; pragul e factura
Schimbări de schemă Gratis pentru atribute; un tipar nou de acces e un GSI nou, cu backfill ALTER TABLE, migrări, ocazional un lock de planificat
Backup-uri PITR pornit, restaurarea pierde setările PITR pornit, restaurarea e un cluster nou
Întrebări ad hoc Scan, sau export în altă parte O interogare
Surprize operaționale în 18 luni Una: partiție fierbinte pe o cheie de tenant prost aleasă, rezolvată cu un sufix Una: o tranzacție lungă a ținut un lock în timpul unei migrări
Lucrul pe care nu-l poți face Join-uri, agregări, interogări neplanificate Să nu te mai gândești deloc la ea

Partea DynamoDB e mai ieftină și mai liniștită pentru ce se pricepe. Partea Postgres costă mai mult și răspunde la mai multe. Niciuna dintre cifre nu e argumentul; workload-ul e.

Versiunea scurtă

Pe fiecare workload, două întrebări: tiparele de acces sunt cunoscute și puține, pe toată viața datelor; și are nevoie de join-uri, agregări sau tranzacții largi. Da și nu înseamnă DynamoDB. Orice altceva înseamnă Postgres. Așteaptă-te să greșești unul, și așteaptă-te ca cel greșit să fie entitatea pe care toată lumea din business vrea până la urmă s-o felieze altfel.

Dacă alegi un store pentru o platformă nouă, sau ai o tabelă DynamoDB cu al patrulea GSI și un export nocturn, te putem ajuta să sortezi workload-urile. E o sesiune la tablă, nu o religie.