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
- Avantatges de distribuir
- Escalabilitat: vertical davant d'horitzontal
- Tolerància a fallades i disponibilitat: els "nous"
- Flexibilitat, localitat i compartició de recursos
- La llei d'Amdahl: el límit de l'escalat
- Desafiaments de distribuir
- Quan NO distribuir
- Exemple de codi: disponibilitat combinada a Quilòmetre Zero
- Errors comuns i consells
- Exercicis
- Conclusió
- 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 |
- 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.
- 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:
- 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.
- 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.
- 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.
- 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:
I quan n tendeix a infinit:
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.
- 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.
- 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.
- 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:
Componentdesa un nom i una disponibilitat entre 0 i 1;caiguda_anual_minla tradueix a minuts de caiguda a l'any, que és la magnitud que entén el negoci.en_seriemultiplica 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.en_parallelireplicarapliquen 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).- 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.
- 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.
- Quantes consultes/s pot atendre una instància sense superar el 80 % de CPU (suposant una relació lineal entre consultes i CPU)?
- Quantes instàncies calen per al pic, amb redundància N+1?
- 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 %).
- Quants minuts de caiguda a l'any permet l'objectiu del 99,95 %?
- Quina disponibilitat mínima X necessita
comandesperquè l'operació compleixi l'objectiu? - Si una instància de
comandesnomé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).
- Calcula l'acceleració amb 6 màquines i amb 18 màquines.
- Quin és el temps mínim possible per moltes màquines que s'afegeixin?
- 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:
- Si 350 consultes/s consumeixen el 60 % de CPU, el 80 % correspon a 350 × (80 / 60) ≈ 467 consultes/s per instància.
- 2.100 / 467 = 4,5 → calen 5 instàncies per al pic, 6 amb redundància N+1.
- 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:
- 0,05 % de 525.600 minuts = 262,8 minuts (unes 4 h 23 min) a l'any.
- 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,
comandesnecessita gairebé la mateixa disponibilitat que l'objectiu global, perquè els altres dos components ja "gasten" part del pressupost. - 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:
- 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.
- 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
- Conceptes Bàsics de Sistemes Distribuïts
- Models de Sistemes Distribuïts
- Avantatges i Desafiaments dels Sistemes Distribuïts
- Les Fal·làcies de la Computació Distribuïda
- Temps, Rellotges i Ordenació d'Esdeveniments
- Del Monòlit a la Plataforma Distribuïda: el Cas Quilòmetre Zero
Mòdul 2: Comunicació en Sistemes Distribuïts
- Protocols de Comunicació
- RPC i RMI
- gRPC i Serialització de Dades
- Missatgeria i Cues de Missatges
- Patrons de Comunicació Asíncrona
Mòdul 3: Consistència i Replicació
- Models de Consistència
- El Teorema CAP i PACELC
- Algorismes de Consens
- Replicació de Dades
- Transaccions Distribuïdes i Sagues
Mòdul 4: Emmagatzematge Distribuït
- Particionament de Dades i Hashing Consistent
- Sistemes de Fitxers Distribuïts
- Emmagatzematge d'Objectes
- Bases de Dades Distribuïdes
- Memòries Cau Distribuïdes
Mòdul 5: Computació Distribuïda
- Models de Computació Distribuïda
- MapReduce i Hadoop
- Spark i Computació en Memòria
- Processament de Fluxos de Dades
- Planificació de Treballs i Pipelines de Dades
Mòdul 6: Seguretat en Sistemes Distribuïts
- Autenticació i Autorització
- Xifratge i Protecció de Dades
- Gestió d'Identitats
- Seguretat entre Serveis: mTLS i Gestió de Secrets
- Passarel·les d'API, Limitació de Taxa i Auditoria
Mòdul 7: Monitoratge i Manteniment
- Monitoratge de Sistemes Distribuïts
- Logs Centralitzats i Traçabilitat Distribuïda
- Gestió de Fallades i Recuperació
- Patrons de Resiliència: Timeouts, Reintents i Circuit Breaker
- Automatització i Orquestració
- Proves en Sistemes Distribuïts i Enginyeria del Caos
