Simulación de Eventos Discretos · Tema 40

Redes de colas

Salidas que alimentan otras colas — del nodo aislado al sistema: tráfico, ruteo y el cuello que manda.

01 · Punto de partida

Ninguna cola vive sola

El banco es informes → caja; la guardia triage → médico → farmacia; la web front → app → DB. Cada salida es una llegada aguas abajo (más arribos externos). Dimensionar el nodo 1 sin mirar el 2 es regalar el cuello: el sistema anda a la velocidad del más cargado.

La red de colas conecta nodos con ruteo y resuelve el tráfico λi de cada uno: con eso, cada nodo se analiza (o simula) con su λ y el total se suma por visitas.

  • ¿Cómo se conectan los nodos y qué fracción va a cada uno?
  • ¿Cómo calculo λ en cada nodo (externo + interno)?
  • ¿Cuál es el cuello y qué W total sufre el cliente?
  • ¿Cuándo puedo analizar nodo por nodo y cuándo simulo la red?

02 · Definición

Nodos, ruteo y tráfico

□

Nodos

Cada uno con su A/B/c/K/D (Temas 23–30): front M/M/2, DB M/D/1, caja M/M/1…

%

Ruteo P

Pij: fracción que del nodo i va al j (y Pi0 la que sale). Suma 1 por fila.

λ

Tráfico

λi resuelve el sistema lineal: lo externo más lo que le mandan los demás.

Red de 2 nodos: γ1=0.4/min, P12=0.7, S1=S2=2.
Nodoλiρi (c=1)Wqi M/M/1
1 · puerta0.400.808.0 min (cuello)
2 · fondo (70%)0.280.562.5 min
Cliente que sigue——W ≈ (8+2) + (2.5+2) = 14.5

03 · El corazón: resolver, hallar el cuello, sumar

Tráfico primero, colas después

γ + P→λ por nodo→ρ y W por nodo

Sin λi no hay ρi ni Wqi: el tráfico manda. En tándem es multiplicar (λ2 = λ1P12); con ciclos (rework) es sistema lineal; con Jackson M/M/c abierto, cada nodo se comporta como si fuera M/M/c aislado con su λi (forma producto).

  1. 1
    Dibujar nodos y flechas.

    γ externas por nodo, Pij entre nodos y Pi0 de salida. Todo suma 1 por fila.

  2. 2
    Resolver λi.

    Tándem: en cadena. Con ciclos: sistema lineal (2×2 a mano, más con Python).

  3. 3
    Hallar el cuello.

    ρi = λi/(ciμi): el máximo decide estabilidad y SLA. Refuerzo va ahí.

  4. 4
    Sumar visitas.

    W total = Σ (visitas medias al i × Wi). El que recorre dos nodos paga dos esperas.

Tándem
Fila en serie: λ2 = λ1P12. El caso del laboratorio y de front→app→DB.
Split / merge
Una salida se parte (70/30) o varias se juntan: λj suma aportes. El merge correlaciona arribos (ojo PASTA).
Jackson (red abierta)
Con M/M/c por nodo y ruteo markoviano, P(n1,n2…) = ΠPi(ni): cada nodo como aislado. Aproximación de trabajo diaria.
Burke
La salida de un M/M/c estable es Poisson: el tándem markoviano se encadena limpio. Con G o K finita, ya no.

Tándem / Jackson

Descompone

λ por nodo, Erlang por nodo, suma por visitas. Rápido y exacto donde valen los supuestos.

Bloqueo y ciclos duros

Simula la red

Con K finita (el lleno frena aguas arriba) o prioridades entre nodos, el FEL único con eventos por nodo manda.

04 · Ejemplos

Cuatro redes de todos los días

  1. 1
    Banco: informes → caja (70%).

    λ1 = 0.4, λ2 = 0.28: el cuello suele ser informes (ρ1 = 0.8).

  2. 2
    Guardia: triage → médico → farmacia.

    Tres tándem con prioridades solo en el primero: red + clases combinadas.

  3. 3
    Web: front → app (80%) → DB (60%).

    λDB = λ·0.48: DB pequeña con todo el tráfico es el cuello clásico.

  4. 4
    Taller con rework 10%.

    P21 = 0.1 de vuelta a corte: ciclo que infla λ1 = γ/(1−0.1·…). Se resuelve, no se adivina.

05 · Representación en Python

Tráfico con álgebra, red con traza

Resolver λi es lineal; simular el tándem es pasarle las salidas del 1 como arribos del 2.

Python en tu navegador. El primero resuelve el tándem; el segundo simula los dos nodos y suma el W total. Cambiá p y buscá el cuello.

# Tráfico del tándem: γ1=0.4, P12=0.7, S1=S2=2
gamma1, p = 0.4, 0.7
lam1, lam2 = gamma1, gamma1 * p
for i, lam in [(1, lam1), (2, lam2)]:
    print(f"nodo{i}: lam={lam:.2f} rho={lam*2:.2f}")
# Tándem M/M/1 -> M/M/1: salidas del 1 alimentan al 2 (p=0.7)
import random
random.seed(40)
lam, mu, p, T = 0.4, 0.5, 0.7, 200.0
t, libre1, libre2, Wtot, n = 0.0, 0.0, 0.0, [], 0
while t < T:
    t += random.expovariate(lam)
    ini1 = max(t, libre1)
    fin1 = ini1 + random.expovariate(mu)
    libre1 = fin1
    if random.random() < p:
        ini2 = max(fin1, libre2)
        fin2 = ini2 + random.expovariate(mu)
        libre2 = fin2
        Wtot.append(fin2 - t)
    else:
        Wtot.append(fin1 - t)
    n += 1
print(f"W total={sum(Wtot)/len(Wtot):.1f} (N={n})")

06 · Exploración

Laboratorio: el tándem y su cuello

Tándem puerta (S1 = 2 fijo) → fondo con prob. p (S2 ajustable), c = 1 en ambos, T = 150, semilla fija. El esquema muestra los flujos λ1 → λ2; las barras comparan Wq1 vs Wq2. Subí p o S2 y mirá cómo el cuello se muda del nodo 1 al 2.

EXPERIMENTO 40

Dónde se muda el cuello

λ2 = λ1·p · T=150

Los resultados numéricos aparecen debajo.
λ2 al fondo0
ρ1 puerta0
ρ2 fondo0
W total0

Subí p o S2 para mudar el cuello.

Flechas con tasas; barras = Wq por nodo (naranja el cuello). W total = puerta + p·fondo para el que sigue.

Preguntas para explorar

  1. Con λ1=0.4, p=70%, S iguales: ¿ρ1 vs ρ2? ¿Dónde está el cuello?
  2. Subí S2=4: ¿ρ2? ¿W total para el que sigue?
  3. Con p=30%: ¿λ2? ¿El fondo respira aunque S2=4?
Ver respuestas sugeridas
  1. ρ1=0.8 vs ρ2=0.56: cuello en puerta (Wq1≈8 vs ≈2.5).
  2. ρ2≈1.12: avalancha en fondo aunque la puerta ande; W total se dispara (sin régimen).
  3. λ2=0.12, ρ2≈0.48: sí, poco tráfico perdona servicio lento.

07 · Comprensión

Confusiones frecuentes

«La salida siempre es Poisson»

Solo la de M/M/c estable sin bloqueo (Burke). Con servicio general, prioridades o cupo, el nodo 2 no ve Poisson.

«Sumo las L sin ponderar»

L total pondera por visitas: el que no va al fondo no suma su L2. W total = W1 + p·W2 en el tándem.

«El cuello es el más lento»

Es el de mayor ρi = λiSi/ci: tráfico × servicio. Un rápido saturado manda sobre un lento vacío.

«Analizo cada nodo aislado con su λ externa»

Con λ externa sola ignorás lo ruteado (λ2 = 0 en el ejemplo). El tráfico se resuelve primero, siempre.

08 · Práctica guiada

Ejercicios con Python

Ejercicio 1: tráfico en cadena

γ1=0.5, P12=0.8, P23=0.5. ¿λ1, λ2, λ3?

g1, p12, p23 = 0.5, 0.8, 0.5
lam1, lam2, lam3 = g1, g1*p12, g1*p12*p23
print(f"{lam1:.2f} {lam2:.2f} {lam3:.2f}")  # 0.50 0.40 0.20
Ver solución razonada

En cadena se multiplica: 0.5 → 0.4 → 0.2. Cada nodo dimensiona con su λ, no con γ1.

Ejercicio 2: W del que sigue

W1=10, W2=4.5, p=0.7. ¿W total medio (todos) y del que sigue?

W1, W2, p = 10.0, 4.5, 0.7
print(f"todos={W1+p*W2:.2f} sigue={W1+W2:.1f}")
Ver solución

Todos: 13.15; el que sigue: 14.5. Promediar sin ponderar visitas miente.

Ejercicio 3: rework que infla

γ=0.4 al nodo 1, P12=1, P21=0.1 (10% vuelve). Resolvé λ1, λ2.

Ver una posible respuesta
# lam1 = g + 0.1*lam2; lam2 = lam1 -> lam1 = g/0.9
g = 0.4
lam1 = g/0.9
print(f"lam1={lam1:.2f} lam2={lam1:.2f}")  # 0.44: el rework infla 11%

λ ≈ 0.44 en ambos: el 10% de retorno se paga en tráfico extra permanente.

09 · Síntesis

Ideas para recordar

  • Red = nodos + P + γ; λi = γi + ΣλjPji primero.
  • Cuello = max ρi; refuerzo y SLA viven ahí.
  • W total pondera visitas: W1 + p·W2 en el tándem.
  • Jackson/Burke habilitan nodo por nodo; bloqueo y G piden FEL único.
  • En Python: resolver tráfico + pasar traza de salidas como arribos.

En el próximo tema mediremos bien el arranque: el período de calentamiento.