Nodos visitados: 11. Comparaciones: sin cambios.
En unas pruebas locales de septiembre de 2026, el prototipo de descubrimiento devolvía repetidamente esos mismos recuentos. Con 32 agentes, y también con 512. La solicitud se propagaba como máximo dos saltos por el vecindario; los números parecían ajustarse a lo previsto.
Pero el tiempo cambiaba. El percentil 95 de latencia pasó de 5.66 a 47.64 milisegundos. La red creció 16 veces y la consulta se volvió más de ocho veces más lenta.
La contradicción apuntaba a algo concreto: había trabajo fuera del recuento de visitas.
Antes de salir, la solicitud ya había recorrido toda la red
Cada agente del prototipo conserva una señal de descubrimiento y se conecta con unos pocos vecinos. Cuando una solicitud pasa por un nodo, debe decidir si cerca hay objetos que merezcan explorarse. Para ello, el sistema construye un resumen del vecindario que reúne las señales públicas del nodo y de sus vecinos a un salto.
Como en un mapa urbano, la consulta solo piensa recorrer unas calles. El resumen es el cartel de orientación de un cruce: ayuda a decidir hacia dónde continuar.
La implementación inicial optó por una solución cómoda: al empezar cada consulta, reconstruir los carteles de todos los nodos y después dejar salir la solicitud.
# 早期请求路径的简化结构
adverts = build_all_neighborhood_summaries(network)
return walk_local_routes(request, adverts)
La segunda línea recorre efectivamente rutas locales. La primera ya recorrió la red entera.
Los contadores cubrían principalmente propagación y comparaciones, así que informaban fielmente de «11 nodos visitados». Medían el trabajo de propagación. La reconstrucción total ocurría antes, consumía tiempo y crecía con la red, pero no figuraba en esa cuenta.
No es un fenómeno extraño en sistemas de datos. Una base puede devolver pocas filas después de examinar muchas; una consulta con LIMIT puede pagar primero el coste inicial de ordenar o construir un índice. La documentación de EXPLAIN de PostgreSQL distingue filas de salida, coste inicial y coste total. Para leer estas cantidades hay que saber qué parte del trabajo cubre cada una.
En este prototipo, el problema ya era preciso: antes de empezar las visitas locales se repetía el trabajo que ellas pretendían ahorrar.
Construir el resumen cuando se necesita
Dividimos la construcción por lotes en construcción por nodo. Solo cuando la consulta alcanza un borde y necesita examinar su vecindario se prepara ese resumen. Si vuelve a necesitarlo durante la misma consulta síncrona, reutiliza el resultado.
# 修订后请求路径的简化结构
adverts = {}
def summary_for(edge_id):
if edge_id not in adverts:
adverts[edge_id] = build_one_neighborhood_summary(edge_id)
return adverts[edge_id]
return walk_local_routes(request, summary_for)
adverts solo vive durante una consulta. La siguiente vuelve a leer los nodos y conexiones actuales; las actualizaciones, altas y bajas producen así resúmenes nuevos de forma natural. Es una simplicidad deliberada: el prototipo se ejecuta de manera síncrona y no modifica la red concurrentemente durante un descubrimiento. La reutilización interna aporta la ganancia principal sin gestionar la invalidación de una caché entre solicitudes.
Construir todos los resúmenes sigue siendo útil para diagnóstico o para exportar una instantánea de la red. Simplemente dejó de ser un paso obligatorio de toda consulta.
Añadimos además dos medidas ligadas a acciones reales: cuántos resúmenes se construyeron y cuántos contribuidores de esos resúmenes se leyeron. Conservamos las visitas; los nuevos recuentos hacen visible también la preparación.
La curva de latencia se aplanó con la misma carga
La comparación mantuvo máquina, topología, consultas y configuración. Ejecutamos 12 solicitudes de descubrimiento por tamaño sobre un anillo bidireccional fijo, con vecinos a desplazamientos 1 y 3 y propagación máxima de dos saltos. Este es el registro histórico de esas pruebas locales breves con topología construida.
| Agentes en la red | p95 anterior | p95 posterior |
|---|---|---|
| 32 | 5.66 ms | 4.28 ms |
| 128 | 13.21 ms | 4.91 ms |
| 512 | 47.64 ms | 5.15 ms |
Figura 1. Comparación histórica antes y después con la misma carga. El eje horizontal ordena los tres tamaños de prueba; las líneas guían la lectura. Cada punto es el p95 de 12 consultas.
Con 512 agentes, el rendimiento pasó de unas 22 consultas por segundo a unas 209. Cada consulta seguía visitando 11 agentes; ahora construía solo 10 resúmenes y examinaba 50 contribuidores. Ambos recuentos fueron iguales en los tres tamaños.
El análisis pareado contrastó candidatos, traspasos, visitas y contadores originales: permanecieron iguales en el registro. La explicación del cambio es concreta: se eliminó preprocesamiento que la consulta no utilizaba. La nueva curva de tiempo y los nuevos contadores se corroboran mutuamente.
El resultado corresponde a aquella máquina única, ejecución síncrona y topología construida. Cada grupo contiene solo 12 solicitudes; el p95 es una interpolación lineal sobre una muestra corta. En producción, concurrencia, red y cambios en los datos también afectan a la cola de latencia. Lo más valioso aquí fue localizar y eliminar trabajo previo a la solicitud que realmente crecía con el conjunto total.
Un algoritmo local necesita una ruta local de solicitud
Un algoritmo puede ser austero en su bucle principal y recorrer todos los datos al inicializar, serializar, mantener índices o limpiar. Esta omisión estaba en la construcción de resúmenes; los nuevos contadores incorporaron ese trabajo al coste de la misma solicitud.
En otro sistema se puede hacer un experimento pequeño: mantener fijos los objetos que necesita la solicitud, aumentar los irrelevantes y registrar el tiempo de extremo a extremo. Si las operaciones centrales no cambian pero el tiempo crece, conviene recorrer la ruta en busca de trabajo sin contabilizar.
Tras la corrección, solo se construye cada resumen utilizado: 10 resúmenes, 50 contribuidores. Una consulta local ya no exige preparar los carteles de toda la red.
Materiales: datos de la prueba local de capacidad y el análisis pareado de Discovery Front del 1 de septiembre de 2026. En esta revisión se contrastaron los archivos originales, la configuración y el código actual de construcción de resúmenes. El código del artículo es una simplificación explicativa. Las ubicaciones detalladas constan en SOURCE-NOTES.md del paquete editorial. Esta nota reescribe un experimento existente.