A les dues lliçons anteriors hem vist què és un sistema distribuït i quins models ens permeten descriure'l. Ara toca respondre la pregunta que qualsevol arquitecte de Quilòmetre Zero es faria després de la caiguda de la Setmana de la Verema: val la pena distribuir? La resposta honesta és "depèn", i aquesta lliçó dona les eines perquè aquest "depèn" sigui un càlcul i no una intuïció.

Quantificarem els avantatges (quanta capacitat guanyem en afegir màquines, quants minuts de caiguda a l'any suposa cada "nou" de disponibilitat, quant accelera realment el paral·lelisme) i posarem nom als desafiaments (complexitat, heterogeneïtat, consistència, fallades parcials, latència, seguretat, observabilitat i cost). Acabarem amb una taula de situacions en què no convé distribuir, perquè saber quan no fer-ho és tan important com saber com fer-ho.

Contingut

  1. Avantatges de distribuir
  2. Escalabilitat: vertical davant d'horitzontal
  3. Tolerància a fallades i disponibilitat: els "nous"
  4. Flexibilitat, localitat i compartició de recursos
  5. La llei d'Amdahl: el límit de l'escalat
  6. Desafiaments de distribuir
  7. Quan NO distribuir
  8. Exemple de codi: disponibilitat combinada a Quilòmetre Zero
  9. Errors comuns i consells
  10. Exercicis
  11. Conclusió

  1. Avantatges de distribuir

Els avantatges d'un sistema distribuït són l'altra cara dels motius pels quals existeixen (lliçó 01-01). Els agrupem en cinc, i els tres primers els quantificarem:

Avantatge Què aporta Com es mesura
Escalabilitat Atendre més càrrega afegint màquines Peticions per segon, usuaris concurrents
Tolerància a fallades i disponibilitat Continuar funcionant encara que fallin components Percentatge de temps disponible ("nous")
Rendiment per localitat Servir cada usuari des de prop Latència (mil·lisegons)
Flexibilitat i modularitat Fer evolucionar cada part per separat Freqüència de desplegament, mida dels equips
Compartició de recursos Aprofitar maquinari, dades i serveis comuns Cost per unitat de treball

  1. Escalabilitat: vertical davant d'horitzontal

Escalar és augmentar la capacitat d'un sistema per atendre més càrrega. Hi ha dos camins:

  • Escalat vertical (scale up): substituir la màquina per una de més potent (més CPU, més memòria, discos més ràpids).
  • Escalat horitzontal (scale out): afegir més màquines i repartir la càrrega entre elles.
Criteri Vertical Horitzontal
Canvis al programari Cap (o gairebé) Cal que l'aplicació es pugui repartir (sense estat local, balanceig)
Límit El de la màquina més gran que existeixi (o que puguis pagar) En teoria, cap; a la pràctica, la llei d'Amdahl (apartat 5)
Cost Creix més que linealment: una màquina el doble de potent costa força més del doble Aproximadament lineal: dues màquines costen el doble que una
Disponibilitat No millora: continua havent-hi un únic punt de fallada Millora: la caiguda d'una màquina no tomba el sistema
Elasticitat Canviar de màquina implica aturada i planificació Es poden afegir i treure màquines segons la demanda (al núvol, en minuts)
Temps d'aplicació Dies o setmanes (comprar, migrar) Minuts (si el sistema ja està preparat)

Càlcul de capacitat per a la Setmana de la Verema

Recordem les dades de l'incident (lliçó 01-01): el servidor únic va començar a degradar-se a unes 380 peticions/s i va caure per sobre de les 700 peticions/s. Màrqueting preveu que la propera campanya, la "Setmana del Formatge Artesà", amb la Formatgeria Montblanc com a protagonista, arribi a un pic de 1.200 peticions/s.

Fem els comptes per a les dues opcions:

Opció vertical. Necessitem una màquina que aguanti 1.200 pet/s amb un marge de seguretat del 30 %: 1.560 pet/s, és a dir, unes 4 vegades la capacitat actual (380 pet/s "còmodes"). Un servidor quatre vegades més potent que l'actual (32 vCPU, 128 GB) no costa 4 vegades més, sinó típicament 5-6 vegades més, i continuarà sent un únic punt de fallada. A més, no està clar que l'aplicació aprofiti linealment els nuclis addicionals (apartat 5).

Opció horitzontal. Mesurem que una instància de l'aplicació Python, en una màquina modesta (4 vCPU, 16 GB), atén còmodament 200 pet/s. Aleshores:

capacitat necessària   = 1.200 pet/s × 1,3 (marge)   = 1.560 pet/s
instàncies necessàries = ceil(1.560 / 200)           = 8 instàncies
instàncies amb redundància (N+1)                     = 9 instàncies

Nou màquines petites durant la setmana de campanya i, la resta de l'any, dues o tres. Aquesta elasticitat és impossible amb l'escalat vertical.

Però atenció: el càlcul assumeix que la capa d'aplicació és el coll d'ampolla. A l'incident real, PostgreSQL va esgotar les seves connexions a 610 pet/s. Si posem 9 instàncies d'aplicació davant de la mateixa base de dades, simplement l'ofegarem abans. L'escalat horitzontal de l'aplicació obliga a escalar també les dades (memòria cau, rèpliques de lectura, particionament), que és matèria del Mòdul 4. La lliçó: l'escalat horitzontal no és una propietat "del sistema", sinó de cada component, i el sistema escala tant com el seu component menys escalable.

  1. Tolerància a fallades i disponibilitat: els "nous"

La disponibilitat d'un sistema és la fracció del temps en què funciona correctament. S'expressa com a percentatge i, col·loquialment, pel seu nombre de nous. És fonamental traduir cada nivell a temps de caiguda per entendre què significa realment:

Disponibilitat Nous Caiguda màxima a l'any Caiguda màxima al mes Caiguda màxima a la setmana
99 % dos 3 dies 15 h 36 min (87,6 h) 7 h 18 min 1 h 41 min
99,9 % tres 8 h 46 min 43 min 50 s 10 min 5 s
99,99 % quatre 52 min 34 s 4 min 23 s 1 min
99,999 % cinc 5 min 15 s 26 s 6 s

El càlcul és directe: un any té 365 × 24 × 60 = 525.600 minuts; el 0,1 % d'aquesta xifra són 525,6 minuts (8 h 46 min); el 0,01 %, 52,56 minuts.

Dues observacions importants:

  1. Cada nou addicional multiplica el cost. Passar del 99,9 % al 99,99 % no és "una mica millor": vol dir que en tot l'any només et pots permetre 52 minuts de caiguda, incloent-hi desplegaments, actualitzacions del sistema operatiu, fallades de maquinari i errors humans. Exigeix redundància a tots els nivells, desplegaments sense aturada i guàrdies 24×7.
  2. La disponibilitat es combina. Si una petició de l'Anna per comprar un formatge travessa quatre components en sèrie (web, comandes, inventari, pagaments), i cadascun té un 99,9 %, la disponibilitat de la compra no és del 99,9 %, sinó aproximadament del 99,6 %: les indisponibilitats se sumen. Per contra, si un component té dues rèpliques independents al 99,9 % i n'hi ha prou que una funcioni, la disponibilitat combinada puja al 99,9999 %. L'exemple de codi de l'apartat 8 fa aquests càlculs.

Amb el monòlit, Quilòmetre Zero tenia una disponibilitat real del 99,3 % l'últim any (unes 61 hores de caiguda, entre la Setmana de la Verema, actualitzacions i una fallada de disc). L'objectiu després de la reestructuració és assolir el 99,9 % a la compra i el 99,95 % a la consulta del catàleg.

  1. Flexibilitat, localitat i compartició de recursos

Flexibilitat i modularitat

Quan cada servei és una unitat de desplegament independent, els equips poden treballar sense trepitjar-se. A Quilòmetre Zero, l'equip de repartiment necessita desplegar diverses vegades al dia per ajustar l'algorisme de rutes, mentre que el de pagaments, subjecte a auditories, prefereix desplegaments quinzenals molt controlats. Al monòlit, tots dos ritmes són incompatibles: cada desplegament és de tot. Distribuir permet que cada servei tingui el seu ritme, la seva tecnologia (Python per a gairebé tot, potser un altre llenguatge per al processament de posicions en temps real) i el seu equip responsable.

Rendiment per localitat

La velocitat de la llum en fibra òptica és d'uns 200.000 km/s. Un viatge d'anada i tornada entre Barcelona i un centre de dades a Frankfurt (uns 1.100 km) triga, com a mínim, 11 ms; amb els salts d'encaminament reals, 25-35 ms. Entre Barcelona i Virgínia (EUA), uns 90-110 ms. Si carregar una pàgina del catàleg requereix 10 peticions seqüencials, la diferència entre servir des de prop i des de lluny és de més d'un segon. Per això els sistemes grans repliquen dades i serveis en diverses regions, i fan servir CDN per al contingut estàtic (les fotos dels productes, en el cas de Quilòmetre Zero). Servir cada ciutat des d'un node proper és un avantatge que un sistema centralitzat no pot oferir.

Compartició de recursos

Un sistema distribuït permet que molts usuaris i serveis comparteixin recursos costosos: una base de dades, un clúster de processament analític, un magatzem de fotos. El servei analitica de Quilòmetre Zero necessitarà, unes hores al dia, una capacitat de càlcul enorme per processar les vendes; la resta del dia, aquesta capacitat es pot dedicar a altres coses. Compartir és més eficient que dedicar.

  1. La llei d'Amdahl: el límit de l'escalat

És temptador pensar que amb el doble de màquines s'obté el doble de rendiment. Gairebé mai no és així, i la raó la va formular Gene Amdahl el 1967: tota tasca té una part que no es pot paral·lelitzar, i aquesta part limita l'acceleració màxima.

Si una fracció p del treball és paral·lelitzable (i per tant 1 − p és seqüencial), l'acceleració S en fer servir n màquines és:

S(n) = 1 / ((1 − p) + p / n)

I quan n tendeix a infinit:

S(∞) = 1 / (1 − p)

Apliquem-ho a Quilòmetre Zero. Suposem que, en processar una comanda, el 90 % del treball (validar, calcular preus, generar la confirmació, renderitzar) és paral·lelitzable entre instàncies, però el 10 % (l'escriptura a l'única base de dades PostgreSQL, que serialitza les transaccions sobre l'estoc) és inherentment seqüencial. Aleshores:

Màquines (n) Acceleració S(n) amb p = 0,9 Acceleració "ingènua" (n) Eficiència S(n)/n
1 1,00 1 100 %
2 1,82 2 91 %
4 3,08 4 77 %
8 4,71 8 59 %
16 6,40 16 40 %
64 8,77 64 14 %
∞ 10,00 ∞ 0 %

Amb 8 màquines aconseguim menys de 5 vegades la capacitat, i mai no superarem les 10 vegades per moltes màquines que afegim, mentre aquest 10 % continuï sent seqüencial. Això connecta amb l'apartat 2: les 9 instàncies d'aplicació no donaran 9 × 200 = 1.800 pet/s si la base de dades és el component seqüencial. L'única manera de trencar el sostre és reduir la fracció seqüencial: posar en memòria cau les lectures del catàleg (04-05), particionar les dades (04-01), o convertir en asíncrones les operacions que no necessiten ser immediates (02-04). Bona part de l'arquitectura distribuïda consisteix, en el fons, a atacar l'(1 − p) d'Amdahl.

  1. Desafiaments de distribuir

Cada avantatge té la seva factura. Aquests són els vuit desafiaments que apareixeran, un per un, a la resta del curs:

Desafiament En què consisteix Com es manifesta a Quilòmetre Zero On es tracta
Complexitat Més peces, més interaccions, més maneres de fallar. El raonament passa d'"una traça de pila" a "un graf de crides entre processos" Una comanda que abans era una funció ara travessa 5 serveis i 2 cues Tot el curs; especialment 08-01
Heterogeneïtat Llenguatges, sistemes operatius, versions, formats de dades i xarxes diferents repartiment rep posicions de mòbils Android i iOS per 4G i wifi; analitica fa servir eines d'un altre ecosistema 02-03 (serialització), 07-05 (orquestració)
Consistència de dades Amb diverses còpies, quina és la veritat? Què passa si dos nodes escriuen alhora? L'Anna i en Marc compren l'última unitat de formatge des de dues ciutats Mòdul 3 sencer
Fallades parcials Algunes parts fallen mentre d'altres continuen; no sempre se sap què ha passat pagaments cobra a la Llúcia però la confirmació a comandes es perd 01-04, 02-05, 07-03, 07-04
Latència Cada crida per xarxa costa mil·lisegons; encadenar moltes crides suma segons Carregar el cistell fa 12 crides a serveis diferents: 12 × 20 ms = 240 ms 01-04, 04-05
Seguretat Cada comunicació per xarxa pot ser interceptada o suplantada; més superfície d'atac Com sap inventari que qui li demana descomptar estoc és realment comandes? Mòdul 6 sencer
Depuració i observabilitat El registre de logs està repartit; reproduir una fallada exigeix correlacionar esdeveniments de moltes màquines amb rellotges diferents "La comanda d'en Marc s'ha quedat en 'pendent' i ningú no sap en quin servei s'ha encallat" Mòdul 7 (07-01, 07-02)
Cost operatiu Més màquines, més desplegaments, més monitoratge, més persones de guàrdia L'equip passa d'administrar un servidor a administrar un clúster amb desenes de contenidors 07-05, 08-03

Val la pena aturar-se en el de consistència, perquè és el més contraintuïtiu. Al monòlit, la transacció de PostgreSQL garanteix que si l'Anna compra l'última unitat, en Marc veurà estoc zero. Amb comandes i inventari separats, i potser amb inventari replicat en diverses ciutats, aquesta garantia desapareix per defecte i cal reconstruir-la amb tècniques específiques (consens, transaccions distribuïdes, sagues) que tenen el seu cost en latència i complexitat. El Mòdul 3 es dedica íntegrament a aquest problema; aquí n'hi ha prou amb saber que existeix i que no té solució gratuïta.

  1. Quan NO distribuir

Un bon arquitecte sap dir "no". Aquestes són situacions en què distribuir és, gairebé amb seguretat, un error:

Situació Per què no distribuir Alternativa
La càrrega cap folgadament en una màquina i no es preveu que creixi S'assumeix tota la complexitat sense obtenir l'avantatge principal Monòlit ben estructurat; escalat vertical si cal
L'equip és petit (menys de ~8 persones) Els microserveis existeixen en bona part perquè equips diferents no es trepitgin; un equip petit no té aquest problema i sí que en paga la complexitat Monòlit modular amb límits clars entre mòduls
Les dades exigeixen transaccions fortes entre gairebé totes les entitats Les transaccions distribuïdes són lentes i complexes; si tot està relacionat amb tot, no hi ha límits naturals per partir Una única base de dades relacional, possiblement amb rèpliques de lectura
No es disposa de capacitat d'operació (monitoratge, desplegament automàtic, guàrdies) Un sistema distribuït sense observabilitat és una caixa negra que fallarà sense que ningú sàpiga per què Invertir primer en operació (Mòdul 7) i distribuir després
El requisit de disponibilitat és modest (amb un 99 % n'hi ha prou) Un monòlit amb còpies de seguretat i un procediment de restauració ja ho aconsegueix Alta disponibilitat simple: màquina de reserva i restauració
No s'ha identificat el coll d'ampolla Distribuir "a cegues" sol moure el problema en lloc de resoldre'l (com les 9 instàncies contra una única base de dades) Mesurar primer, distribuir el component que realment limita

Quilòmetre Zero, després de la Setmana de la Verema, compleix els criteris per distribuir: la càrrega ja no cap en una màquina, hi ha diversos equips, els dominis (catàleg, comandes, repartiment...) tenen límits naturals i la disponibilitat del 99,3 % és inacceptable per al negoci. Però convé observar que no tots els components s'han de distribuir de la mateixa manera ni al mateix temps: la lliçó 01-06 proposa un camí gradual.

  1. Exemple de codi: disponibilitat combinada a Quilòmetre Zero

Escriurem un petit simulador que calcula la disponibilitat d'un flux de negoci a partir de la disponibilitat dels components que travessa. Les dues regles són:

  • Components en sèrie (l'operació necessita que tots funcionin): la disponibilitat combinada és el producte de les disponibilitats. Si A té 0,999 i B té 0,999, A i B junts tenen 0,999 × 0,999 = 0,998.
  • Components en paral·lel (n'hi ha prou que un funcioni, per exemple, rèpliques): la indisponibilitat combinada és el producte de les indisponibilitats. Si A i A' tenen 0,999 cadascun, la probabilitat que fallin tots dos alhora és 0,001 × 0,001 = 0,000001, així que la disponibilitat és 1 − 0,000001 = 0,999999.

La segona regla assumeix que les fallades són independents, cosa que a la realitat no sempre és certa (si les dues rèpliques comparteixen alimentació o xarxa, fallen alhora). Ho comentarem després del codi.

from dataclasses import dataclass

MINUTS_ANY = 365 * 24 * 60   # 525.600 minuts


@dataclass
class Component:
    """Un servei o recurs amb una disponibilitat coneguda (0..1)."""
    nom: str
    disponibilitat: float

    def caiguda_anual_min(self) -> float:
        return (1 - self.disponibilitat) * MINUTS_ANY


def en_serie(nom: str, *components: Component) -> Component:
    """Tots han de funcionar: es multipliquen les disponibilitats."""
    total = 1.0
    for c in components:
        total *= c.disponibilitat
    return Component(nom, total)


def en_parallel(nom: str, *repliques: Component) -> Component:
    """N'hi ha prou que una funcioni: es multipliquen les INdisponibilitats."""
    prob_totes_caigudes = 1.0
    for r in repliques:
        prob_totes_caigudes *= (1 - r.disponibilitat)
    return Component(nom, 1 - prob_totes_caigudes)


def replicar(component: Component, n: int) -> Component:
    """Drecera: n rèpliques independents i idèntiques d'un component."""
    repliques = [Component(f"{component.nom}-{i+1}", component.disponibilitat)
                 for i in range(n)]
    return en_parallel(f"{component.nom} x{n}", *repliques)


def informe(c: Component) -> None:
    minuts = c.caiguda_anual_min()
    hores, resta = divmod(minuts, 60)
    print(f"{c.nom:<42} {c.disponibilitat*100:8.4f} %   "
          f"caiguda/any: {int(hores):3d} h {resta:4.1f} min")


if __name__ == "__main__":
    # Components que travessa la compra d'un producte a Quilòmetre Zero
    web = Component("web", 0.9995)
    comandes = Component("comandes", 0.999)
    inventari = Component("inventari", 0.999)
    pagaments = Component("pagaments", 0.995)     # depèn d'una passarel·la externa
    postgres = Component("postgresql", 0.9995)

    print("=== Escenari 1: una instància de cada component, en sèrie ===")
    compra_v1 = en_serie("compra (tot en sèrie)", web, comandes, inventari, pagaments, postgres)
    for c in (web, comandes, inventari, pagaments, postgres):
        informe(c)
    print("-" * 80)
    informe(compra_v1)

    print("\n=== Escenari 2: repliquem els serveis (2 rèpliques cadascun) ===")
    compra_v2 = en_serie(
        "compra (serveis x2)",
        replicar(web, 2), replicar(comandes, 2), replicar(inventari, 2),
        replicar(pagaments, 2), postgres,
    )
    informe(compra_v2)

    print("\n=== Escenari 3: a més, PostgreSQL amb rèplica de reserva ===")
    compra_v3 = en_serie(
        "compra (tot x2)",
        replicar(web, 2), replicar(comandes, 2), replicar(inventari, 2),
        replicar(pagaments, 2), replicar(postgres, 2),
    )
    informe(compra_v3)

    print("\n=== Quantes rèpliques de 'pagaments' calen per al 99,99 %? ===")
    for n in range(1, 5):
        informe(replicar(pagaments, n))

La sortida és la següent:

=== Escenari 1: una instància de cada component, en sèrie ===
web                                         99.9500 %   caiguda/any:   4 h 22.8 min
comandes                                    99.9000 %   caiguda/any:   8 h 45.6 min
inventari                                   99.9000 %   caiguda/any:   8 h 45.6 min
pagaments                                   99.5000 %   caiguda/any:  43 h 48.0 min
postgresql                                  99.9500 %   caiguda/any:   4 h 22.8 min
--------------------------------------------------------------------------------
compra (tot en sèrie)                       99.2018 %   caiguda/any:  69 h 55.2 min

=== Escenari 2: repliquem els serveis (2 rèpliques cadascun) ===
compra (serveis x2)                         99.9473 %   caiguda/any:   4 h 37.1 min

=== Escenari 3: a més, PostgreSQL amb rèplica de reserva ===
compra (tot x2)                             99.9973 %   caiguda/any:   0 h 14.5 min

=== Quantes rèpliques de 'pagaments' calen per al 99,99 %? ===
pagaments x1                                99.5000 %   caiguda/any:  43 h 48.0 min
pagaments x2                                99.9975 %   caiguda/any:   0 h 13.1 min
pagaments x3                               100.0000 %   caiguda/any:   0 h  0.1 min
pagaments x4                               100.0000 %   caiguda/any:   0 h  0.0 min

Analitzem el programa i els seus resultats:

  1. Component desa un nom i una disponibilitat entre 0 i 1; caiguda_anual_min la tradueix a minuts de caiguda a l'any, que és la magnitud que entén el negoci.
  2. en_serie multiplica disponibilitats. Observa l'escenari 1: cap component individual no baixa del 99,5 %, però la compra completa queda al 99,2 %, gairebé 70 hores a l'any. Com més components travessi una operació, pitjor. Aquest és el cost ocult de "descompondre en serveis": cada frontera de xarxa que s'afegeix a un flux síncron resta disponibilitat.
  3. en_parallel i replicar apliquen la regla de la redundància. L'escenari 2 en mostra l'efecte: replicar els quatre serveis porta la compra del 99,2 % al 99,95 %, i ara el component que domina és el que no s'ha replicat, PostgreSQL (4 h 23 min de les 4 h 37 min totals).
  4. L'escenari 3 replica també la base de dades i arriba al 99,997 %. Però compte: replicar una base de dades no és tan simple com replicar un servei sense estat. Cal mantenir les còpies coherents, i això és tot el Mòdul 3. El nombre és una cota superior optimista.
  5. L'últim bloc respon a una pregunta molt pràctica: pagaments, que depèn d'una passarel·la externa amb només el 99,5 %, passa al 99,9975 % amb dues rèpliques. Això, però, només és cert si les dues rèpliques fallen de manera independent. Si totes dues depenen de la mateixa passarel·la externa i és aquesta la que cau, les dues cauen alhora i la rèplica no serveix de res. El model d'aquest script no captura fallades correlacionades; a la realitat, sempre cal preguntar-se què comparteixen les rèpliques (xarxa, alimentació, proveïdor, versió de programari amb el mateix error).

Errors Comuns i Consells

  • Sumar disponibilitats en lloc de multiplicar-les. "Cada servei té un 99,9 %, així que el sistema té un 99,9 %" és fals. Amb cinc components en sèrie al 99,9 %, el sistema té un 99,5 %. Cada salt de xarxa en un flux síncron és un factor multiplicador més petit que u.
  • Creure que les rèpliques fallen de manera independent. Dues rèpliques al mateix rack, amb la mateixa versió de programari i la mateixa dependència externa, tenen fallades molt correlacionades. La redundància real exigeix diversitat (zones diferents, desplegaments esglaonats).
  • Escalar el component equivocat. Afegir instàncies d'aplicació quan el coll d'ampolla és la base de dades no serveix de res (Amdahl). Cal mesurar abans d'escalar.
  • Confondre "més ràpid" amb "més escalable". Un sistema distribuït sol ser més lent per a una única petició (latència de xarxa) i més capaç per a moltes peticions (rendiment total). Si el que importa és la latència d'una operació aïllada, la distribució la pot empitjorar.
  • Perseguir nous sense que el negoci els necessiti. Cada nou costa aproximadament un ordre de magnitud més. Pregunta sempre quant costa cada hora de caiguda per al negoci i compara-ho amb el que costa evitar-la.
  • Consell: documenta la disponibilitat objectiu de cada operació de negoci (no de cada servei) i calcula, amb la regla de la sèrie, quina disponibilitat exigeix això a cada component. Així es descobreixen ràpidament els components que necessiten redundància.

Exercicis

Exercici 1: Planificar la capacitat

L'equip de Quilòmetre Zero mesura que una instància del servei cataleg atén 350 consultes/s amb un 60 % de CPU, i que a partir del 80 % de CPU la latència es dispara. Per a la Setmana del Formatge Artesà es preveuen 2.100 consultes/s al catàleg.

  1. Quantes consultes/s pot atendre una instància sense superar el 80 % de CPU (suposant una relació lineal entre consultes i CPU)?
  2. Quantes instàncies calen per al pic, amb redundància N+1?
  3. Si la meitat de les consultes es poguessin resoldre des d'una memòria cau en memòria sense arribar al servei, quantes instàncies caldrien?

Exercici 2: Pressupost de caiguda

El negoci decideix que l'operació "consultar l'estat de la meva comanda" ha de tenir un 99,95 % de disponibilitat. L'operació travessa, en sèrie: la passarel·la (99,99 %), el servei comandes (X) i la seva base de dades (99,98 %).

  1. Quants minuts de caiguda a l'any permet l'objectiu del 99,95 %?
  2. Quina disponibilitat mínima X necessita comandes perquè l'operació compleixi l'objectiu?
  3. Si una instància de comandes només aconsegueix el 99,9 %, n'hi ha prou amb dues rèpliques independents?

Exercici 3: Amdahl al processament de vendes

El servei analitica processa les vendes del dia en un treball que triga 60 minuts en una màquina. Una anàlisi mostra que 6 minuts corresponen a llegir i consolidar el resultat final en un únic fitxer (seqüencial) i els 54 restants a càlculs per ciutat (paral·lelitzables).

  1. Calcula l'acceleració amb 6 màquines i amb 18 màquines.
  2. Quin és el temps mínim possible per moltes màquines que s'afegeixin?
  3. Modifica l'script de l'apartat 8 (o escriu-ne un de nou) amb una funció amdahl(p, n) i fes-la servir per imprimir una taula d'acceleracions per a n = 1, 2, 4, 8, 16, 32.

Solucions

Solució 1:

  1. Si 350 consultes/s consumeixen el 60 % de CPU, el 80 % correspon a 350 × (80 / 60) ≈ 467 consultes/s per instància.
  2. 2.100 / 467 = 4,5 → calen 5 instàncies per al pic, 6 amb redundància N+1.
  3. Si la memòria cau n'absorbeix la meitat, arriben 1.050 consultes/s al servei: 1.050 / 467 = 2,25 → 3 instàncies (4 amb N+1). Fixa't que una memòria cau (lliçó 04-05) redueix les màquines a la meitat: reduir la feina sol ser més rendible que afegir màquines.

Solució 2:

  1. 0,05 % de 525.600 minuts = 262,8 minuts (unes 4 h 23 min) a l'any.
  2. La disponibilitat en sèrie és 0,9999 × X × 0,9998 ≥ 0,9995. Aïllant: X ≥ 0,9995 / (0,9999 × 0,9998) = 0,9995 / 0,99970002 ≈ 0,99980 (99,98 %). És a dir, comandes necessita gairebé la mateixa disponibilitat que l'objectiu global, perquè els altres dos components ja "gasten" part del pressupost.
  3. Dues rèpliques independents al 99,9 %: 1 − (0,001)² = 0,999999 (99,9999 %), molt per sobre del 99,98 % necessari. Sí que n'hi ha prou, sempre que la fallada d'una no arrossegui l'altra i que el balancejador que les reparteix no es converteixi en el nou punt únic de fallada (caldria incloure'l a la cadena en sèrie).

Solució 3:

  1. La fracció paral·lelitzable és p = 54 / 60 = 0,9. Amb n = 6: S = 1 / (0,1 + 0,9 / 6) = 1 / 0,25 = 4,0 (el treball triga 15 minuts). Amb n = 18: S = 1 / (0,1 + 0,9 / 18) = 1 / 0,15 = 6,67 (9 minuts). Triplicar les màquines només millora el temps de 15 a 9 minuts.
  2. El temps mínim és la part seqüencial: 6 minuts (acceleració màxima 1 / 0,1 = 10). Per baixar d'aquí cal atacar la consolidació final, per exemple, escrivint resultats parcials per ciutat en paral·lel (el patró que fa MapReduce, lliçó 05-02).
def amdahl(p: float, n: int) -> float:
    """Acceleració d'Amdahl amb fracció paral·lelitzable p i n màquines."""
    return 1 / ((1 - p) + p / n)


if __name__ == "__main__":
    p = 54 / 60
    temps_base_min = 60
    print(f"{'n':>4} {'acceleració':>12} {'temps (min)':>13} {'eficiència':>11}")
    for n in (1, 2, 4, 8, 16, 32):
        s = amdahl(p, n)
        print(f"{n:>4} {s:>12.2f} {temps_base_min / s:>13.1f} {s / n * 100:>10.0f} %")

Sortida:

   n  acceleració   temps (min)  eficiència
   1         1.00          60.0        100 %
   2         1.82          33.0         91 %
   4         3.08          19.5         77 %
   8         4.71          12.7         59 %
  16         6.40           9.4         40 %
  32         7.80           7.7         24 %

La columna d'eficiència (quina fracció de cada màquina s'aprofita) és la que hauria de mirar qui paga la factura: amb 32 màquines s'està aprofitant menys de la quarta part de cadascuna.

Conclusió

Distribuir un sistema aporta avantatges reals i mesurables: escalabilitat horitzontal (amb un càlcul de capacitat que, en el cas de la Setmana del Formatge Artesà, substitueix una màquina enorme per nou de modestes i elàstiques), disponibilitat (on hem après a traduir els "nous" a minuts de caiguda i a combinar components en sèrie i en paral·lel), localitat (servir cada ciutat des de prop), flexibilitat (cada equip amb el seu ritme) i compartició de recursos. Però també hem vist que l'escalat té un sostre, la llei d'Amdahl, marcat per la fracció seqüencial del treball —normalment, l'accés a les dades—, i que cada frontera de xarxa que afegim a un flux síncron multiplica la disponibilitat per un factor més petit que u.

Els desafiaments —complexitat, heterogeneïtat, consistència, fallades parcials, latència, seguretat, observabilitat i cost operatiu— són l'índex de la resta del curs. I la taula de "quan no distribuir" recorda que la resposta correcta a molts problemes continua sent un monòlit ben fet.

Molts d'aquests desafiaments neixen de suposicions falses que els programadors fem sense adonar-nos-en sobre la xarxa. La lliçó següent, Les Fal·làcies de la Computació Distribuïda, els posa nom una per una i mostra, amb codi, què passa quan les creiem certes.

Curs d'Arquitectures Distribuïdes

Mòdul 1: Introducció als Sistemes Distribuïts

Mòdul 2: Comunicació en Sistemes Distribuïts

Mòdul 3: Consistència i Replicació

Mòdul 4: Emmagatzematge Distribuït

Mòdul 5: Computació Distribuïda

Mòdul 6: Seguretat en Sistemes Distribuïts

Mòdul 7: Monitoratge i Manteniment

Mòdul 8: Casos d'Estudi i Aplicacions

© Copyright 2026. Tots els drets reservats