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-1amb dades fictícies, i serveixen per comparar ordres de magnitud, no per pressupostar.
Contingut
- Per què «una base de dades per a tot» acaba fallant
- Els tres símptomes de l'acoblament de càrregues
- Persistència poliglota: una eina per a cada feina
- Les nou famílies de bases de dades
- Taula mestra: família, servei d'AWS i cas de MercadoFresco
- El primer criteri: el patró d'accés, no el model de dades
- Volum, creixement i latència objectiu
- Consultes conegudes davant de consultes exploratòries
- Consistència: el teorema CAP amb una caixa de maduixes
- Transaccions, esquema i cost
- Arbre de decisió
- OLTP davant d'OLAP
- Normalització, desnormalització i el canvi de mentalitat de NoSQL
- Les quatre càrregues de MercadoFresco, mesurades
- La decisió raonada, càrrega per càrrega
- Com es migra sense aturar la botiga
- AWS DMS i SCT: les eines de migració
- Errors habituals i consells
- Exercicis
- 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:
- Quines operacions es fan, amb quina freqüència i en quina proporció de lectura contra escriptura?
- Per quin camp s'hi accedeix? Sempre el mateix, o canvia?
- Quants elements retorna una operació típica: un, cent, un milió?
- Quina és la latència màxima acceptable al percentil 99?
- Què passa si una dada es perd? I si es llegeix un valor de fa dos segons?
- 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:
- Es dissenya des de les consultes, no des de les entitats.
- Duplicar no és un error, és la tècnica.
- La integritat la garanteix l'aplicació, no el motor.
- 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_clienteoid_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
VACUUMd'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-devTres 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-cdcfa càrrega completa i després canvis continus. Requereix que l'origen tinguirds.logical_replicationactivat, 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=migraciona 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):
- 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.
- 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.
- 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.
- «Els clients com tu també van comprar». Recomanació basada en compres conjuntes, fins a tres salts de distància entre clients i productes.
- Notificacions enviades. Registre de cada correu i SMS enviat: 50.000/dia, es consulta només per
id_clienteper 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
- Què és AWS?
- Configuració del teu compte d'AWS
- Infraestructura global d'AWS
- Consola d'administració d'AWS
- AWS CLI i SDK
Mòdul 2: Serveis principals d'AWS
Mòdul 3: Xarxes i lliurament de contingut
- Amazon VPC
- Grups de seguretat i llistes de control d'accés
- Elastic Load Balancing
- Amazon CloudFront
- Route 53
Mòdul 4: Seguretat i identitat
- AWS Identity and Access Management (IAM)
- AWS Key Management Service (KMS)
- Secrets Manager i Parameter Store
- AWS Shield
- AWS WAF
Mòdul 5: Monitoratge i gestió
- Amazon CloudWatch
- AWS X-Ray i traçabilitat distribuïda
- AWS CloudTrail
- AWS Config
- AWS Trusted Advisor
Mòdul 6: Bases de dades
- Com triar la base de dades adequada
- Amazon DynamoDB
- Amazon Aurora
- Amazon Redshift
- Amazon ElastiCache
Mòdul 7: Integració d'aplicacions
- Amazon SQS
- Amazon SNS
- Amazon EventBridge
- AWS Step Functions
- Patrons d'integració: idempotència, reintents i cues de missatges fallits
