El mòdul 5 va acabar amb un diagnòstic incòmode: el següent coll d'ampolla de MercadoFresco és la base de dades. No pas perquè mercadofresco-pedidos estigui mal configurada —té Multi-AZ, rèplica de lectura, còpies automàtiques i PITR des de 02-04—, sinó perquè fa quatre feines diferents i només una és realment la seva.

La temptació, arribats aquí, és obrir la consola i començar a crear serveis. DynamoDB sona ràpid, Redshift sona analític, ElastiCache sona a memòria cau. Aquesta és exactament la manera d'acabar amb sis bases de dades i els mateixos problemes, més el cost de mantenir-les.

Aquesta lliçó no crea cap recurs. És la lliçó en què la Marta s'asseu amb les dades que li va donar el mòdul 5 —mètriques de CloudWatch, traces de X-Ray, registres de l'ALB— i decideix, amb criteris explicables davant de direcció, quin motor rep cada càrrega de treball i per què. Les quatre lliçons següents executen aquesta decisió. Aquesta la justifica.

Nota sobre cost. Aquesta lliçó és de disseny: no es crea res i, per tant, no genera factura. Les xifres de cost que hi apareixen són estimacions de la regió eu-west-1 amb dades fictícies, i serveixen per comparar ordres de magnitud, no per pressupostar.

Contingut

  1. Per què «una base de dades per a tot» acaba fallant
  2. Els tres símptomes de l'acoblament de càrregues
  3. Persistència poliglota: una eina per a cada feina
  4. Les nou famílies de bases de dades
  5. Taula mestra: família, servei d'AWS i cas de MercadoFresco
  6. El primer criteri: el patró d'accés, no el model de dades
  7. Volum, creixement i latència objectiu
  8. Consultes conegudes davant de consultes exploratòries
  9. Consistència: el teorema CAP amb una caixa de maduixes
  10. Transaccions, esquema i cost
  11. Arbre de decisió
  12. OLTP davant d'OLAP
  13. Normalització, desnormalització i el canvi de mentalitat de NoSQL
  14. Les quatre càrregues de MercadoFresco, mesurades
  15. La decisió raonada, càrrega per càrrega
  16. Com es migra sense aturar la botiga
  17. AWS DMS i SCT: les eines de migració
  18. Errors habituals i consells
  19. Exercicis
  20. Conclusió

Per què «una base de dades per a tot» acaba fallant

Quan a 02-04 vam crear mercadofresco-pedidos, PostgreSQL era la resposta correcta. Hi havia una aplicació, unes poques taules i un equip de tres persones. Una base de dades relacional ben normalitzada resolia el catàleg, les comandes, la cistella i els informes amb el mateix SELECT.

El problema no és que aquella decisió fos dolenta. És que les càrregues de treball divergeixen amb el temps i la base de dades no. Divuit mesos després, dins la mateixa instància hi conviuen:

  • Escriptures minúscules i constants que caduquen soles (la cistella).
  • Transaccions que han de ser exactes per sempre (les comandes).
  • Lectures idèntiques repetides milers de vegades per minut (el catàleg).
  • Escombrades de milions de files per calcular sumes (els informes de la Sara).

Cadascuna d'aquestes quatre coses té un motor que la fa bé. Cap de les quatre no és PostgreSQL fent-ho tot alhora.

Els tres símptomes de l'acoblament de càrregues

Ficar càrregues incompatibles en un mateix motor produeix sempre els mateixos tres símptomes. Reconèixer-los és la meitat del diagnòstic.

1. Interferència de rendiment. Una càrrega degrada una altra perquè competeixen pel mateix recurs finit. A MercadoFresco, l'informe mensual de la Sara manté un pla d'execució amb Seq Scan sobre pedidos i lineas_pedido durant 40 segons; mentrestant, la memòria cau de PostgreSQL s'omple de pàgines històriques que expulsen les pàgines calentes del catàleg, i la latència de la botiga puja encara que l'informe no toqui cap taula de la botiga. És l'efecte més contraintuïtiu de l'acoblament: el mal no viatja pels bloqueigs, viatja per la memòria compartida.

2. Acoblament de disponibilitat. Si la instància cau, cauen les quatre càrregues. Un DROP INDEX mal mesurat, una consulta que esgota les connexions o una actualització de versió afecten tothom per igual. La rèplica mercadofresco-pedidos-lectura ho mitiga només per a lectures, i no per a totes.

3. Escalat del mínim comú múltiple. Quan una sola càrrega necessita més recursos, cal escalar tota la instància. Els informes de la Sara necessiten memòria; la cistella necessita IOPS d'escriptura; el catàleg necessita CPU per analitzar la mateixa consulta milers de vegades. Com que no es poden escalar per separat, s'acaba pagant una db.r6g.2xlarge perquè una de les quatre càrregues vagi bé tres hores al mes.

graph TD
    A[Botiga MercadoFresco] --> DB[(mercadofresco-pedidos<br/>PostgreSQL 16 db.t3.small)]
    B[Cistella i sessions] --> DB
    C[Cataleg de productes] --> DB
    D[Informes de la Sara] --> DB
    DB --> E[Interferencia: l'informe expulsa<br/>de la memoria cau les pagines del cataleg]
    DB --> F[Acoblament: una caiguda, quatre serveis aturats]
    DB --> G[Escalat: es paga pel pic de la carrega mes exigent]

Persistència poliglota: una eina per a cada feina

Persistència poliglota és el nom del principi que diu que una aplicació pot —i sovint ha de— fer servir diversos magatzems de dades, cadascun triat pel seu encaix amb una càrrega concreta. No és una moda de microserveis: és l'aplicació a l'emmagatzematge de la mateixa idea que ja acceptem sense discussió en altres àmbits. Ningú no desa les fotos del catàleg a PostgreSQL: són a mercadofresco-catalogo-fotos, a S3, des de 02-03. Això ja era persistència poliglota.

Les seves contrapartides són reals i cal dir-les abans de vendre-la:

A favor En contra
Cada càrrega rendeix al màxim del seu motor Més serveis per operar, vigilar i apedaçar
Escalat i cost independents per càrrega Més superfície de seguretat (IAM, xifratge, xarxa)
Una fallada no arrossega les altres càrregues Coherència entre magatzems: ja no hi ha un JOIN
Es pot canviar una peça sense tocar la resta L'equip ha de conèixer diversos models de dades
S'elimina la interferència de rendiment Còpies de seguretat i restauracions coordinades

La regla pràctica: afegeix un motor quan puguis anomenar la càrrega concreta que el justifica i mesurar la millora. Si no pots fer totes dues coses, no l'afegeixis. A MercadoFresco passarem d'una base de dades a quatre magatzems, i cadascun tindrà al darrere un mesurament del mòdul 5.

Les nou famílies de bases de dades

Convé entendre què modela cada família abans de mirar noms de producte. El model de dades determina quines consultes són barates i quines són cares, i això és l'únic que importa.

Relacional

Modela entitats i relacions en taules amb files i columnes, esquema fix i restriccions d'integritat. El motor garanteix propietats ACID i permet combinar taules amb JOIN en temps de consulta. Brilla quan les dades tenen relacions complexes, quan les consultes no es coneixen per endavant i quan la correcció transaccional és innegociable. No brilla quan cal escalar horitzontalment l'escriptura, quan l'esquema canvia cada setmana o quan el volum per consulta és de milions de files agregades.

Clau-valor

Modela un diccionari gegant: una clau retorna un valor opac. No hi ha JOIN ni consultes per camps arbitraris. A canvi, la cerca per clau és de cost constant i el motor pot repartir les claus entre centenars de particions sense coordinació. Brilla en sessions, cistelles, perfils i qualsevol accés del tipus «dona'm el registre X». No brilla quan cal preguntar «dona'm tots els registres que compleixin Y» sense haver-ho previst.

Documental

Modela documents JSON imbricats amb esquema flexible i índexs sobre camps interns. És un clau-valor que a més sap mirar dins del valor. Brilla en catàlegs amb atributs heterogenis —un lluç té «pes» i «origen de captura», un formatge té «curació» i «llet»— i en dades que es llegeixen sempre senceres. No brilla en agregacions massives ni quan les relacions entre documents són el centre del problema.

En memòria

Modela estructures de dades (cadenes, hashos, llistes, conjunts ordenats) que viuen a la RAM, amb latències de microsegons i persistència opcional. Brilla com a memòria cau, com a magatzem de sessions, com a comptador i com a marcador en temps real. No brilla com a font de veritat de dades que no es poden perdre, ni quan el conjunt de dades no cap a la memòria a un cost raonable.

Columnar o magatzem de dades

Modela fets i dimensions i desa les dades per columna en lloc de per fila, cosa que permet llegir només les columnes necessàries i comprimir-les moltíssim. Brilla en agregacions sobre centenars de milions de files. No brilla en la lectura o l'escriptura d'una fila concreta, que és precisament el que fa una botiga tot el dia.

Sèries temporals

Modela mesures amb marca de temps: mètriques, telemetria, sensors. Optimitza l'escriptura seqüencial, la retenció per antiguitat i les funcions de finestra temporal. Brilla en «temperatura de la cambra frigorífica cada 10 segons durant dos anys». No brilla en dades sense dimensió temporal dominant.

Grafs

Modela nodes i arestes i abarateix els recorreguts de profunditat variable: «clients que van comprar el mateix que aquest client i viuen a la seva ciutat, a tres salts». En un relacional això són JOIN recursius que exploten. Brilla en recomanacions, detecció de frau i xarxes socials. No brilla quan el problema és tabular i les relacions són d'un sol salt.

Cerca

Modela text invertit: per a cada terme, la llista de documents que el contenen, amb rellevància, tolerància a errors tipogràfics, sinònims i facetes. Brilla en el cercador de la botiga —«sarmó» ha de retornar «salmó»— i en l'anàlisi de registres. No brilla com a font de veritat transaccional.

Llibre major

Modela un registre immutable i verificable criptogràficament de canvis. Brilla quan cal demostrar davant d'un tercer que un històric no s'ha alterat. No brilla com a base de dades de propòsit general, i convé saber que Amazon QLDB és en fi de suport: per a casos nous, la recomanació d'AWS és utilitzar Aurora PostgreSQL amb taules de només inserció i signatures.

Taula mestra: família, servei d'AWS i cas de MercadoFresco

Família Servei d'AWS Latència típica Consultes ad hoc Cas de MercadoFresco
Relacional Amazon RDS / Aurora 1-10 ms Sí, SQL complet Comandes, factures, estoc: la font de veritat (06-03)
Clau-valor Amazon DynamoDB <10 ms, estable No, només per clau Cistella i sessions (06-02)
Documental Amazon DocumentDB 1-10 ms Parcial Fitxes de producte amb atributs heterogenis (futur)
En memòria ElastiCache / MemoryDB <1 ms No Memòria cau del catàleg i sessions web (06-05)
Columnar Amazon Redshift Segons Sí, analític Informes de la Sara sobre 18 mesos (06-04)
Sèries temporals Amazon Timestream ms Temporal Telemetria de temperatura de furgonetes frigorífiques
Grafs Amazon Neptune ms Recorreguts «Qui va comprar això també va comprar…»
Cerca Amazon OpenSearch Service ms Text i facetes Cercador de la botiga amb tolerància a errades
Llibre major (QLDB en fi de suport) Traçabilitat de lot de producte fresc

Els quatre en negreta són els d'aquest mòdul. La resta s'anomenen perquè sàpigues que existeixen i no pas per fer-los servir: cada servei que afegeixes és una cosa més per operar, i MercadoFresco no té equip per a nou.

El primer criteri: el patró d'accés, no el model de dades

L'error més estès a l'hora de triar base de dades és començar dibuixant les entitats. Al món relacional funciona, perquè el model relacional està dissenyat precisament perquè puguis normalitzar primer i consultar després de qualsevol manera. A la resta de famílies no funciona, i l'ordre correcte és l'invers.

Abans de triar motor, respon amb xifres aquestes preguntes per a cada càrrega:

  1. Quines operacions es fan, amb quina freqüència i en quina proporció de lectura contra escriptura?
  2. Per quin camp s'hi accedeix? Sempre el mateix, o canvia?
  3. Quants elements retorna una operació típica: un, cent, un milió?
  4. Quina és la latència màxima acceptable al percentil 99?
  5. Què passa si una dada es perd? I si es llegeix un valor de fa dos segons?
  6. Quant creix al mes i quina mida tindrà d'aquí a tres anys?

Aquestes sis respostes, i no el diagrama entitat-relació, decideixen el motor. El mòdul 5 ens va donar les sis per a les quatre càrregues de MercadoFresco: això és el que fa aquesta decisió defensable.

Volum, creixement i latència objectiu

Volum i creixement decideixen si un motor de node únic serveix. Un servidor relacional ben dimensionat gestiona sense dificultat desenes de terabytes; el problema apareix quan el que cal escalar és l'escriptura, perquè una base de dades relacional escala escriptures verticalment —màquina més gran— fins que s'acaben les màquines. Els motors clau-valor distribuïts escalen l'escriptura horitzontalment afegint particions, i això és el que els fa diferents.

La latència objectiu s'ha d'expressar sempre en percentils, mai en mitjana. A 05-01 vam veure que la mitjana de TiempoConfirmacionPedido era de 240 ms i el p99, de 1.900 ms: la mitjana amagava el problema. Els ordres de magnitud que cal memoritzar:

Origen Latència típica Què significa per a la botiga
Memòria cau en memòria (mateixa AZ) 0,2-1 ms Imperceptible
Clau-valor gestionada 3-10 ms Imperceptible en una petició
Relacional amb índex 1-10 ms Bé, si són poques consultes
Relacional amb Seq Scan 100 ms-60 s El p99 de 05-02
Magatzem columnar 1-30 s Acceptable en un informe, letal en una fitxa

Una fitxa de producte que fa 30 consultes relacionals de 8 ms triga 240 ms només en base de dades. La mateixa fitxa resolta des de la memòria cau triga menys de 10 ms. Aquest és tot l'argument de 06-05.

Consultes conegudes davant de consultes exploratòries

Aquest criteri separa el món en dos i gairebé ningú no el formula explícitament.

  • Consultes conegudes per endavant. Saps avui, en temps de disseny, les deu consultes que l'aplicació farà durant els propers dos anys: «dona'm la cistella del client X», «dona'm la comanda Y». Amb això pots modelar perquè cada consulta sigui un accés directe. És el terreny de DynamoDB.
  • Consultes exploratòries. La Sara no sap avui què preguntarà al març. Necessita creuar el que sigui amb el que sigui. Aquí cal un motor que accepti SQL arbitrari: relacional per a volums petits, columnar per a volums grans.

Triar DynamoDB per a una càrrega exploratòria produeix Scan sobre tota la taula, que és lent i car. Triar relacional per a una càrrega coneguda d'altíssim volum produeix el que té MercadoFresco. La mateixa dada pot viure als dos llocs: les comandes són transaccionals a Aurora i analítiques a Redshift, i això no és una contradicció sinó el disseny.

Consistència: el teorema CAP amb una caixa de maduixes

El teorema CAP diu que un sistema distribuït no pot garantir simultàniament consistència (Consistency), disponibilitat (Availability) i tolerància a la partició de xarxa (Partition tolerance). Com que la partició de xarxa no és opcional —els cables es tallen—, la tria real és entre consistència i disponibilitat quan hi ha partició.

Amb producte fresc es veu immediatament. Queden 3 caixes de maduixes i dos clients les demanen alhora des de nodes diferents que han perdut el contacte entre ells:

Tria Comportament Conseqüència per a MercadoFresco
Consistència (CP) El node aïllat rebutja l'operació fins a recuperar el contacte Ningú no ven de més; alguns clients veuen un error en afegir a la cistella
Disponibilitat (AP) Tots dos nodes accepten i es reconcilien després Ningú no veu errors; es poden vendre 4 caixes de 3

La resposta correcta depèn de l'operació, no de l'empresa:

  • Confirmar la comanda i descomptar estoc: consistència forta, sense discussió. Vendre maduixes que no existeixen significa trucar al client, reemborsar i perdre'l. Va a Aurora, amb transaccions.
  • Mostrar «queden poques unitats» a la fitxa: consistència eventual, perfectament acceptable. Que el comptador vagi dos segons endarrerit no fa mal a ningú. Va a la memòria cau.
  • Desar la cistella: consistència eventual acceptable, amb lectura forta només al pas final de compra. Va a DynamoDB, que permet demanar cada lectura d'una manera o de l'altra.

Aquesta distinció —consistència per operació, no per sistema— és el concepte que més rendiment allibera a la pràctica i el que més costa acceptar venint del món relacional.

Transaccions, esquema i cost

Transaccions. Pregunta si diverses escriptures han de tenir èxit o fracassar juntes. Confirmar una comanda és descomptar estoc, crear la comanda, registrar el pagament i generar la factura: o totes quatre o cap. Això demana un motor amb ACID real i un BEGIN … COMMIT natural. DynamoDB té TransactWriteItems amb límits (fins a 100 elements, sense lògica intermèdia) i serveix per a casos acotats, no per a un flux de negoci complet.

Esquema. Totes les files tenen els mateixos camps? El catàleg de MercadoFresco no: el peix té llotja d'origen i talla mínima, el vi té denominació i anyada. En relacional això són columnes nul·les o taules d'atributs; en documental o clau-valor és natural. Però esquema flexible no vol dir sense esquema: vol dir que l'esquema el valida l'aplicació en comptes del motor, i si ningú no el valida, acabes amb precio com a número en uns registres i com a cadena en uns altres.

Cost. Els models són estructuralment diferents i no es comparen mirant el preu per hora:

Model Es paga per Bo quan Dolent quan
Instància (RDS, Aurora provisionada) Hores d'instància, s'usi o no Càrrega estable i predictible Càrrega amb valls profundes
Sense servidor per capacitat (Aurora Serverless v2) ACU-hora consumida Càrrega variable amb vall nocturna Càrrega plana 24×7
Per petició (DynamoDB sota demanda) Cada lectura i escriptura Trànsit irregular o impredictible Volum enorme i constant
Per consulta (Athena) TB escanejats Consultes esporàdiques Moltes consultes diàries
Per memòria (ElastiCache) Hores de node Conjunt calent i acotat Dades fredes i voluminoses

Arbre de decisió

graph TD
    A[Nova carrega de treball] --> B{Es analitica:<br/>agregar milions de files?}
    B -->|Si| C{Consultes frequents<br/>o esporadiques?}
    C -->|Frequents| D[Redshift]
    C -->|Esporadiques sobre S3| E[Athena]
    B -->|No| F{S'hi accedeix sempre<br/>per una clau coneguda?}
    F -->|No| G{Cerca de text<br/>o relacions profundes?}
    G -->|Text| H[OpenSearch]
    G -->|Relacions| I[Neptune]
    G -->|Cap: SQL ad hoc| J[Aurora / RDS]
    F -->|Si| K{Es pot perdre<br/>sense consequencies?}
    K -->|Si, es una copia| L[ElastiCache]
    K -->|No, es la veritat| M{Necessita transaccions<br/>de diverses entitats?}
    M -->|Si| J
    M -->|No| N[DynamoDB]

L'arbre és una guia, no una llei. El seu valor és en l'ordre de les preguntes: primer analític o transaccional, després accés per clau o consulta lliure, després veritat o còpia, i només al final transaccions. Aquest ordre reprodueix l'impacte real de cada decisió.

OLTP davant d'OLAP

La primera bifurcació de l'arbre mereix desenvolupar-se, perquè és la que explica el 80 % dels problemes de MercadoFresco.

OLTP (transaccional) OLAP (analític)
Pregunta típica «Dona'm la comanda 84.213» «Tiquet mitjà per ciutat en 18 mesos»
Files tocades 1-100 10⁶-10⁹
Columnes tocades Totes les de la fila 3-6 de 40
Latència esperada Mil·lisegons Segons o minuts
Concurrència Milers de sessions Desenes
Escriptures Constants i petites Càrregues massives periòdiques
Emmagatzematge Per files Per columnes
Normalització Alta (3FN) Baixa (estrella)
Servei Aurora, RDS, DynamoDB Redshift, Athena

Quan la Sara executa el seu informe mensual a mercadofresco-pedidos està demanant a un motor OLTP que faci feina OLAP. PostgreSQL ho fa —és un bon motor— però llegeix files senceres de 40 columnes per usar-ne 4, no comprimeix res i no paral·lelitza. Que trigui 40 segons i arrasi la memòria cau no és una fallada: és la conseqüència previsible d'usar l'eina equivocada.

Normalització, desnormalització i el canvi de mentalitat de NoSQL

En relacional, normalitzar —cada dada en un sol lloc, sense duplicar— és la manera correcta de dissenyar. Evita anomalies d'actualització: si canvia el nom d'un producte, canvia en una fila i prou. El preu d'aquesta puresa és que reconstruir informació completa exigeix JOIN a cada consulta.

En clau-valor i documental es desnormalitza deliberadament: es duplica la dada perquè una sola lectura retorni tot el que cal, perquè no hi ha JOIN i perquè la lectura és l'operació cara d'optimitzar.

Normalitzat Desnormalitzat
Dada duplicada No Sí, expressament
Cost de lectura Diversos JOIN Una lectura
Cost d'escriptura Una escriptura Diverses escriptures coordinades
Risc Consultes lentes Còpies divergents
Canviar consultes noves Fàcil Pot exigir remodelar

El canvi de mentalitat que exigeix NoSQL es resumeix en quatre inversions respecte de l'hàbit relacional:

  1. Es dissenya des de les consultes, no des de les entitats.
  2. Duplicar no és un error, és la tècnica.
  3. La integritat la garanteix l'aplicació, no el motor.
  4. No s'afegeixen consultes noves de franc: una consulta imprevista pot requerir un índex secundari nou o reescriure el model.

La fallada clàssica —i ho veurem a 06-02— és portar DynamoDB a la mentalitat relacional: una taula per entitat, Scan per cercar i unió manual al codi. El resultat és més lent i més car que PostgreSQL, i sovint la conclusió errònia és «DynamoDB no serveix».

Les quatre càrregues de MercadoFresco, mesurades

Aquestes són les dades reals que el mòdul 5 va deixar damunt la taula. Són fictícies, però són el tipus de xifra que cal tenir abans de decidir.

Càrrega A: comandes i estoc

  • 900 comandes/hora al pic del divendres; unes 4.000 al dia.
  • Cada confirmació són 6 escriptures a 4 taules, dins d'una transacció.
  • Consultes exploratòries freqüents d'atenció al client: «comandes d'aquest client al març».
  • Volum: 340 GB, +12 GB/mes.
  • Pèrdua d'una dada: inacceptable. Consistència: forta.

Càrrega B: cistella i sessions

  • 180.000 escriptures/dia a sesiones; el 92 % són actualitzacions del mateix registre.
  • Accés sempre per id_cliente o id_sesion. Cap consulta exploratòria.
  • La taula ha crescut fins a 78 GB dels quals el 71 % són cistelles abandonades de fa més de 60 dies.
  • El VACUUM d'aquesta taula és l'operació que més E/S consumeix de tota la instància.
  • Pèrdua d'una dada: molesta, no greu. Consistència: eventual llevat del pas de pagament.

Càrrega C: catàleg

  • 4.100 lectures/minut en hora punta; el 94 % de les consultes retornen exactament el mateix resultat que l'anterior.
  • Els preus i les descripcions canvien un cop al dia, a les 06:00, en la càrrega de la llotja.
  • Volum: 1,2 GB. Cap sencer a la memòria diverses vegades.
  • Latència objectiu: <5 ms. Consistència: eventual, amb marge de minuts.

Càrrega D: informes

  • 3-8 informes al dia de la Sara, amb pics a final de mes.
  • Cadascun agrega entre 8 i 18 mesos: de 6 a 40 milions de files.
  • Fa servir 4-6 columnes de les 40 disponibles.
  • Durada actual: de 40 s a 6 min, amb impacte mesurat en la latència de la botiga.
  • Consistència: les dades d'ahir serveixen perfectament.

La decisió raonada, càrrega per càrrega

Càrrega Patró dominant Motor triat Raó decisiva Lliçó
A. Comandes i estoc OLTP transaccional, SQL ad hoc Aurora PostgreSQL Transaccions ACID i consultes lliures; compatible sense reescriure 06-03
B. Cistella i sessions Clau-valor, alta escriptura, dades efímeres DynamoDB Accés per clau, escala d'escriptura i TTL que esborra sol 06-02
C. Catàleg Lectura repetida idèntica ElastiCache (Redis) Latència <1 ms i descàrrega del 94 % de les lectures 06-05
D. Informes OLAP, agregació massiva Redshift Serverless Columnar i MPP; i sobretot, fora de producció 06-04

Val la pena fer explícit el que no es tria i per què, perquè una decisió sense alternatives descartades no és una decisió:

  • La cistella no va a ElastiCache encara que sigui ràpid: són dades del client que no volem perdre en una commutació per error, i necessitem que caduquin de manera auditable. Redis ho faria; DynamoDB amb TTL ho fa a més amb durabilitat de disc i sense dimensionar memòria.
  • Les comandes no van a DynamoDB: atenció al client fa consultes que ningú no va preveure, i la confirmació de comanda és una transacció de quatre entitats amb lògica intermèdia.
  • Els informes no es resolen amb la rèplica de lectura: la rèplica treu el bloqueig, però continua llegint per files, sense comprimir i sense paral·lelitzar. Passar de 40 s a 35 s no és la solució.
  • El catàleg no s'arregla amb més CPU a la base de dades: el problema no és que la consulta sigui lenta, és que es fa 4.100 vegades per minut per retornar el mateix.

I una nota d'ordre important: primer Aurora, després la resta. Migrar el motor principal abans de repartir càrregues evita fer dues migracions sobre la mateixa dada. A la pràctica, MercadoFresco executarà DynamoDB (06-02) i Aurora (06-03) en paral·lel perquè toquen dades disjuntes, i Redshift (06-04) i ElastiCache (06-05) després, perquè tots dos llegeixen del que hi ha abans.

Com es migra sense aturar la botiga

Cap d'aquestes migracions no es pot fer amb un tall de servei llarg. Hi ha tres estratègies, i es combinen.

Doble escriptura

L'aplicació escriu al magatzem antic i al nou alhora, llegeix de l'antic, i quan el nou porta setmanes coincidint, es canvia la lectura.

sequenceDiagram
    participant App as Botiga
    participant PG as PostgreSQL (antic)
    participant DDB as DynamoDB (nou)
    Note over App: Fase 1 · escriptura doble, lectura antiga
    App->>PG: escriure cistella
    App->>DDB: escriure cistella
    App->>PG: llegir cistella
    Note over App: Fase 2 · lectura nova amb reserva
    App->>DDB: llegir cistella
    alt no trobada
        App->>PG: llegir cistella (reserva)
    end
    Note over App: Fase 3 · nomes el nou
    App->>DDB: llegir i escriure

Els seus tres paranys: cal decidir què passa si la segona escriptura falla (el correcte gairebé sempre és registrar l'error i continuar, no trencar la comanda); cal migrar l'històric a part, perquè la doble escriptura només cobreix el que és nou; i cal comparar tots dos magatzems amb un procés automàtic abans de fiar-se'n.

Patró estrangulador

En lloc de migrar-ho tot de cop, s'intercepta una funcionalitat cada vegada i es redirigeix al sistema nou, fins que l'antic es queda sense feina i s'apaga. És el patró que segueix aquest mòdul: la cistella surt primer, després els informes, després el catàleg, i mercadofresco-pedidos acaba fent només allò per a què era bo.

Tall controlat

Per a càrregues que toleren una finestra —els informes, per exemple— n'hi ha prou d'exportar, carregar i canviar el destí. És la més simple i cal fer-la servir sempre que es pugui: la complexitat de la doble escriptura només es justifica quan el tall és inacceptable.

Estratègia Tall Complexitat Reversió Quan usar-la
Tall controlat Minuts o hores Baixa Fàcil Informes, càrregues internes
Doble escriptura Zero Alta Mitjana Cistella, sessions
Estrangulador Zero Mitjana Fàcil per funció Migració per fases
Rèplica promoguda 1-2 minuts Mitjana Difícil després de promoure Canvi de motor compatible

AWS DMS i SCT: les eines de migració

AWS Database Migration Service (DMS) copia dades entre magatzems i, el que és important, pot replicar els canvis de manera contínua (CDC) després de la càrrega inicial: l'origen continua en producció mentre el destí es manté sincronitzat. Admet orígens i destins heterogenis —PostgreSQL a Aurora, PostgreSQL a DynamoDB, PostgreSQL a Redshift o a S3—, que és exactament el ventall d'aquest mòdul.

# Estructura d'una tasca de DMS: instancia de replica, dos endpoints i una tasca.
# 1) La instancia de replica viu a la VPC, a les subxarxes de dades.
aws dms create-replication-instance \
  --replication-instance-identifier dms-mercadofresco \
  --replication-instance-class dms.t3.medium \
  --replication-subnet-group-identifier sng-mercadofresco-datos \
  --no-publicly-accessible \
  --tags Key=Proyecto,Value=mercadofresco Key=Entorno,Value=produccion \
         Key=Componente,Value=migracion Key=Propietario,Value=marta \
         Key=CentroCoste,Value=plataforma \
  --region eu-west-1 --profile mercadofresco-dev

# 2) L'endpoint d'origen apunta a la RDS actual. La contrasenya NO s'escriu aqui:
#    es referencia el secret de Secrets Manager creat a 04-03.
aws dms create-endpoint \
  --endpoint-identifier origen-mercadofresco-pedidos \
  --endpoint-type source --engine-name postgres \
  --secrets-manager-secret-id mercadofresco/produccion/rds/mfadmin \
  --secrets-manager-access-role-arn arn:aws:iam::111122223333:role/rol-dms-secretos \
  --database-name pedidos \
  --region eu-west-1 --profile mercadofresco-dev

Tres detalls que fan que la tasca funcioni o no:

  • dms.t3.medium és la instància de rèplica, no el destí. Es paga per hora mentre la tasca viu i cal esborrar-la en acabar: és l'oblit més car d'una migració.
  • El tipus de tasca full-load-and-cdc fa càrrega completa i després canvis continus. Requereix que l'origen tingui rds.logical_replication activat, cosa que obliga a reiniciar la instància: cal planificar-ho abans, no descobrir-ho el dia de la migració.
  • DMS no migra índexs, procediments ni restriccions per defecte: copia dades. L'esquema es prepara a part.

AWS Schema Conversion Tool (SCT) tradueix l'esquema i el codi —vistes, funcions, procediments— entre motors diferents, i genera un informe del que no pot convertir automàticament. Per a MercadoFresco, que va de PostgreSQL a Aurora PostgreSQL, no cal: el motor és el mateix. SCT és l'eina de les migracions heterogènies, típicament Oracle o SQL Server cap a PostgreSQL.

Avís de cost i neteja. Una migració deixa residus cars: instàncies de rèplica de DMS, instantànies manuals, clústers de destí en proves i buckets intermedis. Abans de tancar qualsevol migració, revisa l'etiqueta Componente=migracion a Cost Explorer (11-03) i esborra tot el que la porti. I no esborris l'origen fins a tenir almenys una restauració provada del destí.

Errors Habituals i Consells

Triar per moda. «Fem servir DynamoDB perquè escala.» Escala què, exactament, i des de quina xifra? Si una càrrega fa 40 escriptures per segon, PostgreSQL l'aguanta amb una mà lligada. La pregunta no és si un motor escala, sinó si la teva càrrega necessita aquesta escala. La moda costa cara perquè el cost no és la factura: és l'equip aprenent un model nou mentre hi ha incidències per atendre.

Migrar sense mesurar abans. Sense la línia base del mòdul 5 —latència p99, IOPS, encerts de memòria cau, durada dels informes— no es pot demostrar que la migració hagi millorat res. I si no es pot demostrar, la següent proposta d'arquitectura no s'aprova. Captura les mètriques la setmana abans, no l'endemà.

Fer servir NoSQL amb mentalitat relacional. Una taula de DynamoDB per entitat, Scan per cercar i unions al codi de l'aplicació. És lent, car i fràgil. Si no pots escriure la llista de consultes que la taula ha de servir, no estàs a punt per dissenyar-la.

Confondre «pot» amb «ha de». PostgreSQL té tipus JSONB, cerca de text complet, tipus geoespacials i fins i tot extensions vectorials. Pot fer gairebé tot. Això no vol dir que ho hagi de fer: la pregunta és si ho fa prou bé per al teu volum. Amb 1,2 GB de catàleg, la cerca de text de PostgreSQL fa de sobres; amb 300 GB i facetes, no.

Afegir un motor sense pla d'operació. Cada magatzem nou necessita: còpies de seguretat provades, alarmes a CloudWatch, política d'IAM de privilegi mínim, xifratge amb alias/mercadofresco-datos, etiquetes completes i algú que sàpiga restaurar-lo a les tres de la matinada. Si no pots comprometre't a aquestes sis coses, no l'afegeixis.

Oblidar que ara hi ha dues veritats. Tan bon punt la cistella viu a DynamoDB i la comanda a Aurora, ja no hi ha JOIN ni transacció que els abasti. Cal decidir explícitament què passa si una de les dues escriptures falla. El mòdul 7 tracta precisament d'això.

Consell: escriu la decisió. Un document d'una pàgina per càrrega —patró mesurat, opcions considerades, motor triat, criteri decisiu, com se'n mesurarà l'èxit— és el que converteix una migració en enginyeria. D'aquí a un any, quan algú pregunti per què la cistella és a DynamoDB, aquesta pàgina val més que la memòria de ningú.

Exercicis

Exercici 1: classificar cinc càrregues noves

MercadoFresco planeja cinc funcionalitats. Per a cadascuna, indica família de base de dades, servei d'AWS i el criteri decisiu (només un, el que més pesa):

  1. Traçabilitat del fresc. Cada lot de peix ha de poder demostrar davant de Sanitat el seu recorregut des de la llotja. 400 lots/dia, consultes raríssimes però legalment obligatòries, i l'històric no es pot alterar.
  2. Temperatura de les furgonetes. 30 vehicles envien la temperatura del compartiment cada 10 segons. Es consulta la corba de les últimes 24 hores i es conserven 2 anys per normativa.
  3. Cercador de la botiga. Els clients escriuen «pebrot», «sarmó» o «formatge curat d'ovella» i esperen resultats rellevants, amb filtres per categoria, al·lergògens i franja de preu.
  4. «Els clients com tu també van comprar». Recomanació basada en compres conjuntes, fins a tres salts de distància entre clients i productes.
  5. Notificacions enviades. Registre de cada correu i SMS enviat: 50.000/dia, es consulta només per id_cliente per a atenció al client, i s'esborra als 90 dies.

Exercici 2: aplicar CAP a una decisió concreta

MercadoFresco vol llançar «últimes unitats»: quan queden menys de 5 unitats d'un producte, la fitxa mostra un comptador en directe. L'equip proposa dos dissenys:

  • Disseny A: la fitxa consulta l'estoc real a la base de dades transaccional a cada càrrega.
  • Disseny B: l'estoc es publica en una memòria cau amb TTL de 30 segons, i la fitxa hi llegeix.

Respon: (a) què tria cada disseny en termes de CAP i què se sacrifica?; (b) amb 4.100 lectures per minut en hora punta, quina càrrega afegeix cadascun a la base de dades?; (c) què li passa a un client que afegeix a la cistella l'última caixa de maduixes en el disseny B?; (d) proposa un disseny C que combini tots dos i digues exactament en quin punt del flux de compra cal la lectura forta.

Exercici 3: pla de migració de la cistella

Escriu el pla de migració de la taula sesiones (78 GB, 180.000 escriptures/dia) de PostgreSQL a DynamoDB, sense tall de servei. Ha d'incloure: estratègia triada i per què; les fases amb el seu criteri de sortida mesurable; què es fa amb els 55 GB de cistelles abandonades de més de 60 dies; com es verifica que tots dos magatzems coincideixen; el pla de reversió a cada fase; i les tres mètriques del mòdul 5 amb què demostraràs davant de la Marta que la migració ha valgut la pena.

Solucions

Solució 1

# Família Servei Criteri decisiu
1 Relacional amb registre immutable Aurora PostgreSQL amb taules de només inserció Verificabilitat davant d'un tercer; QLDB és en fi de suport, així que la via actual és només-inserció més signatura i trail-mercadofresco com a suport d'auditoria
2 Sèries temporals Amazon Timestream Retenció per antiguitat: 259.200 punts/dia que es consulten gairebé sempre en finestra recent i després només es conserven; el cicle de vida memòria→magnètic el fa el motor
3 Cerca Amazon OpenSearch Service Tolerància a errades i facetes: «sarmó» ha de retornar «salmó», i això no ho dona un LIKE
4 Grafs Amazon Neptune Recorreguts de profunditat variable: tres salts en SQL són JOIN recursius que creixen exponencialment
5 Clau-valor DynamoDB Accés només per clau i caducitat: patró idèntic al de la cistella; TTL a 90 dies resol l'esborrat sense cap procés

Matís important per al cas 1: encara que tècnicament sigui traçabilitat d'aliments, el volum és ridícul (400 lots/dia). No justifica un motor nou. La resposta correcta operativament és resoldre-ho a Aurora amb una taula de només inserció i disparadors que impedeixin UPDATE i DELETE. Aquest és justament el consell de la lliçó: no afegeixis un motor si pots anomenar per què no.

Solució 2

(a) CAP. El disseny A tria consistència: la dada mostrada és sempre la real, a costa que cada visita a una fitxa depengui de la disponibilitat i la latència de la base de dades. El disseny B tria disponibilitat i latència: la fitxa respon en menys d'un mil·lisegon encara que la base de dades estigui saturada, a costa de mostrar un valor amb fins a 30 segons d'antiguitat. El que se sacrifica a B és exactitud momentània; el que se sacrifica a A és rendiment i aïllament de fallades.

(b) Càrrega afegida. Disseny A: 4.100 consultes per minut addicionals, unes 68 per segon, sobre la instància que ja és el coll d'ampolla. Disseny B: amb TTL de 30 segons i encara que cada producte es consulti constantment, la base de dades rep com a màxim 2 consultes per minut i producte; per a un catàleg de 600 productes actius, unes 1.200 per minut en el pitjor cas, i a la pràctica moltíssim menys perquè només es refresquen els productes que algú mira. La reducció és d'un a dos ordres de magnitud.

(c) El cas de l'última caixa. El client veu «en queden 2», afegeix a la cistella i arriba al pagament. Entre la seva lectura i la seva compra, un altre client se'n va endur les dues. En el disseny B l'error no ha d'aparèixer en afegir a la cistella, sinó en la confirmació de la comanda, on una transacció amb consistència forta descompta estoc i falla si no hi ha existències. L'experiència correcta és un missatge clar —«s'han exhaurit mentre completaves la comanda»— i el suggeriment d'un producte alternatiu. Mai no s'ha de confirmar una comanda llegint de la memòria cau.

(d) Disseny C. Lectura eventual des de la memòria cau per mostrar (fitxa, llistats, cercador) i lectura i escriptura fortes dins d'una transacció per comprometre (l'UPDATE stock SET unidades = unidades - :n WHERE id = :p AND unidades >= :n en la confirmació de la comanda, comprovant que ha afectat una fila). El punt exacte on cal la lectura forta és la confirmació de la comanda, no la cistella ni la fitxa. Aquest és el patró general: eventual per llegir, forta per decidir.

Solució 3

Estratègia: doble escriptura combinada amb estrangulador. El tall no és acceptable —una cistella perduda és una venda perduda— i la càrrega és d'escriptura contínua, així que el tall controlat queda descartat. L'estrangulador ordena les fases per funcionalitat; la doble escriptura garanteix que no es perd res durant la transició.

Fases i criteris de sortida:

Fase Què es fa Criteri de sortida mesurable
0 Modelar la taula mercadofresco-carritos a partir de les consultes reals extretes dels registres Llista tancada de consultes; cap no requereix Scan
1 Escriptura doble; lectura només de PostgreSQL; els errors a DynamoDB es registren però no trenquen res 7 dies amb taxa d'error d'escriptura a DynamoDB <0,01 %
2 Migrar l'històric útil amb DMS en mode càrrega completa 100 % de cistelles actives dels últims 30 dies presents a totes dues
3 Lectura des de DynamoDB amb reserva a PostgreSQL si no es troba 7 dies amb reserves <0,1 % de les lectures
4 Treure la reserva i l'escriptura a PostgreSQL 7 dies sense incidències; TiempoConfirmacionPedido p99 estable o millor
5 Eliminar la taula sesiones després de la còpia final Còpia verificada a mercadofresco-copias-basedatos

Els 55 GB de cistelles abandonades: no es migren. Migrar-los costaria escriptures i emmagatzematge per a dades que ningú no consultarà. S'exporten a S3 en Parquet com a arxiu històric (per si la Sara vol analitzar l'abandonament de cistella a Redshift, 06-04) i es descarten del destí. La taula nova neix amb TTL de 30 dies, de manera que el problema no es pot reproduir. Aquest és el punt més important de l'exercici: una migració és l'única ocasió barata de no arrossegar les escombraries.

Verificació: un procés diari que pren una mostra aleatòria de 1.000 claus de PostgreSQL, les cerca a DynamoDB i compara camp a camp, publicant una mètrica personalitzada MercadoFresco/Migracion/DiscrepanciasCarrito a l'espai MercadoFresco/Tienda, amb alarma a alertas-mercadofresco si supera 5 en 24 hores. Comparar la mostra, no el total: comparar 78 GB diaris costa més que la migració.

Reversió: a les fases 1 i 2 és immediata perquè PostgreSQL continua sent la font de lectura —n'hi ha prou de desactivar l'escriptura doble—. A la fase 3 és una bandera de configuració a Parameter Store (/mercadofresco/produccion/carrito/origen) que es canvia sense desplegar. A partir de la fase 4 la reversió ja no és trivial: per això la fase 4 no comença fins a acumular set dies nets a la 3.

Les tres mètriques: (1) TiempoConfirmacionPedido p99 de l'espai MercadoFresco/Tienda, que ha de baixar en desaparèixer les escriptures de sessió de la instància; (2) WriteIOPS i CPUUtilization de mercadofresco-pedidos, que han de caure en perdre 180.000 escriptures diàries i el VACUUM associat; i (3) el cost mensual amb etiqueta Componente=basedatos a Cost Explorer, comparant el mes anterior amb el posterior. Totes tres ja estaven instrumentades des del mòdul 5: per això aquesta migració es pot defensar amb dades.

Conclusió

Aquesta lliçó no ha creat ni un recurs, i probablement és la més important del mòdul. Saps per què una base de dades per a tot acaba fallant —interferència de rendiment a través de la memòria cau compartida, acoblament de disponibilitat i escalat del mínim comú múltiple— i coneixes la persistència poliglota amb les seves contrapartides honestes: més serveis per operar, més superfície de seguretat i la desaparició del JOIN entre magatzems.

Tens el mapa de les nou famílies —relacional, clau-valor, documental, en memòria, columnar, sèries temporals, grafs, cerca i llibre major— amb el seu servei d'AWS i el cas de MercadoFresco al qual s'aplicaria, i saps que només quatre entren en aquest mòdul perquè les altres cinc no tenen encara una càrrega que les justifiqui.

I sobretot tens l'ordre correcte de les preguntes: primer el patró d'accés —no el model de dades—, després volum i latència en percentils, després si les consultes es coneixen per endavant o són exploratòries, després consistència decidida per operació i no per sistema —eventual per mostrar que queden poques maduixes, forta per descomptar-les—, i només al final transaccions, esquema i cost. Amb la distinció OLTP davant d'OLAP com a primera bifurcació, i amb el canvi de mentalitat que exigeix NoSQL: es dissenya des de les consultes, duplicar és la tècnica i la integritat la garanteix l'aplicació.

La decisió queda presa i és el full de ruta del mòdul: DynamoDB per a la cistella i les sessions, per accés exclusiu per clau, escala d'escriptura i un TTL que resol els 55 GB d'escombraries; Aurora per a comandes i estoc, per transaccions ACID i consultes exploratòries sense reescriure res; Redshift Serverless per als informes de la Sara, per columnar, massivament paral·lel i, sobretot, fora de producció; i ElastiCache per al catàleg, perquè el problema mai no va ser que la consulta fos lenta sinó que es repetia 4.100 vegades per minut per retornar el mateix. Amb les estratègies per arribar-hi sense aturar la botiga: doble escriptura, patró estrangulador i tall controlat quan es pugui, amb DMS i la seva replicació contínua com a eina i SCT reservat per a les migracions heterogènies que MercadoFresco no necessita.

Comencem a executar per la càrrega més independent i la que més alleuja la instància actual. A 06-02, «Amazon DynamoDB», traurem la cistella i les sessions de PostgreSQL: modelarem la taula mercadofresco-carritos des de les seves consultes i no des de les seves entitats, veurem claus de partició i d'ordenació, disseny de taula única, Query davant de Scan, índexs secundaris, capacitat sota demanda davant de provisionada amb els comptes del pic del divendres, i el TTL que farà que els 55 GB de cistelles abandonades siguin un problema que ja no pot tornar a existir.

Curs d'AWS

Mòdul 1: Introducció a AWS

Mòdul 2: Serveis principals d'AWS

Mòdul 3: Xarxes i lliurament de contingut

Mòdul 4: Seguretat i identitat

Mòdul 5: Monitoratge i gestió

Mòdul 6: Bases de dades

Mòdul 7: Integració d'aplicacions

Mòdul 8: Eines per a desenvolupadors

Mòdul 9: Infraestructura com a codi i govern de comptes

Mòdul 10: Contenidors a AWS

Mòdul 11: Millors pràctiques i gestió de costos

© Copyright 2026. Tots els drets reservats