Benchmarking
El comando de benchmark mide operaciones de la API de RouterOS contra un router real. Está pensado para desarrollo y planificación de capacidad, no para despliegues normales.
Comando
Sección titulada «Comando»Compila y ejecuta el benchmark:
go run ./cmd/benchmarkLa ruta de configuración es opcional y por defecto es config/test.yaml:
go run ./cmd/benchmark config/test.yamlEl benchmark lee la sección de MikroTik del archivo YAML seleccionado, se conecta a RouterOS y después ejecuta operaciones a nivel de API.
Qué mide
Sección titulada «Qué mide»- Adiciones/eliminaciones individuales de direcciones IPv4 e IPv6 en address-list.
- Llamadas de búsqueda y listado de address-list.
- Llamadas de creación, búsqueda y eliminación de reglas de firewall.
- Tiempos de adición/listado/búsqueda/eliminación secuenciales de lotes IPv4.
El benchmark usa direcciones de prueba de prefijos de documentación como 198.51.100.0/24 y 2001:db8::/32, pero aun así escribe en las address lists y los menús de firewall de RouterOS configurados.
Ejemplo de salida
Sección titulada «Ejemplo de salida»Connected to: lab-router
=== SINGLE OPERATION BENCHMARKS (RouterOS API) === Add single IPv4 35ms OK Find IPv4 (1 entry) 12ms OK Remove IPv4 by .id 18ms OK
=== BATCH ADD BENCHMARKS (sequential via API) === Add 100 IPv4 (sequential) 4s (40ms/ip, failures=0)Usa los números para comparar versiones de RouterOS, modelos de hardware, API con TLS frente a texto plano y latencia de red.
Para el rendimiento real de arranque del bouncer, prefiere las pruebas funcionales de CAPI, porque la reconciliación usa adiciones masivas basadas en scripts y eliminaciones basadas en pool, no solo llamadas secuenciales a la API.
Resultados en el mundo real
Sección titulada «Resultados en el mundo real»Estas cifras provienen de la suite de pruebas funcionales de CAPI (tests/functional/) ejecutada contra un MikroTik RB5009, no de la herramienta de operaciones individuales cmd/benchmark anterior. Consulta Arquitectura: Pool de conexiones y Adición masiva basada en scripts para conocer los mecanismos detrás de estos números.
| Escenario | Resultado |
|---|---|
| Adición optimista cache-first (la dirección aún no está en el router) | ~1–3 ms por operación |
| Adición check-first (listar entradas antes de añadir, evitado por la caché) | ~400 ms por IP |
| Adición masiva basada en scripts frente a llamadas secuenciales a la API | ~97× más rápida para lotes grandes |
| Bulk-add completo en RB5009, ~22.000 entradas de origen CAPI | ~29 s de bulk, ~34 s desde el arranque |
La diferencia entre cache-first (~1-3 ms) y check-first (~400 ms) es la razón por la que existe la caché de direcciones en memoria descrita en Arquitectura: permite al bouncer saltarse el viaje de ida y vuelta listar-y-añadir de RouterOS para las direcciones que ya conoce.
Para despliegues a escala de CAPI (decenas de miles de entradas), consulta también Blocklists de CAPI y Ajuste de rendimiento para orientación sobre el dimensionado de pool_size.
El ciclo de vida completo, muestreado cada 100 ms
Sección titulada «El ciclo de vida completo, muestreado cada 100 ms»La gráfica siguiente es una única captura continua de 70 segundos del RB5009 de
producción, tomada con un muestreador a 10 Hz que lee /proc/stat en el propio
router (ver la nota sobre el método al final de esta página). Cubre los tres
estados con los que un operador se encuentra de verdad: el router ocioso con el
bouncer parado y la lista de direcciones vacía, la primera reconciliación
importando ~22.000 entradas, y el estado tranquilo posterior con la lista
completa cargada. La CPU se lee en el eje izquierdo, la RAM en el derecho, y
los marcadores discontinuos salen de los propios timestamps del log del
bouncer. Cada punto es la media de cinco muestras de 100 ms; los picos
sub-segundo alcanzan el 57% en rebanadas sueltas de 100 ms durante el import.
El import es la meseta: aproximadamente un 31% sostenido durante ~26 segundos, repartido entre los cuatro cores con el pool de conexiones rotando picos de un solo core del 50–100%. La RAM es la parte tranquila de la historia, con una sorpresa en el cuándo: el escalón de ~19 MiB cae al conectar, antes de importar una sola entrada — y 22.000 entradas después no se ha movido más. Mantener la lista le cuesta al router casi nada; la memoria no es donde muerde esta carga, la CPU durante las lecturas de la lista, sí. El tramo ocioso también enseña los propios blips de fondo del router — un dispositivo real nunca es una línea plana.
Nota sobre el método
Sección titulada «Nota sobre el método»La serie de 100 ms procede de un contenedor muestreador que corre en el propio
router, leyendo /proc/stat y /proc/meminfo del kernel compartido a 10 Hz y
empujando lotes directamente a Loki — el cpu-load propio de RouterOS se
actualiza solo una vez por segundo, así que los scripts no pueden ver por
debajo de eso. El protocolo de captura: parar el bouncer, borrar ambas listas
de direcciones, dejar asentar el router, y arrancar el bouncer grabando a
través de la primera reconciliación hasta el régimen estable.
Toda la instrumentación se despliega con un comando contra cualquier RouterOS con el paquete de contenedores habilitado:
go run ./cmd/perfmon install -router admin@192.168.88.1 -port 22 \ -loki http://tu-loki:3100Compila el muestreador en cruzado, empaqueta la imagen del contenedor sin
necesitar Docker, crea el veth, el NAT y las pertenencias a listas del firewall
de forma idempotente, arranca el contenedor y verifica que las muestras llegan
a Loki. uninstall elimina exactamente lo que creó; capture extrae cualquier
ventana como CSV; plot redibuja la gráfica de arriba desde el dataset
versionado. Cualquier verbo con -h muestra la lista completa de flags.
Medir contra un router en producción
Sección titulada «Medir contra un router en producción»Dos costumbres separan un número accionable de uno que engaña, y ambas se aprendieron por las malas afinando este bouncer.
Intercala las variantes. Un router no es una máquina en silencio: enruta tráfico, ejecuta su propio trabajo de fondo y deriva a lo largo de los minutos. Medir la variante A un rato y luego la B otro rato atribuye esa deriva al cambio. Altérnalas — A, B, A, B — dentro de la misma conexión y el mismo minuto, y compara muestras emparejadas. La primera comparación in situ de la reducción de proplist se hizo en dos ventanas separadas y dio −2%; la versión intercalada dio −11,2%, con las 48 parejas favoreciendo el mismo lado. El mismo código y el mismo router; solo cambió el calendario.
Desconfía de una curva que no es monótona. Barrer el tamaño de bloque una vez por valor, en secuencia, produjo esto:
bloque 50 6,926sbloque 100 4,679sbloque 250 9,760s <- el doble que sus vecinos por ambos ladosbloque 500 5,395sbloque 1000 6,194sNingún modelo de coste produce esa forma.
Reporta una dispersión, no un solo número. El arreglo evidente — intercalar los tamaños entre rondas y quedarse con el mejor tiempo de cada uno — sigue siendo incorrecto, solo que de forma menos evidente. El mínimo es un estimador defendible cuando el ruido es unilateral, pero tira justo la información que decide si la comparación significa algo. Repetido guardando todas las muestras, el mismo barrido dice:
| bloque | mediana | media | IQR |
|---|---|---|---|
| 50 | 5,78 s | 6,86 s | 1,76 s |
| 100 | 5,06 s | 5,31 s | 0,22 s |
| 250 | 5,31 s | 6,39 s | 2,47 s |
| 500 | 5,50 s | 5,77 s | 0,84 s |
| 1000 | 4,36 s | 5,75 s | 2,55 s |
La dispersión dentro de un mismo tamaño llega a 2,55 s, mientras que la distancia entre el mejor y el peor tamaño es de 1,43 s. El ruido de una variante es mayor que la diferencia entre variantes, así que el barrido no resuelve nada — y, en efecto, qué tamaño “gana” depende del estimador: mediana y mínimo eligen 1.000, la media elige 100. Reportar solo el mejor de tres rondas habría escondido todo eso tras una tabla de aspecto impecable.
La conclusión sobrevivió, porque nunca dependió del ranking: insertar una fila domina, así que ningún tamaño de bloque en este rango mueve el import de forma medible. Pero la primera redacción enunciaba un modelo de coste de dos términos con dos cifras significativas que los datos no sostienen.
Un reflejo útil: antes de creerte un resultado, pregunta qué más cambió entre las dos mediciones. Casi siempre es el tiempo.
Lista de comprobación de seguridad
Sección titulada «Lista de comprobación de seguridad»- Confirma que el destino es un router de laboratorio.
- Usa address lists de prueba dedicadas cuando sea posible.
- Mantén
command_timeoutlo bastante alto para dispositivos lentos. - Revisa el router tras una interrupción y elimina cualquier comentario
benchmark-*si una ejecución se detiene a medias.