A la lliçó 02-03 vam fer un càlcul que va deixar la Marta en silenci: de la factura mensual d'S3 del catàleg de fotos, el 97 % no era emmagatzematge, era transferència de sortida. Cada vegada que un client de Sevilla obre la fitxa del tomàquet de branca, la foto viatja sencera des d'un centre de dades d'Irlanda fins al seu mòbil, i MercadoFresco paga per cada byte. Si el client recarrega la pàgina, es paga un altre cop. Si deu mil clients miren la mateixa foto, es paga deu mil vegades pel mateix fitxer.

I ara, després de muntar el balancejador a 03-03, hi ha un segon cobrament per GB: l'ALB també factura pel trànsit que processa.

Amazon CloudFront és la xarxa de distribució de contingut (CDN) d'AWS: uns 700 punts de presència repartits pel món que guarden una còpia del teu contingut a prop de qui la demana. El client de Sevilla rep la foto des de Madrid en comptes de des de Dublín; la petició no arriba ni a S3 ni a l'ALB; i la transferència de sortida de CloudFront té una capa gratuïta permanent d'1 TB al mes que cobreix sencera la demanda actual de MercadoFresco.

En aquesta lliçó la Marta posa CloudFront davant de tot i ataca directament el problema del cost, sense perdre de vista l'altra cosa que aporta una CDN i que sovint importa més: latència.

Contingut

  1. Què és una CDN i com funciona el repartiment des de la vora
  2. Encerts i fallades de memòria cau
  3. Distribucions i orígens
  4. Grups d'origen i commutació per error
  5. Comportaments de memòria cau i patrons de ruta
  6. La clau de memòria cau: polítiques de memòria cau i de sol·licitud d'origen
  7. TTL: mínim, màxim i per defecte
  8. Compressió, HTTP/2 i HTTP/3
  9. Origin Access Control: tancar el bucket al món
  10. Invalidacions davant del versionat de noms de fitxer
  11. Dominis propis i el parany del certificat a us-east-1
  12. Contingut dinàmic a través de CloudFront cap a l'ALB
  13. CloudFront Functions i Lambda@Edge
  14. Registres, mètriques i taxa d'encerts
  15. Classes de preu i el càlcul d'estalvi de MercadoFresco
  16. Creació per CLI, invalidació i neteja

Què és una CDN i com funciona el repartiment des de la vora

Una CDN (Content Delivery Network) és una xarxa de servidors de memòria cau distribuïts geogràficament que se situen entre l'usuari i el servidor d'origen. CloudFront té tres nivells:

Nivell Quants Què fa
Edge locations ~700 en més de 100 ciutats Atenen l'usuari i guarden el contingut més popular
Regional edge caches ~13, més grans Segon nivell de memòria cau: si falla l'edge, es pregunta aquí abans que a l'origen
Origen El teu bucket S3, el teu ALB, o qualsevol servidor HTTP La font de la veritat

Les edge locations més properes als clients de MercadoFresco són Madrid i Marsella, amb sortida també per Londres i París. Un client de Sevilla que avui espera que la foto travessi 2.000 km fins a Dublín passarà a rebre-la des de Madrid, a 400 km.

El guany de latència és la meitat de l'argument i no s'ha de subestimar: una botiga que carrega mig segon més lenta perd conversions mesurables. L'altra meitat són els diners, i la veiem amb números al final de la lliçó.

Encerts i fallades de memòria cau

Tot el funcionament de CloudFront es redueix a aquest diagrama:

sequenceDiagram
    participant C as Client<br/>(Sevilla)
    participant E as Edge location<br/>(Madrid)
    participant R as Regional edge cache<br/>(Frankfurt)
    participant O as Origen<br/>mercadofresco-catalogo-fotos

    Note over C,O: FALLADA DE MEMORIA CAU (primera peticio)
    C->>E: GET /productos/tomate-rama.jpg
    E->>E: El tinc? No (Miss)
    E->>R: GET al segon nivell
    R->>R: El tinc? No (Miss)
    R->>O: GET a l'origen
    O-->>R: 200 + imatge (transferencia GRATIS a CloudFront)
    R-->>E: imatge (es desa)
    E-->>C: imatge (es desa) · ~350 ms

    Note over C,O: ENCERT DE MEMORIA CAU (peticions seguents)
    C->>E: GET /productos/tomate-rama.jpg
    E->>E: El tinc? Si (Hit)
    E-->>C: imatge des de Madrid · ~25 ms

Tres coses que aquest diagrama ensenya i que convé fixar:

  1. Només el primer usuari paga l'espera llarga. Els següents reben la resposta des de la vora.
  2. La transferència de l'origen a CloudFront és gratuïta quan l'origen és S3 (i també des d'un ALB o EC2 al mateix compte). Aquesta és la clau econòmica de tota la lliçó.
  3. Existeix un segon nivell. Encara que l'edge de Madrid no el tingui, potser el té la regional edge cache, i l'origen s'estalvia la petició igualment. Això millora molt la taxa d'encerts real respecte del que es calcularia a ull.

Cada resposta porta la capçalera X-Cache, que diu exactament què ha passat:

Valor de X-Cache Significat
Hit from cloudfront Servit des de l'edge, sense tocar l'origen
Miss from cloudfront No hi era: s'ha demanat a l'origen
RefreshHit from cloudfront Havia caducat, l'origen ha respost 304 Not Modified
Error from cloudfront L'origen ha fallat

Distribucions i orígens

Una distribució és la unitat de configuració de CloudFront. En crear-la, AWS assigna un nom de domini propi, del tipus d111111abcdef8.cloudfront.net, i desplega la configuració a totes les edge locations en uns minuts.

Dins d'una distribució es declaren un o diversos orígens. MercadoFresco en necessita dos:

Origen (Id) Tipus Domini Què serveix
origen-fotos-s3 S3 amb OAC mercadofresco-catalogo-fotos.s3.eu-west-1.amazonaws.com Fotos de productes i miniatures
origen-tienda-alb Personalitzat alb-mercadofresco-tienda-1234567890.eu-west-1.elb.amazonaws.com HTML, API, tot el dinàmic

La diferència entre els dos tipus d'origen no és cosmètica:

Origen S3 Origen personalitzat (ALB, EC2, servidor extern)
Protocol cap a l'origen Intern d'AWS HTTP o HTTPS, configurable
Accés restringit Origin Access Control (OAC) Capçalera secreta + grup de seguretat
Reenviament de capçaleres Limitat Complet
Mètodes permesos Només GET, HEAD, OPTIONS Tots, inclosos POST i PUT
Temps d'espera Fixos Ajustables (OriginReadTimeout)

Un matís que confon: si configures un bucket d'S3 com a lloc web estàtic (el mode que vam veure a 02-03, amb el seu propi domini .s3-website-), CloudFront el tracta com a origen personalitzat, no com a origen S3, i llavors no pots fer servir OAC. Per a MercadoFresco fem servir el punt d'enllaç REST d'S3 amb OAC, que és el correcte.

Grups d'origen i commutació per error

Un grup d'origen aparella dos orígens: un de primari i un de secundari. Si el primari retorna un dels codis d'error configurats, CloudFront reintenta automàticament contra el secundari, de manera transparent per al client.

{
  "Quantity": 1,
  "Items": [
    {
      "Id": "grupo-fotos-con-respaldo",
      "FailoverCriteria": {
        "StatusCodes": { "Quantity": 4, "Items": [500, 502, 503, 504] }
      },
      "Members": {
        "Quantity": 2,
        "Items": [
          { "OriginId": "origen-fotos-s3" },
          { "OriginId": "origen-fotos-s3-respaldo" }
        ]
      }
    }
  ]
}

Només funciona amb GET, HEAD i OPTIONS, i els criteris poden incloure a més 403 i 404. Per a MercadoFresco té sentit el dia que es repliqui el catàleg a un bucket d'una altra regió; avui és una configuració preparada, no activa. La commutació per error a nivell de DNS, que és un mecanisme diferent i complementari, s'estudia a la lliçó 03-05.

Comportaments de memòria cau i patrons de ruta

Un comportament de memòria cau (cache behavior) associa un patró de ruta amb un origen i amb un conjunt de regles. És l'equivalent a les regles de l'ALB, però a la vora.

MercadoFresco en defineix quatre:

Prec. Patró Origen Mètodes Política de memòria cau Per què
0 /productos/* origen-fotos-s3 GET, HEAD Memòria cau llarga (1 any) Les fotos no canvien: el nom porta versió
1 /miniaturas/* origen-fotos-s3 GET, HEAD Memòria cau llarga (1 any) Generades per Lambda, immutables
2 /api/* origen-tienda-alb Tots CachingDisabled Dades de comandes: mai no es desen a la memòria cau
(defecte) * origen-tienda-alb GET, HEAD, OPTIONS Memòria cau curta (60 s) HTML del catàleg

Regles d'avaluació, molt semblants a les de l'ALB:

  • Els comportaments s'avaluen per ordre de precedència i guanya el primer que coincideix.
  • El comportament per defecte (*) s'avalua sempre l'últim, sense excepció.
  • Els patrons admeten * i ?, i distingeixen majúscules de minúscules.

El comportament de /api/* mereix atenció: cal permetre tots els mètodes HTTP (GET, HEAD, OPTIONS, PUT, POST, PATCH, DELETE) perquè, si no, un client que confirmi una comanda amb POST rebria un 403 de CloudFront. I cal desactivar la memòria cau explícitament: desar a la memòria cau una resposta de /api/pedidos/4711 i servir-la a un altre client seria una fuita de dades greu.

La clau de memòria cau: polítiques de memòria cau i de sol·licitud d'origen

Aquesta secció és la que separa una CDN que estalvia diners d'una que no serveix de res.

La clau de memòria cau és el conjunt de dades amb què CloudFront identifica un objecte desat. Per defecte és només la ruta de l'URL. Però s'hi poden afegir capçaleres, galetes i cadenes de consulta. I aquí hi ha el parany:

Cada valor diferent de qualsevol element de la clau de memòria cau crea una entrada diferent a la memòria cau.

Un exemple aritmètic que ho deixa clar. Suposa que inclous a la clau de memòria cau la capçalera User-Agent, que té milers de valors diferents:

Elements a la clau de memòria cau Entrades per a UNA foto Taxa d'encerts
Només la ruta 1 ~95 %
Ruta + Accept-Encoding 2 (gzip, br) ~93 %
Ruta + CloudFront-Viewer-Country ~30 ~70 %
Ruta + User-Agent milers ~5 %
Ruta + totes les galetes Pràcticament una per usuari ~0 %

Amb User-Agent a la clau, CloudFront guarda una còpia diferent de la mateixa foto per a cada versió de cada navegador. Gairebé totes les peticions són fallades, totes van a l'origen, i has pagat per una CDN que no desa res a la memòria cau. És l'error més car i més freqüent de CloudFront.

Per distingir-ho bé, AWS separa dues polítiques:

Política de memòria cau Política de sol·licitud d'origen
Què controla Què forma la clau de memòria cau Què es reenvia a l'origen
Efecte a la memòria cau Cada valor crea una entrada nova Cap
Quan fer-la servir Només si el contingut canvia segons aquell valor Si l'origen necessita aquella dada per funcionar

El cas que aclareix la diferència: l'origen vol registrar el país del visitant als seus registres. Si poses CloudFront-Viewer-Country a la política de memòria cau, multipliques les entrades per 30. Si el poses a la política de sol·licitud d'origen, l'origen rep la dada a cada fallada de memòria cau i la memòria cau continua tenint una sola entrada. La segona és la correcta.

Les polítiques gestionades per AWS cobreixen gairebé tot:

Política gestionada Clau de memòria cau Quan
CachingOptimized Només la ruta Contingut estàtic: les fotos de MercadoFresco
CachingOptimizedForUncompressedObjects Només la ruta, sense compressió Fitxers ja comprimits (JPEG, vídeo)
CachingDisabled No es desa res a la memòria cau /api/*
Elemental-MediaPackage Específica de vídeo Streaming

I una política pròpia, quan de debò cal variar per idioma:

{
  "Name": "pol-cache-catalogo-mercadofresco",
  "Comment": "HTML del cataleg: varia per idioma i per pagina",
  "DefaultTTL": 60,
  "MinTTL": 0,
  "MaxTTL": 300,
  "ParametersInCacheKeyAndForwardedToOrigin": {
    "EnableAcceptEncodingGzip": true,
    "EnableAcceptEncodingBrotli": true,
    "HeadersConfig": {
      "HeaderBehavior": "whitelist",
      "Headers": { "Quantity": 1, "Items": ["Accept-Language"] }
    },
    "CookiesConfig": { "CookieBehavior": "none" },
    "QueryStringsConfig": {
      "QueryStringBehavior": "whitelist",
      "QueryStrings": { "Quantity": 2, "Items": ["pagina", "categoria"] }
    }
  }
}

Decisions d'aquesta política, una a una:

  • Accept-Language a la llista blanca: el catàleg se serveix en castellà i en català, així que que canvia el contingut. Multiplica les entrades per 2, no per milers.
  • CookieBehavior: none: les galetes de sessió no canvien l'HTML del catàleg. Incloure-les destruiria la memòria cau del tot.
  • Només dos paràmetres de consulta a la llista blanca: pagina i categoria sí que canvien el contingut. Els paràmetres de campanyes de màrqueting (utm_source, utm_medium…) no, i si s'hi incloguessin, cada enllaç de cada campanya seria una entrada de memòria cau diferent del mateix HTML.
  • EnableAcceptEncodingGzip i Brotli: CloudFront normalitza la capçalera i guarda les variants comprimides de manera intel·ligent, sense que comptin com a valors arbitraris.

TTL: mínim, màxim i per defecte

El TTL (Time To Live) és quant de temps guarda CloudFront un objecte abans de tornar a preguntar. Hi ha tres valors i la seva interacció amb les capçaleres de l'origen despista:

Paràmetre Què fa
MinTTL Temps mínim que es guarda, encara que l'origen en demani menys
DefaultTTL Temps que es fa servir si l'origen no envia Cache-Control
MaxTTL Temps màxim, encara que l'origen en demani més

La lògica completa:

  1. Si l'origen no envia Cache-Control ni Expires → s'aplica DefaultTTL.
  2. Si l'origen envia Cache-Control: max-age=N → es fa servir N, acotat entre MinTTL i MaxTTL.
  3. Cache-Control: no-store o private → no es desa a la memòria cau (llevat que MinTTL sigui més gran que 0, cas en què es desa igualment: una font clàssica de sorpreses).

Els valors de MercadoFresco:

Contingut MinTTL DefaultTTL MaxTTL Cache-Control de l'origen
Fotos /productos/* 0 31.536.000 (1 any) 31.536.000 public, max-age=31536000, immutable
Miniatures /miniaturas/* 0 31.536.000 31.536.000 public, max-age=31536000, immutable
HTML del catàleg 0 60 300 public, max-age=60
/api/* 0 0 0 no-store

Un any de memòria cau per a les fotos sona temerari fins que s'entén la tècnica del versionat de noms, que veiem d'aquí a dos apartats. El correcte és posar la capçalera a l'objecte d'S3 en pujar-lo, perquè allà també l'aprofiten els navegadors:

aws s3 cp foto-nueva.jpg s3://mercadofresco-catalogo-fotos/productos/tomate-rama-v3.jpg \
  --profile mercadofresco-dev --region eu-west-1 \
  --cache-control "public, max-age=31536000, immutable" \
  --content-type "image/jpeg"

immutable és una directiva que diu al navegador que ni tan sols pregunti si ha canviat. Elimina fins i tot les peticions de revalidació 304.

Compressió, HTTP/2 i HTTP/3

Tres ajustos que s'activen amb una casella i redueixen bytes i latència:

Compressió automàtica. Amb Compress: true, CloudFront comprimeix amb Gzip o Brotli les respostes de tipus de contingut comprimibles (HTML, CSS, JavaScript, JSON, SVG) quan el client ho admet, sempre que l'objecte pesi entre 1 KB i 10 MB. Brotli redueix un 15-20 % més que Gzip. Advertència: no comprimeix JPEG, PNG ni MP4, que ja estan comprimits; intentar-ho només gastaria CPU.

HTTP/2 i HTTP/3. S'activen per distribució:

Protocol Avantatge Estat
HTTP/1.1 Universal Compatibilitat
HTTP/2 Multiplexat: moltes peticions en una connexió Per defecte
HTTP/3 (QUIC) Sobre UDP; sobreviu al canvi de xarxa i arrenca més ràpid Cal activar-lo

HTTP/3 importa especialment per a MercadoFresco: bona part dels seus clients naveguen des del mòbil, i al mòbil les connexions canvien d'antena i de wifi constantment. QUIC manté la sessió quan això passa; TCP ha de reconnectar.

# A la configuració de la distribució
"HttpVersion": "http2and3"

Origin Access Control: tancar el bucket al món

Avui mercadofresco-catalogo-fotos té una política que permet s3:GetObject públic sota productos/. Això vol dir que qualsevol pot saltar-se CloudFront i descarregar directament des d'S3, i MercadoFresco paga la transferència cara. A més, fa possible el hotlinking: que una altra web enllaci les fotos de MercadoFresco i li carregui la factura.

Origin Access Control (OAC) resol les dues coses: fa que només CloudFront pugui llegir del bucket, signant cada petició a l'origen amb SigV4.

OAC substitueix l'antic OAI (Origin Access Identity). Si trobes documentació amb OAI, està desactualitzada: OAI no admet el xifratge amb KMS (la nostra clau alias/mercadofresco-datos), no funciona a totes les regions i no accepta POST/PUT. Per a tot el que sigui nou, OAC.

Creació del control d'accés:

OAC_ID=$(aws cloudfront create-origin-access-control \
  --profile mercadofresco-dev \
  --origin-access-control-config '{
    "Name": "oac-mercadofresco-catalogo",
    "Description": "Acces de CloudFront al bucket de fotos de MercadoFresco",
    "SigningProtocol": "sigv4",
    "SigningBehavior": "always",
    "OriginAccessControlOriginType": "s3"
  }' \
  --query 'OriginAccessControl.Id' --output text)

I la política del bucket, que és la peça essencial:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "SoloCloudFrontPuedeLeerLasFotos",
      "Effect": "Allow",
      "Principal": {
        "Service": "cloudfront.amazonaws.com"
      },
      "Action": "s3:GetObject",
      "Resource": [
        "arn:aws:s3:::mercadofresco-catalogo-fotos/productos/*",
        "arn:aws:s3:::mercadofresco-catalogo-fotos/miniaturas/*"
      ],
      "Condition": {
        "StringEquals": {
          "AWS:SourceArn": "arn:aws:cloudfront::111122223333:distribution/E2QWERTY123ABC"
        }
      }
    },
    {
      "Sid": "DenegarTodoLoQueNoVayaCifrado",
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:*",
      "Resource": [
        "arn:aws:s3:::mercadofresco-catalogo-fotos",
        "arn:aws:s3:::mercadofresco-catalogo-fotos/*"
      ],
      "Condition": {
        "Bool": { "aws:SecureTransport": "false" }
      }
    }
  ]
}

El més important d'aquesta política, clàusula a clàusula:

  • El principal és el servei cloudfront.amazonaws.com, no una identitat d'usuari.
  • La condició AWS:SourceArn és la part crítica: sense ella, qualsevol distribució de CloudFront de qualsevol compte d'AWS podria llegir el bucket. Restringeix el permís a la distribució concreta E2QWERTY123ABC del compte 111122223333.
  • Només es concedeix s3:GetObject, i només sota els dos prefixos del catàleg. CloudFront no pot llistar el bucket ni escriure-hi res.
  • La segona clàusula, amb Deny i aws:SecureTransport: false, rebutja qualsevol accés per HTTP sense xifrar. És una bona pràctica que convé tenir a tots els buckets.

El resultat, comparant l'abans i el després:

flowchart LR
    subgraph ABANS["ABANS: bucket amb lectura publica"]
        C1["Client"] -->|"paga transferencia cara"| S1[("mercadofresco-catalogo-fotos")]
        C2["Web aliena<br/>(hotlinking)"] -->|"i tambe paga MercadoFresco"| S1
    end

    subgraph DESPRES["DESPRES: bucket tancat amb OAC"]
        C3["Client"] --> CF["CloudFront<br/>E2QWERTY123ABC"]
        CF -->|"signa SigV4<br/>transferencia gratuita"| S2[("mercadofresco-catalogo-fotos")]
        C4["Acces directe a S3"] -.->|"403 Forbidden"| S2
    end

Després cal treure l'antiga política pública i comprovar que el bloqueig d'accés públic (vist a 02-03) continua actiu:

aws s3api put-bucket-policy --profile mercadofresco-dev --region eu-west-1 \
  --bucket mercadofresco-catalogo-fotos \
  --policy file://politica-oac-catalogo.json

# Verificacio: l'acces directe ha de fallar ara amb 403
curl -s -o /dev/null -w "S3 directe: %{http_code}\n" \
  https://mercadofresco-catalogo-fotos.s3.eu-west-1.amazonaws.com/productos/tomate-rama-v3.jpg

curl -s -o /dev/null -w "Per CloudFront: %{http_code}\n" \
  https://d111111abcdef8.cloudfront.net/productos/tomate-rama-v3.jpg

El resultat esperat és 403 al primer i 200 al segon. Aquell parell d'ordres és la verificació completa que OAC està ben muntat.

Un detall pràctic: les fotos estan xifrades amb la clau KMS alias/mercadofresco-datos (02-03). La política d'aquella clau ha de permetre kms:Decrypt al servei de CloudFront; si no, totes les peticions retornaran 403 i el missatge no serà gaire clar. KMS i les seves polítiques de clau s'estudien a 04-02.

Invalidacions davant del versionat de noms de fitxer

El Luis substitueix la foto del tomàquet per una de millor i la puja amb el mateix nom. CloudFront continua servint l'antiga durant un any, perquè així ho diu el TTL. Hi ha dues maneres de resoldre-ho, i una és clarament millor.

Opció A: invalidació. Es diu a CloudFront que oblidi un objecte a totes les edge locations.

aws cloudfront create-invalidation --profile mercadofresco-dev \
  --distribution-id E2QWERTY123ABC \
  --paths "/productos/tomate-rama.jpg"

# Invalidar-ho tot (lent i car; nomes per a emergencies)
aws cloudfront create-invalidation --profile mercadofresco-dev \
  --distribution-id E2QWERTY123ABC --paths "/*"

Opció B: versionat del nom. Cada versió de la foto es puja amb un nom diferent: tomate-rama-v1.jpg, tomate-rama-v2.jpg, tomate-rama-v3.jpg. L'HTML apunta a l'última, i com que l'URL és nova, és una fallada de memòria cau neta. L'antiga caduca sola.

Invalidació Versionat del nom
Temps fins a veure el canvi 1-5 minuts (propagar a 700 edges) Immediat
Cost 1.000 rutes gratis al mes; després 0,005 USD per ruta Zero
Tornada enrere Impossible: el vell s'ha esborrat Canviar l'HTML a v2
Objectes ja descarregats pels navegadors Continuen sent els vells Es demanen de nou, URL diferent
Risc en un desplegament Finestra d'inconsistència Cap
Escalabilitat Se satura amb desplegaments freqüents Il·limitada

La quarta fila és la decisiva i gairebé ningú no la veu venir: la invalidació neteja la memòria cau de CloudFront, però no la del navegador del client. Si el navegador ha desat la foto amb max-age=31536000, continuarà mostrant la vella durant un any passi el que passi. El versionat del nom resol també això, perquè l'URL és diferent.

Per això MercadoFresco adopta el versionat, i les invalidacions queden reservades per a emergències —una foto pujada per error, un preu equivocat a l'HTML desat a la memòria cau.

Dominis propis i el parany del certificat a us-east-1

Per defecte la distribució respon a d111111abcdef8.cloudfront.net. Per fer servir cdn.mercadofresco.example calen dues coses: declarar-lo com a nom de domini alternatiu (CNAME) i aportar un certificat TLS que el cobreixi.

⚠️ El parany clàssic de CloudFront

El certificat d'ACM per a CloudFront ha d'estar SEMPRE a la regió us-east-1 (Nord de Virgínia), sigui quina sigui la regió on visquin els teus recursos.

Això és així perquè CloudFront és un servei global i el seu pla de control és a us-east-1 (ho vam veure en parlar de serveis globals, regionals i zonals a 01-03). Un certificat emès a eu-west-1 és perfectament vàlid per a l'ALB, però CloudFront ni tan sols el veurà a la llista desplegable, i el missatge d'error no explica per què.

Conseqüència pràctica per a MercadoFresco: cal demanar dos certificats per al mateix domini.

# Certificat per a l'ALB: a la regio de l'ALB
aws acm request-certificate --profile mercadofresco-dev --region eu-west-1 \
  --domain-name mercadofresco.example \
  --subject-alternative-names "*.mercadofresco.example" \
  --validation-method DNS

# Certificat per a CloudFront: OBLIGATORIAMENT a us-east-1
aws acm request-certificate --profile mercadofresco-dev --region us-east-1 \
  --domain-name mercadofresco.example \
  --subject-alternative-names "*.mercadofresco.example" \
  --validation-method DNS

Tots dos són gratuïts i tots dos es renoven sols. Tots dos queden en PENDING_VALIDATION fins que es creïn els registres CNAME de validació, cosa que farem a la lliçó 03-05.

A més, tota distribució hauria de forçar HTTPS:

Ajust Valor Efecte
ViewerProtocolPolicy redirect-to-https Qui entri per HTTP rep un 301 a HTTPS
MinimumProtocolVersion TLSv1.2_2021 No s'accepten versions antigues de TLS
OriginProtocolPolicy (ALB) https-only El tram CloudFront→ALB també va xifrat

Contingut dinàmic a través de CloudFront cap a l'ALB

Una CDN serveix per a més que fitxers estàtics. Passar també l'HTML i l'API per CloudFront aporta coses fins i tot quan no es desa res a la memòria cau:

Avantatge Per què passa
Connexió TLS més propera La salutació TLS es completa a Madrid, no a Dublín: s'estalvien diversos viatges d'anada i tornada
Connexions persistents a l'origen CloudFront manté connexions obertes amb l'ALB i les reutilitza
Xarxa troncal d'AWS De l'edge a l'origen es viatja per la xarxa privada d'AWS, més estable que internet
Un únic punt per a WAF i Shield La protecció s'aplica a la vora, abans d'arribar a la VPC — 04-04 i 04-05
Compressió i HTTP/3 de franc Encara que l'origen no els admeti
Menys trànsit processat per l'ALB Tot el que es pot desar a la memòria cau deixa de comptar com a LCU

Quan no compensa: si l'aplicació és interna i tots els usuaris són a la mateixa regió que l'origen, CloudFront afegeix un salt sense guany. Per a MercadoFresco, amb clients per tot Espanya i plans d'obrir a Portugal, compensa clarament.

L'única precaució: per al comportament /api/* cal permetre tots els mètodes i reenviar a l'origen les capçaleres que l'aplicació necessita (Authorization, Host, Content-Type) mitjançant la política de sol·licitud d'origen AllViewerExceptHostHeader, sense ficar-les a la clau de memòria cau.

CloudFront Functions i Lambda@Edge

De vegades cal executar lògica a la vora: reescriure un URL, afegir capçaleres de seguretat, redirigir per país. CloudFront ofereix dos mecanismes molt diferents.

CloudFront Functions Lambda@Edge
On s'executa A l'edge location (les ~700) A les regional edge caches (~13)
Llenguatge JavaScript (ECMAScript 5.1 estricte) Node.js o Python
Temps màxim < 1 ms 5 s (viewer) / 30 s (origin)
Memòria 2 MB 128-10.240 MB
Accés a la xarxa No
Accés al cos de la petició No
Pot cridar altres serveis d'AWS No
Esdeveniments Sol·licitud/resposta de visor Sol·licitud/resposta de visor i d'origen
Cost 0,10 USD per milió 0,60 USD per milió + temps de còmput
Cas típic Reescriptura d'URL, capçaleres, redireccions simples Autenticació, crides a bases de dades, transformació d'imatges

La regla: si cap a CloudFront Functions, va a CloudFront Functions. És sis vegades més barat, s'executa a més llocs i és ordres de magnitud més ràpid.

Exemple real de MercadoFresco: afegir capçaleres de seguretat a totes les respostes i normalitzar els URL del catàleg.

// funcio-capcaleres-seguretat.js
// Esdeveniment: viewer-response (s'executa just abans de retornar la resposta al client)
function handler(event) {
    var resposta = event.response;
    var capcaleres = resposta.headers;

    // Forca HTTPS durant un any a tots els subdominis
    capcaleres['strict-transport-security'] = {
        value: 'max-age=31536000; includeSubDomains; preload'
    };
    // Impedeix que el navegador endevini el tipus de contingut
    capcaleres['x-content-type-options'] = { value: 'nosniff' };
    // Impedeix que la botiga es carregui dins d'un iframe alie (clickjacking)
    capcaleres['x-frame-options'] = { value: 'DENY' };
    // No envia l'URL completa com a referent a llocs externs
    capcaleres['referrer-policy'] = { value: 'strict-origin-when-cross-origin' };
    // Desactiva API del navegador que la botiga no fa servir
    capcaleres['permissions-policy'] = {
        value: 'geolocation=(), microphone=(), camera=()'
    };

    return resposta;
}

I la reescriptura d'URL, a l'esdeveniment de sol·licitud de visor:

// funcio-normalitzar-url.js
// Esdeveniment: viewer-request (abans de mirar la memoria cau)
function handler(event) {
    var peticio = event.request;
    var uri = peticio.uri;

    // /categoria/verduras  ->  /categoria/verduras/index.html
    if (uri.endsWith('/')) {
        peticio.uri = uri + 'index.html';
    } else if (!uri.includes('.')) {
        peticio.uri = uri + '/index.html';
    }

    // Elimina els parametres de campanya de la clau de memoria cau.
    // Sense aixo, cada enllac de cada campanya de marqueting seria una entrada diferent
    // de la MATEIXA pagina, i la taxa d'encerts s'enfonsaria.
    var qs = peticio.querystring;
    ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'fbclid', 'gclid']
        .forEach(function (p) { delete qs[p]; });

    return peticio;
}

Aquest segon exemple té efecte econòmic directe: és una funció de quatre línies útils que recupera la taxa d'encerts que les campanyes de la Sara estaven destruint sense que ningú ho sabés.

Detall important sobre el moment d'execució: a viewer-request la funció s'executa abans de consultar la memòria cau, així que la modificació de l'URI afecta la clau de memòria cau. Si s'executés a origin-request, només es llançaria a les fallades de memòria cau i no canviaria res.

# Publicar i associar la funcio
aws cloudfront create-function --profile mercadofresco-dev \
  --name mercadofresco-normalizar-url \
  --function-config '{"Comment":"Normalitza URL i neteja parametres de campanya","Runtime":"cloudfront-js-2.0"}' \
  --function-code fileb://funcio-normalitzar-url.js

aws cloudfront publish-function --profile mercadofresco-dev \
  --name mercadofresco-normalizar-url --if-match "$ETAG"

Registres, mètriques i taxa d'encerts

Registres estàndard. CloudFront aboca a S3 una línia per petició, amb el resultat de memòria cau inclòs:

# Es configuren dins de la distribucio
"Logging": {
  "Enabled": true,
  "IncludeCookies": false,
  "Bucket": "mercadofresco-registros-web.s3.amazonaws.com",
  "Prefix": "cloudfront/"
}

Mètriques a CloudWatch (sempre a us-east-1, per ser un servei global):

Mètrica Què mesura Objectiu a MercadoFresco
Requests Peticions totals
CacheHitRate % servit des de la memòria cau > 90 % en fotos
OriginLatency Temps de resposta de l'origen < 300 ms
4xxErrorRate Errors de client < 1 %
5xxErrorRate Errors de servidor < 0,1 %
TotalErrorRate Suma de tots dos < 1 %
BytesDownloaded Bytes servits Base del càlcul de cost

CacheHitRate és la mètrica que cal vigilar: si baixa, l'estalvi desapareix i l'origen es carrega. Les causes més freqüents d'una taxa baixa són les que ja hem vist: massa elements a la clau de memòria cau, TTL massa curt o Cache-Control mal posat a l'origen.

aws cloudwatch get-metric-statistics --profile mercadofresco-dev --region us-east-1 \
  --namespace AWS/CloudFront --metric-name CacheHitRate \
  --dimensions Name=DistributionId,Value=E2QWERTY123ABC Name=Region,Value=Global \
  --start-time "$(date -u -d '7 days ago' +%Y-%m-%dT%H:%M:%SZ)" \
  --end-time "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
  --period 86400 --statistics Average \
  --query 'sort_by(Datapoints,&Timestamp)[].{Dia:Timestamp,Encerts:Average}' --output table

Els taulers i les alarmes sobre aquestes mètriques es construeixen a la lliçó 05-01.

Classes de preu i el càlcul d'estalvi de MercadoFresco

Les classes de preu limiten des de quines edge locations se serveix, a canvi d'un preu menor:

Classe Regions incloses Cost relatiu Per a MercadoFresco
PriceClass_All Totes, incloses Sud-amèrica, Austràlia, Índia Més car Innecessari avui
PriceClass_200 Totes menys Sud-amèrica, Austràlia i Nova Zelanda Intermedi Innecessari avui
PriceClass_100 Nord-amèrica, Europa i Israel Més barat L'elecció correcta

Els clients de MercadoFresco són a Espanya i, properament, a Portugal: tots dos a Europa. Amb PriceClass_100 es paga menys i l'experiència dels clients reals és idèntica. Qui sigui fora continuarà sent atès, només que des d'una edge més llunyana.

El càlcul, amb els números de 02-03

Dades de partida del catàleg de MercadoFresco:

  • 40 GB de fotos i miniatures a S3.
  • 1.200.000 visualitzacions de foto al mes.
  • Pes mitjà per foto servida: 250 KB → 300 GB de transferència mensual.

Situació actual, servint directament des d'S3:

Concepte Càlcul Cost
Emmagatzematge 40 GB × 0,023 USD/GB 0,92 USD
Peticions GET 1.200.000 × 0,0004 USD/1.000 0,48 USD
Transferència de sortida 300 GB × 0,09 USD/GB 27,00 USD
Total 28,40 USD

I aquí hi ha el 97 % de 02-03: 27,00 ÷ 28,40 = 95 %, que amb el trànsit dels mesos de campanya supera el 97 %.

Amb CloudFront al davant, suposant un 90 % d'encerts de memòria cau:

Concepte Càlcul Cost
Emmagatzematge a S3 40 GB × 0,023 USD/GB 0,92 USD
Transferència S3 → CloudFront Gratuïta sempre 0,00 USD
Peticions GET a S3 (només el 10 % de fallades) 120.000 × 0,0004/1.000 0,05 USD
Transferència de sortida de CloudFront 300 GB, dins de l'1 TB gratuït permanent 0,00 USD
Peticions HTTPS de CloudFront 1.200.000, dins dels 10 M gratuïts 0,00 USD
Total 0,97 USD

Estalvi: 27,43 USD al mes, un 96,6 %. I a més les fotos se serveixen en uns 25 ms en comptes de 350 ms.

La capa gratuïta permanent de CloudFront (1 TB de sortida i 10 milions de peticions al mes, sense caducitat, no confondre amb la capa gratuïta de 12 mesos de 01-01) és el que fa que el resultat sigui tan rotund. Convé veure també què passa quan MercadoFresco creixi deu vegades:

Escenari Només S3 Amb CloudFront Estalvi
Avui: 300 GB, 1,2 M peticions 28,40 USD 0,97 USD 96,6 %
×10: 3 TB, 12 M peticions 277 USD 176 USD 36,5 %
×50: 15 TB, 60 M peticions 1.383 USD ~880 USD 36 %

L'estalvi percentual baixa en créixer, perquè la capa gratuïta deixa de ser significativa, però l'estalvi absolut puja. I a aquesta xifra cal sumar-hi el que es deixa de pagar en LCU de l'ALB pel trànsit que ja no el travessa, més la conversió que es guanya per servir cinc vegades més ràpid.

Creació per CLI, invalidació i neteja

La configuració d'una distribució és un JSON llarg. L'escrivim en un fitxer:

{
  "CallerReference": "mercadofresco-catalogo-2026-08-02",
  "Comment": "CDN del cataleg i la botiga de MercadoFresco",
  "Enabled": true,
  "PriceClass": "PriceClass_100",
  "HttpVersion": "http2and3",
  "IsIPV6Enabled": true,
  "DefaultRootObject": "index.html",
  "Origins": {
    "Quantity": 2,
    "Items": [
      {
        "Id": "origen-fotos-s3",
        "DomainName": "mercadofresco-catalogo-fotos.s3.eu-west-1.amazonaws.com",
        "OriginAccessControlId": "E1OACMERCADOFRESCO",
        "S3OriginConfig": { "OriginAccessIdentity": "" }
      },
      {
        "Id": "origen-tienda-alb",
        "DomainName": "alb-mercadofresco-tienda-1234567890.eu-west-1.elb.amazonaws.com",
        "CustomOriginConfig": {
          "HTTPPort": 80,
          "HTTPSPort": 443,
          "OriginProtocolPolicy": "https-only",
          "OriginSslProtocols": { "Quantity": 1, "Items": ["TLSv1.2"] },
          "OriginReadTimeout": 30,
          "OriginKeepaliveTimeout": 5
        }
      }
    ]
  },
  "DefaultCacheBehavior": {
    "TargetOriginId": "origen-tienda-alb",
    "ViewerProtocolPolicy": "redirect-to-https",
    "AllowedMethods": {
      "Quantity": 3,
      "Items": ["GET", "HEAD", "OPTIONS"],
      "CachedMethods": { "Quantity": 2, "Items": ["GET", "HEAD"] }
    },
    "Compress": true,
    "CachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6",
    "OriginRequestPolicyId": "b689b0a8-53d0-40ab-baf2-68738e2966ac"
  },
  "CacheBehaviors": {
    "Quantity": 2,
    "Items": [
      {
        "PathPattern": "/productos/*",
        "TargetOriginId": "origen-fotos-s3",
        "ViewerProtocolPolicy": "redirect-to-https",
        "AllowedMethods": {
          "Quantity": 2,
          "Items": ["GET", "HEAD"],
          "CachedMethods": { "Quantity": 2, "Items": ["GET", "HEAD"] }
        },
        "Compress": false,
        "CachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6"
      },
      {
        "PathPattern": "/api/*",
        "TargetOriginId": "origen-tienda-alb",
        "ViewerProtocolPolicy": "https-only",
        "AllowedMethods": {
          "Quantity": 7,
          "Items": ["GET", "HEAD", "OPTIONS", "PUT", "POST", "PATCH", "DELETE"],
          "CachedMethods": { "Quantity": 2, "Items": ["GET", "HEAD"] }
        },
        "Compress": true,
        "CachePolicyId": "4135ea2d-6df8-44a3-9df3-4b5a84be39ad"
      }
    ]
  },
  "Logging": {
    "Enabled": true,
    "IncludeCookies": false,
    "Bucket": "mercadofresco-registros-web.s3.amazonaws.com",
    "Prefix": "cloudfront/"
  }
}

Els identificadors llargs són polítiques gestionades per AWS, iguals a tots els comptes: 658327ea-... és CachingOptimized, 4135ea2d-... és CachingDisabled i b689b0a8-... és la política de sol·licitud d'origen AllViewer.

# Crear la distribucio
DIST_ID=$(aws cloudfront create-distribution --profile mercadofresco-dev \
  --distribution-config file://distribucion-mercadofresco.json \
  --query 'Distribution.Id' --output text)

# Etiquetar-la (CloudFront fa servir una ordre a part, amb ARN)
aws cloudfront tag-resource --profile mercadofresco-dev \
  --resource "arn:aws:cloudfront::111122223333:distribution/$DIST_ID" \
  --tags 'Items=[{Key=Proyecto,Value=mercadofresco},{Key=Entorno,Value=produccion},
                 {Key=Componente,Value=catalogo},{Key=Propietario,Value=marta},
                 {Key=CentroCoste,Value=marketing}]'

# El desplegament a les edge locations triga uns minuts
aws cloudfront wait distribution-deployed --profile mercadofresco-dev --id "$DIST_ID"

aws cloudfront get-distribution --profile mercadofresco-dev --id "$DIST_ID" \
  --query 'Distribution.DomainName' --output text

Nota sobre el perfil: CloudFront és global, així que les seves ordres no porten --region; la CLI fa servir us-east-1 internament.

Invalidació i seguiment:

INV_ID=$(aws cloudfront create-invalidation --profile mercadofresco-dev \
  --distribution-id "$DIST_ID" --paths "/productos/tomate-rama.jpg" \
  --query 'Invalidation.Id' --output text)

aws cloudfront get-invalidation --profile mercadofresco-dev \
  --distribution-id "$DIST_ID" --id "$INV_ID" --query 'Invalidation.Status'

⚠️ Cost i neteja

CloudFront no cobra per tenir una distribució: només per transferència i peticions, i els primers 1 TB i 10 M al mes són gratuïts de manera permanent. És, amb diferència, el servei més barat d'aquest mòdul, i una distribució de pràctiques amb trànsit de laboratori costa zero.

L'única cosa que pot sorprendre són les invalidacions: 1.000 rutes gratis al mes i 0,005 USD per ruta després. Invalidar /* compta com una sola ruta, així que ni això és car; el dolent és invalidar 5.000 fitxers un a un a cada desplegament.

Per esborrar-la cal desactivar-la primer i esperar que es desplegui el canvi:

ETAG=$(aws cloudfront get-distribution-config --profile mercadofresco-dev \\
  --id "$DIST_ID" --query 'ETag' --output text)
# Editar el JSON posant "Enabled": false i tornar a aplicar-lo
aws cloudfront update-distribution --profile mercadofresco-dev --id "$DIST_ID" \\
  --distribution-config file://distribucion-desactivada.json --if-match "$ETAG"
aws cloudfront wait distribution-deployed --profile mercadofresco-dev --id "$DIST_ID"
aws cloudfront delete-distribution --profile mercadofresco-dev --id "$DIST_ID" --if-match "$ETAG_NUEVO"

I si esborres la distribució, recorda't de restaurar l'accés al bucket, o les fotos deixaran de servir-se del tot.

Una menció final: davant de CloudFront s'hi poden col·locar AWS Shield, que protegeix davant d'atacs de denegació de servei (lliçó 04-04), i AWS WAF, que filtra peticions malicioses per regles i per taxa (lliçó 04-05). Tots dos s'apliquen a la vora, abans que el trànsit arribi a la VPC, i aquest és precisament el motiu pel qual convé que tot el trànsit de MercadoFresco, estàtic i dinàmic, passi per CloudFront.

Errors Habituals i Consells

Ficar massa coses a la clau de memòria cau. És l'error car. User-Agent o totes les galetes enfonsen la taxa d'encerts a gairebé zero i pagues una CDN que no desa res. Si l'origen necessita una dada però el contingut no canvia amb ella, va a la política de sol·licitud d'origen, no a la de memòria cau.

Demanar el certificat de CloudFront a eu-west-1. Ha d'estar a us-east-1. Ni tan sols apareixerà a la llista i perdràs mitja hora buscant-ne el motiu.

Invalidar a cada desplegament en comptes de versionar els noms. És més lent, costa diners, no neteja la memòria cau dels navegadors i no permet tornar enrere. Versiona el nom del fitxer.

Oblidar AWS:SourceArn a la política de l'OAC. Sense aquesta condició, qualsevol distribució de CloudFront del món pot llegir el teu bucket. És una fallada de seguretat real i silenciosa.

Desar /api/* a la memòria cau. Servir a un client la resposta desada de la comanda d'un altre és una fuita de dades. Fes servir CachingDisabled i permet tots els mètodes HTTP.

Posar TTL llargs sense Cache-Control a l'origen. El TTL de CloudFront no arriba al navegador. Si vols que el client també ho desi, la capçalera ha d'estar a l'objecte d'S3.

No revisar CacheHitRate. Una distribució amb un 20 % d'encerts està mal configurada i ningú se n'assabenta fins que arriba la factura. Mira-ho cada setmana.

Deixar els paràmetres de campanya a la clau de memòria cau. Cada utm_source diferent crea una entrada nova del mateix HTML. Neteja'ls amb una CloudFront Function a viewer-request.

Fer servir Lambda@Edge per a alguna cosa que resol una CloudFront Function. Sis vegades més car, menys punts d'execució i molta més latència, per a res.

Consell d'or: després de cada canvi de configuració, comprova la capçalera X-Cache amb curl -I dues vegades seguides. La primera ha de dir Miss; la segona, Hit. Si la segona continua dient Miss, hi ha alguna cosa a la clau de memòria cau que no hi hauria de ser.

Exercicis

Exercici 1: dissenyar els comportaments de memòria cau d'una botiga completa

MercadoFresco afegeix tres tipus de contingut nous: /static/* (CSS i JavaScript amb nom versionat), /pedidos/* (pàgines HTML personalitzades per usuari autenticat) i /buscar (cerca amb paràmetre q, els resultats de la qual són iguals per a tots els usuaris). Dissenya el comportament de memòria cau de cadascun: patró, origen, mètodes, política de memòria cau, TTL i justificació.

Exercici 2: diagnosticar una taxa d'encerts del 12 %

MercadoFresco porta un mes amb CloudFront i CacheHitRate està al 12 %. La factura d'S3 no ha baixat. Enumera com a mínim cinc causes possibles, l'ordre o la comprovació que confirma cadascuna, i la correcció.

Exercici 3: calcular el punt d'equilibri

La Sara vol saber a partir de quin volum de trànsit CloudFront deixa de sortir «de franc» i quant estalviaria si MercadoFresco obrís a Portugal i França i el trànsit es dupliqués. Calcula el cost mensual de servir 2 TB amb 4 milions de peticions, amb i sense CloudFront, i explica què canvia quan se supera la capa gratuïta.

Solucions

Solució 1

Patró Origen Mètodes Política de memòria cau TTL Justificació
/static/* origen-fotos-s3 o l'ALB GET, HEAD CachingOptimized + Compress: true Min 0 / Def 1 any / Max 1 any El nom porta versió (app.a3f9c1.js), així que el contingut és immutable. La compressió és clau: CSS i JS es redueixen un 70-80 % amb Brotli
/pedidos/* origen-tienda-alb Tots CachingDisabled 0 / 0 / 0 Contingut personalitzat per usuari autenticat. Desar-lo a la memòria cau mostraria la comanda d'un client a un altre. A més cal reenviar Authorization i les galetes de sessió amb la política de sol·licitud d'origen AllViewer, sense ficar-les a la clau de memòria cau (que aquí no existeix)
/buscar origen-tienda-alb GET, HEAD Política pròpia: clau = ruta + paràmetre q únicament Min 0 / Def 300 / Max 3600 El resultat que és igual per a tothom, així que es pot desar a la memòria cau: la cerca de «tomàquet» la fan centenars de clients. Només q a la clau; ni galetes ni utm_*. Cinc minuts són suficients per absorbir el pic sense mostrar preus obsolets

El cas més instructiu és /buscar: és contingut dinàmic que es pot desar a la memòria cau perquè no depèn de l'usuari. La distinció correcta no és «estàtic davant de dinàmic», sinó «igual per a tothom davant de personalitzat». Una cerca popular servida des de la memòria cau estalvia una consulta a RDS per cada encert, cosa que descarrega la base de dades a més de la xarxa.

Precedència: /static/*, /pedidos/* i /buscar abans que el comportament per defecte *. L'ordre entre ells és indiferent perquè els patrons no se solapen.

Solució 2

Causa 1: elements innecessaris a la clau de memòria cau. La més probable amb diferència.

aws cloudfront get-cache-policy --profile mercadofresco-dev --id "$POLICY_ID" \
  --query 'CachePolicy.CachePolicyConfig.ParametersInCacheKeyAndForwardedToOrigin'

Cal buscar HeaderBehavior: whitelist amb capçaleres molt variables, CookieBehavior: all o QueryStringBehavior: all. Correcció: passar tot el que l'origen necessiti però que no canviï el contingut a la política de sol·licitud d'origen.

Causa 2: paràmetres de campanya. La Sara ha llançat una campanya i cada correu porta un utm_content diferent. Es veu als registres d'accés, amb milers d'URL gairebé idèntics. Correcció: la CloudFront Function de neteja de paràmetres.

Causa 3: l'origen envia Cache-Control: no-cache o max-age=0.

curl -I https://mercadofresco-catalogo-fotos.s3.eu-west-1.amazonaws.com/productos/tomate-rama-v3.jpg

Si no apareix Cache-Control, l'objecte es va pujar sense la capçalera. Correcció: tornar a pujar amb --cache-control, o aws s3 cp sobre si mateix amb --metadata-directive REPLACE.

Causa 4: TTL massa curt. Un DefaultTTL de 60 s a les fotos fa que la memòria cau caduqui constantment. Es veu a get-cache-policy. Correcció: 1 any per a contingut versionat.

Causa 5: trànsit molt repartit geogràficament amb contingut poc popular. Cada edge location té la seva pròpia memòria cau; si un objecte es demana un cop al mes des de cada ciutat, sempre serà una fallada. Es confirma creuant els registres d'accés per x-edge-location. Correcció: PriceClass_100 concentra el trànsit en menys edges i millora la taxa d'encerts a més d'abaratir.

Causa 6, menys evident: el comportament per defecte * està capturant les fotos perquè el patró /productos/* està mal escrit (per exemple, productos/* sense la barra inicial). Es comprova amb X-Cache i amb l'x-edge-result-type dels registres.

Solució 3

Sense CloudFront, 2 TB (2.048 GB) i 4 M de peticions des d'S3:

Concepte Càlcul Cost
Transferència de sortida 2.048 GB × 0,09 USD/GB 184,32 USD
Peticions GET 4.000.000 × 0,0004/1.000 1,60 USD
Emmagatzematge 40 GB × 0,023 0,92 USD
Total 186,84 USD

Amb CloudFront (PriceClass_100, 90 % d'encerts):

Concepte Càlcul Cost
Transferència de CloudFront El primer 1 TB de franc; els altres 1.024 GB × 0,085 87,04 USD
Peticions HTTPS 4 M, dins dels 10 M gratuïts 0,00 USD
Transferència S3 → CloudFront Gratuïta 0,00 USD
Peticions GET a S3 (10 % de fallades) 400.000 × 0,0004/1.000 0,16 USD
Emmagatzematge 40 GB × 0,023 0,92 USD
Total 88,12 USD

Estalvi: 98,72 USD al mes, un 53 %.

Què canvia en superar la capa gratuïta. Per sota d'1 TB, CloudFront és essencialment de franc i l'estalvi frega el 100 %. Per sobre, l'estalvi passa a dependre de dos factors estructurals que es mantenen sempre:

  1. La transferència de l'origen a CloudFront és gratuïta, així que S3 deixa de facturar sortida del tot, sigui quin sigui el volum.
  2. El preu per GB de CloudFront és menor que el d'S3 (0,085 davant de 0,09 USD/GB a Europa) i a més baixa per trams amb el volum: a partir de 10 TB, 50 TB i 150 TB el preu cau esglaonadament, mentre que el d'S3 és pràcticament pla.

El punt d'equilibri, per tant, no existeix: CloudFront és més barat que S3 directe en qualsevol volum, i l'única raó per no posar-lo seria que el contingut fos impossible de desar a la memòria cau i estigués consumit per un únic client a la mateixa regió. Aquest no és el cas d'una botiga.

Conclusió

MercadoFresco ha atacat el problema del cost per l'arrel. Saps què és una CDN, com funcionen els tres nivells de CloudFront —edge locations, regional edge caches i origen— i què passa exactament en un encert i en una fallada de memòria cau, inclosa la dada que ho canvia tot: la transferència de l'origen a CloudFront és gratuïta. Saps llegir la capçalera X-Cache per saber en quina situació estàs.

Has configurat una distribució amb dos orígens —el bucket mercadofresco-catalogo-fotos i l'alb-mercadofresco-tienda de la lliçó anterior—, coneixes els grups d'origen per commutar per error, i has repartit el trànsit en comportaments de memòria cau per patró de ruta, amb la regla que guanya el primer que coincideix i el * va sempre l'últim. Sobretot, domines el concepte que decideix si una CDN serveix d'alguna cosa: la clau de memòria cau. Saps que cada valor diferent de cada element crea una entrada nova, que ficar-hi User-Agent o totes les galetes enfonsa la taxa d'encerts al 5 %, i que la distinció correcta és entre la política de memòria cau (el que forma la clau) i la política de sol·licitud d'origen (el que l'origen necessita rebre sense fragmentar la memòria cau). Saps com interactuen MinTTL, DefaultTTL i MaxTTL amb el Cache-Control de l'origen, i per què la capçalera s'ha de posar a l'objecte d'S3.

Has tancat el bucket amb Origin Access Control, amb una política que autoritza el servei cloudfront.amazonaws.com únicament des de la distribució concreta gràcies a la condició AWS:SourceArn —sense la qual qualsevol distribució del món podria llegir-lo—, i saps que OAC substitueix l'antic OAI. Has comprovat amb dos curl que l'accés directe retorna 403 i el de CloudFront 200. Saps per què el versionat de noms de fitxer és millor que les invalidacions: és immediat, gratuït, reversible i neteja també la memòria cau del navegador. Coneixes el parany del certificat a us-east-1 i saps que calen dos certificats, un per regió. Has vist quan compensa passar també el contingut dinàmic per CloudFront, i has distingit CloudFront Functions de Lambda@Edge, escrivint dues funcions reals: les capçaleres de seguretat i la neteja de paràmetres de campanya que recupera la taxa d'encerts que les campanyes de la Sara estaven destruint.

I els comptes: amb PriceClass_100, la capa gratuïta permanent d'1 TB i un 90 % d'encerts, el cost mensual del catàleg passa de 28,40 USD a 0,97 USD, un 96,6 % menys, i les fotos se serveixen en 25 ms en lloc de 350 ms. El problema del 97 % de transferència de sortida detectat a 02-03 està resolt, i l'ALB de 03-03 només processa ja el que de debò no es pot desar a la memòria cau.

Falta una sola cosa, i és la que fa que res d'això sigui visible per a un client real: el domini. Ara mateix la botiga respon a d111111abcdef8.cloudfront.net i el balancejador a alb-mercadofresco-tienda-1234567890.eu-west-1.elb.amazonaws.com. Ningú no teclejarà això. A més, els dos certificats d'ACM que has demanat continuen en PENDING_VALIDATION esperant uns registres DNS que encara no existeixen. A la lliçó 03-05, «Route 53», muntarem el DNS de MercadoFresco: validarem els certificats, aprendrem què són els registres d'àlies i per què són l'única manera d'apuntar el vèrtex mercadofresco.example a CloudFront, repassarem les polítiques d'encaminament —ponderada per al canari del 10 %, geolocalització per obrir a Portugal, commutació per error cap a una pàgina de manteniment— i tancarem el mòdul amb l'arquitectura de xarxa completa.

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