Por Lucas Yoris · Performate
Pruebas de carga geo-distribuidas: DNS, latencia y journeys de usuario realistas
Corre generadores cerca de usuarios—o emula latencia—y evita atajos de DNS que falsifican rendimiento.
Tu runner de k6 está en us-east-1, tus usuarios abren la app en São Paulo y Madrid, y el dashboard muestra p95 en verde—hasta que Black Friday expone saltos de base de datos entre regiones y una clave de caché CDN que solo se calienta en Virginia. Las pruebas de carga distribuidas por geografía sirven para demostrar que latencia y enrutamiento coinciden con la realidad del cliente, no con el atajo de red de tu CI.
En esta guía verás por qué un solo generador regional miente, cómo etiquetar runs k6 por región, cuándo desplegar agentes distribuidos frente a emular RTT y qué decisiones de DNS van en el escenario—no en suposiciones.
Por qué la geografía cambia el rendimiento—no solo gráficos de ping
Agregar todos los usuarios virtuales por un generador regional oculta problemas que solo aparecen en la ruta que usan los clientes:
- GeoDNS dirige nombres a edges distintos; resolver equivocado en la prueba implica POP equivocado.
- TLS y HTTP/3 negocian distinto por distancia; el CPU del cliente no es la historia—el RTT amplifica colas en APIs charlativas.
- Ratio de acierto en CDN varía por región; caché caliente en Virginia no ayuda a Chile en el primer byte.
- Réplicas de base de datos pueden estar en una región y escrituras en otra—journeys de lectura parecen rápidos solo cerca del primary.
- Enrutamiento por compliance fuerza tráfico UE por clusters UE; un generador solo en EE. UU. nunca ejercita ese camino.
El rendimiento es un mapa, no un número. Un punto es resultado de laboratorio; el contorno es lo que tu SLO debe defender.
Combina tags regionales con métricas y tags de observabilidad en k6 para que los resúmenes fusionados sigan separando http_req_duration por region:eu-west vs region:sa-east.
Implementación práctica en k6: tags regionales y escenarios en paralelo
Puedes ejecutar k6 distribuido (k6 Cloud o runners self-hosted según ejecución distribuida) o un script con tags region explícitos por escenario cuando cada proceso corre en un locale distinto. Emular RTT con tc en Linux es respaldo—aproxima retardo, no pérdida, jitter ni MTU del camino.
Script de ejemplo (ilustrativo—no listo para producción). Hosts y umbrales ficticios. Adapta URLs, auth y tasas a tu topología.
Qué demuestra este ejemplo:
- Escenarios regionales en paralelo:
journey_euyjourney_sacon el reparto de RPS de analytics—no 100 % desde un POP. - Tags de región: Cada request lleva
region:euoregion:sapara comparar percentiles en un export. - DNS realista: Variables
BASE_EUyBASE_SAapuntan a hostnames con geo-steering que resuelven tus clientes—no un CNAME global de staging. - Forma del journey: Flujo multipaso (catálogo + carrito) expone APIs charlativas que el RTT amplifica.
- Umbrales por región: Gates
p(99)separados cuando el SLO difiere por mercado.
import http from 'k6/http';
import { check, sleep } from 'k6';
const BASE_EU = __ENV.API_EU || 'https://api-eu.staging.ejemplo.com';
const BASE_SA = __ENV.API_SA || 'https://api-sa.staging.ejemplo.com';
const TOKEN = __ENV.API_TOKEN || 'reemplazar';
export const options = {
scenarios: {
journey_eu: {
executor: 'constant-arrival-rate',
rate: Number(__ENV.EU_RPS || 20),
timeUnit: '1s',
duration: '8m',
preAllocatedVUs: 50,
maxVUs: 150,
exec: 'journeyEu',
},
journey_sa: {
executor: 'constant-arrival-rate',
rate: Number(__ENV.SA_RPS || 12),
timeUnit: '1s',
duration: '8m',
preAllocatedVUs: 40,
maxVUs: 120,
exec: 'journeySa',
},
},
thresholds: {
'http_req_duration{region:eu}': ['p(95)<600', 'p(99)<1200'],
'http_req_duration{region:sa}': ['p(95)<900', 'p(99)<1800'],
http_req_failed: ['rate<0.02'],
},
};
function catalog(base, regionTag) {
const res = http.get(`${base}/v1/catalog?page=1`, {
headers: { Authorization: `Bearer ${TOKEN}` },
tags: { name: 'catalog', region: regionTag },
});
check(res, { 'catalog 200': (r) => r.status === 200 });
return res;
}
function addToCart(base, regionTag) {
const res = http.post(
`${base}/v1/cart/items`,
JSON.stringify({ sku: 'SKU-100', qty: 1 }),
{
headers: {
Authorization: `Bearer ${TOKEN}`,
'Content-Type': 'application/json',
},
tags: { name: 'add_to_cart', region: regionTag },
}
);
check(res, { 'cart 201': (r) => r.status === 201 });
}
export function journeyEu() {
catalog(BASE_EU, 'eu');
addToCart(BASE_EU, 'eu');
sleep(0.5);
}
export function journeySa() {
catalog(BASE_SA, 'sa');
addToCart(BASE_SA, 'sa');
sleep(0.8);
}
Si aún no puedes desplegar runners en el extranjero, documenta esa brecha en el informe—y combina con pruebas de carga de headers de caché CDN para que el edge no quede invisible.
Marco de decisión: runners distribuidos vs emulación de latencia
| Situación | Acción recomendada |
|---|---|
| Producto global, SLO por mercado | Runners en regiones objetivo; escenarios paralelos con RPS de analytics |
| Presupuesto pre-prod, un stack staging | Emular RTT con cautela + tags region:*; marcar resultados como aproximados |
| Cambio de CDN o geoDNS este sprint | Resolver y hostname por región en env; comparar antes/después con mismos tags |
| Backends móviles con shards regionales | Escenarios separados por URL de shard; no fusionar en un solo BASE |
| Solo smoke en CI | Una región, baja RPS; matriz geo completa nightly o semanal |
Usa runners distribuidos cuando los release gates dependen de p99 por mercado—no del ping del laboratorio.
Usa emulación de RTT cuando necesitas señal direccional antes del presupuesto de infra—nunca como certificación.
Usa hostnames por región cuando geoDNS es parte del contrato del producto—atajos internos staging.global falsifican el journey.
Observabilidad y checklist pre-release
Las pruebas geo fallan en silencio cuando tags y DNS derivan. Antes de escalar tráfico:
- Documentar reparto de RPS por región y fuente en analytics (gateway, mesh o CDN).
- Registrar qué resolver y hostname usó cada runner—notas de env en el run.
- Alertar cuando
p(99){region:sa}supere epsilon vs baseline mientrasregion:euse mantiene. - Correlacionar tags
regionde k6 con dimensionesgeooavailability_zoneen APM. - Archivar JSON de escenarios, env regional y git SHA por release (smoke en CI/CD; matriz completa programada).
Cómo Performate coordina paquetes multiregión
Duplicar repos enteros por locale no escala. Flujo concreto para el journey UE + Sudamérica de este artículo:
- Importa una colección con requests de catálogo y carrito en carpetas
EUySA(URLs base o host headers distintos). Problema resuelto: una fuente de verdad para los pasos. - Crea dos escenarios—
journey_eua 20 req/s,journey_saa 12 req/s—según mezcla de la semana pasada. Problema resuelto: pesos honestos sin editar bloques executor a mano. - Aplica tags:
region:euyregion:saen cada escenario másroute:checkout_pathcompartido. Problema resuelto: informes alineados con el modelo de tags de k6. - Ejecuta ambos y abre comparación—filtra por región y comprueba si p99 en SA cumple el SLO más laxo. Problema resuelto: un export para producto y SRE.
- Cuando marketing mueve tráfico, cambia RPS en el editor y re-ejecuta. Problema resuelto: cambios geo son parámetros, no forks.
- Exporta k6 para jobs multiregión programados en runners que provea tu infra.
Coincide con el cta: coordinar paquetes multiregión con tagging consistente.
Cierre
Las pruebas de carga geo-distribuidas son un problema de enrutamiento y residencia disfrazado de gráfico de latencia. Corre generadores donde están los usuarios—or sé explícito al emular—y etiqueta cada familia de requests por región para que la divergencia de colas frene releases que se ven bien desde un POP.
Ejecuta esta semana la mezcla regional de analytics antes del próximo cambio de CDN o geoDNS—y anota qué región sigue poseyendo el p99 que nombra tu SLO.
¿Listo para optimizar el rendimiento de tu API?
Usa Performate para coordinar paquetes de escenarios multiregión con tagging consistente.