Qué ocurrió
DNS · Rust · Ingeniería de rendimiento · Ingeniería de software · Informe técnicopublicado el 27 ago 2026 · despliegue del 18 may al 6 jul 2026
Representación, no algoritmo · y el caso raro en que más pequeño es también más rápido
533 bytes por entrada, 100 terabytes por flota
Big Pineapple, la plataforma que hay detrás de 1.1.1.1, mantiene más de 250 mil millones de entradas de caché DNS en cada momento. Cinco cambios en cómo se dispone una de esas entradas en memoria la llevaron de 953 bytes a 420, liberando unos 100 terabytes en la flota de Cloudflare. Ninguno de los cinco es un algoritmo: son cambios sobre qué tipo de Rust contiene qué. Las afirmaciones de disposición de abajo se comprobaron compilándolas, no dándolas por buenas.
Las cifras Cada una recalculada a partir del antes y el después del propio artículo
- −56%huella de caché por entrada, de 953 bytes a 420, en el banco de pruebas
- ~100 TBconjunto de trabajo agregado liberado en la flota, medido en producción
- 250 mil Mentradas de caché DNS mantenidas en cada momento
- +43%rendimiento de inserción en caché, de 625,000 a 893,000 entradas por segundo
- −19%latencia de búsqueda en caché, de 828 ns a 670 ns
El registro, graduado Parte de esto un lector puede comprobarlo sin ayuda de Cloudflare
| Grado | Qué | Cómo se comprobó |
|---|---|---|
| Confirmado | Un Vec<T> ocupa 24 bytes y un Box<[T]> 16, así que quitar el campo de capacidad no usado ahorra 8 bytes por campo: 64 bytes en los ocho campos de ese tipo de una entrada de caché. Lo mismo vale para String frente a Box<str>. | Compilado aquí e impresos los tamaños. Coincide exactamente con el artículo. |
| Confirmado | Sustituir tres listas de registros por una lista y dos desplazamientos de sección u16 ahorra 28 bytes por entrada: tres punteros gordos cuestan 48 bytes, uno más dos desplazamientos cuesta 20. | Compilado aquí. 48 − 20 = 28, tal como se afirma. |
| Confirmado | Un enum de Rust es tan grande como su variante mayor, así que un registro A con 4 bytes de dirección ocupaba una ranura de 144 bytes dimensionada para NAPTR. Encajonar las variantes grandes deja el enum en 24 bytes, ahorrando 120 en cada registro A y AAAA, que son el 81% del tráfico. | Compilado aquí: el enum encajonado son 24 bytes, y el NAPTR reconstruido a partir de la prosa del artículo son 136. Los 144 del enum dependen de sus tipos de campo exactos. |
| Confirmado | El DNS repite los nombres de propietario en el formato de cable y los comprime con un puntero de dos octetos, así que la caché guarda el propietario completo en su lugar, cambiando memoria por no perseguir punteros en la ruta caliente. Cuando el propietario coincide con el nombre consultado, ahora se omite y se infiere de la clave de caché. | El puntero de compresión de dos octetos es el RFC 1035 §4.1.4, leído directamente. Sus dos primeros bits son 11, dejando un desplazamiento de 14 bits. |
| Confirmado, no verificable aquí | El resultado en producción: la memoria residente p99 por instancia bajó de 9.3 GB a 5.3 GB y la p90 de 6.5 GB a 3.8 GB, en un despliegue del 18 de mayo al 6 de julio de 2026, para un agregado de unos 100 TB. | Ambos porcentajes se recalculan correctamente. Solo Cloudflare puede medir su propia flota; no se publica desglose. |
| Sin confirmar | Que 130 servidores Gen 13 sumen 100 TB de RAM, que es la equivalencia que da el artículo. Sale a unos 769 GB por servidor; no se encontró especificación publicada de memoria de Gen 13 con la que contrastarlo. | Aritmética a partir de las dos cifras del propio artículo; la especificación no es pública. |
Cronología
Desplegado, luego contado El trabajo estaba terminado y en producción siete semanas antes de contarse
- 18 may 2026Comienza el despliegue. Cada versión lleva uno o varios de los cinco cambios, así que la memoria baja por escalones y no de golpe.
- 18 may – 6 jul 2026Las instancias reiniciadas empiezan con cachés vacías y usan menos memoria hasta que se llenan, así que los valles del gráfico no son el resultado. Lo son las mesetas.
- 6 jul 2026El despliegue se completa en todos los servicios: 49 días de principio a fin.
- 27 ago 2026Cloudflare publica el relato, de Sebastiaan Neuteboom, con el método del banco de pruebas, el gráfico de producción y nueve diagramas.
Lo que no tiene fecha Dos, y una es el objeto de todo el ejercicio
El artículo dice que cada versión llevaba uno o varios de los cinco cambios, pero no dice cuál llevaba cuál, así que los escalones del gráfico no pueden emparejarse con las optimizaciones que los causaron. Y la memoria liberada no se ha gastado: Cloudflare dice que planea reinvertirla en una caché mayor, lo que subiría las tasas de acierto y reduciría el volumen de consultas aguas arriba. Eso está escrito en futuro, y no se da fecha. Hasta que ocurra, el resultado de este trabajo son 100 terabytes de holgura y no una caché mejor, que es un resultado perfectamente bueno, y distinto del que describe el plan.
El argumento
Cambiar la representación, no el algoritmo Y la premisa que lo permite: la entrada no se vuelve a modificar
La afirmación que hace el artículo sobre su propio trabajo es modesta y merece tomarse en serio: no cambió ninguna política de caché, regla de expulsión ni estructura de datos. Lo que cambió es qué tipo contiene qué. La premisa que desbloquea los cinco cambios es una frase de la segunda sección: una vez que una respuesta DNS está en la caché, no se modifica nunca más. Un Vec lleva un campo de capacidad y espacio de montículo sobreasignado para poder crecer; un valor que nunca crecerá está pagando por una capacidad que no puede usar. El mismo razonamiento recorre el resto: tres listas de registros separadas se vuelven una lista con dos desplazamientos u16, porque los recuentos de sección caben en 16 bits; el nombre de propietario de un registro se omite cuando coincide con el nombre consultado, porque la clave de caché ya está a mano en cada búsqueda; y el enum de datos de registro deja de dimensionarse por su variante más rara. El par más interesante son los dos últimos, porque discuten entre sí. Encajonar las variantes grandes del enum arregla el relleno pero introduce el redondeo del asignador y dispersa los datos por el montículo; guardar los datos de registro como un búfer de bytes contiguo elimina los dos costes que el encajonado acababa de crear. Quien se detuviera en el cuarto cambio construiría algo peor que quien siguiera leyendo, y el artículo es inusualmente honesto al exponer el paso intermedio en vez de presentar el diseño final como si hubiera llegado entero.
- 5cambios, ninguno a un algoritmo
- 1premisa bajo los cinco: la entrada nunca se muta
- 2de los cinco deshacen costes que otros introdujeron
Los cinco cambios En el orden en que se describen, que es también el orden en que se apoyan unos en otros
| Cambio | Por qué sale gratis | Ahorro |
|---|---|---|
1. Vec<T> pasa a Box<[T]>, String pasa a Box<str> | Una entrada en caché nunca crece, así que el campo de capacidad y la cola de montículo reservada son peso muerto. | 64 bytes por entrada, más la cola de montículo desperdiciada |
2. Tres listas de registros pasan a una, con dos desplazamientos de sección u16 | Los recuentos de registros por sección caben en 16 bits, así que un desplazamiento cuesta 2 bytes donde una lista cuesta un puntero gordo de 16. | 28 bytes por entrada |
| 3. Omitir el nombre de propietario del registro cuando coincide con la consulta | La clave de caché está presente en cada búsqueda, así que el nombre puede restaurarse en vez de guardarse. La mayoría coincide; los que van tras un CNAME no, y conservan el suyo. | Una asignación de montículo por registro, en el caso común |
| 4. Encajonar las variantes grandes del enum | No sale gratis. Arregla 120 bytes de relleno en los registros comunes pero añade redondeo del asignador y dispersa los datos por el montículo. | 120 bytes por registro A o AAAA |
| 5. Guardar los datos de registro en un único búfer de bytes contiguo | Elimina los dos costes que introdujo el cambio 4, y permite copiar la mayoría de tipos de registro directamente a una respuesta saliente sin reserializar. El coste: los registros ya no pueden indexarse aleatoriamente. | Latencia de búsqueda −5%, rendimiento de inserción +13%, por sí solos |
Lo que añaden otros
Tres formas de comprobar esto sin Cloudflare Una propiedad rara en un artículo de un operador sobre su propia flota
Un compilador
Las afirmaciones de disposición
Vec24 bytes frente aBox<[T]>16, yString24 frente aBox<str>16: 8 por campo, 64 en ocho campos. Exactamente la cifra del artículo.- Tres punteros gordos 48 bytes, uno más dos desplazamientos
u1620: un ahorro de 28 bytes, tal como se afirma. - Reconstruir NAPTR a partir de la prosa del artículo da 136 bytes exactos. El enum salió 136 y no 144: la etiqueta cupo en el relleno sobrante, lo que depende de tipos de campo que el artículo no publica. El mecanismo queda confirmado; los últimos 8 bytes son suyos.
Un RFC
Las afirmaciones sobre DNS
- El §4.1.4 da la compresión de nombres como “una secuencia de dos octetos” cuyos dos primeros bits son
11, dejando un desplazamiento de 14 bits. La descripción del artículo es correcta. - Por qué la caché no la usa es criterio propio de Cloudflare, no del RFC: perseguir punteros de compresión en la ruta caliente de búsqueda es caro, así que gasta memoria en su lugar.
- El §4.1.4 da la compresión de nombres como “una secuencia de dos octetos” cuyos dos primeros bits son
Aritmética
Los resultados publicados
- Cada porcentaje del artículo se recalcula desde su propio antes y después: −55.9%, −58.1%, +42.9%, −19.1%, −43.0%, −41.5%.
- La mezcla de tráfico suma 100%, y A más AAAA es 81%: el “más del 80%” del artículo.
- “Más de 15 terabytes” para el primer cambio son 16.0 TB decimales pero 14.6 TiB binarios. Cierto en decimal, y conservador, ya que el recuento de entradas es un mínimo.
La garantía en la que se apoya el artículo y no nombra Hallazgo propio de este informe, compilado y confirmado
El tercer cambio guarda el propietario como Option<Box<Name>> y lo pone a None cuando el propietario coincide con el nombre consultado. Compilado aquí, Option<Box<T>> tiene el mismo tamaño que Box<T>: 16 bytes en ambos casos. Esa es la optimización de puntero nulo de Rust: como un Box nunca puede ser nulo, el compilador usa el propio puntero nulo como discriminante de None, de modo que la envoltura Option no cuesta nada. Sin esa garantía el cambio sería un trato mucho peor. Cada registro pagaría un byte de discriminante más relleno de alineación por el privilegio de omitir a veces un propietario: recuperar una asignación de montículo en el caso común al precio de bytes en todos los casos, en una estructura donde todo el ejercicio consiste en contar bytes. El artículo presenta el cambio como un intercambio directo de almacenamiento por una inferencia en tiempo de búsqueda y no menciona la regla del lenguaje que hace el intercambio unilateral. Es de esas cosas que son invisibles cuando funcionan y caras cuando no, y conviene saber en cuál de las dos se está confiando.
Qué es el banco de pruebas, y qué no El artículo traza esta línea él mismo, y merece la pena recogerlo
El 56% es una cifra de banco de pruebas: entradas generadas al azar para acercarse a la mezcla de registros de producción, con TXT haciendo de todos los tipos que no son A/AAAA con un tamaño aleatorio de 64 a 224 bytes, y la memoria contada por un asignador propio que envuelve al del sistema de Rust. El artículo dice con sus palabras que estas entradas “aproximan la producción en vez de reproducirla exactamente”, y que la memoria del proceso también depende de la mezcla de tráfico, la ocupación de la caché, el estado del asignador y todo lo que hay fuera de la caché, razón por la cual también se midió la memoria residente en instancias de producción. Los dos números tienen tamaños distintos y la brecha es instructiva. Llevar el ahorro del banco de pruebas directamente a la flota da 533 bytes por 250 mil millones de entradas, o unos 133 terabytes. La cifra publicada es 100: aproximadamente tres cuartas partes del producto. Cloudflare podría haber publicado el número mayor con una nota al pie y no lo hizo. Es también por lo que las mesetas del gráfico de producción, y no sus valles, son el resultado: las instancias reiniciadas empiezan con cachés vacías, y una caché vacía no es una caché eficiente.
Conclusión
Qué se generaliza, y qué no Tres hallazgos, cada uno con su límite
La parte comprobable es la que importa
El número del título, unos 100 terabytes, es la cifra menos comprobable del artículo: un agregado sobre una flota que solo su operador puede medir, sin desglose. El mecanismo que hay debajo es el más comprobable, porque cualquiera con un compilador puede reproducirlo en un minuto. Ese es el orden correcto. Quien confirme que Vec son 24 bytes y Box<[T]> 16 se ha ganado un motivo para creer la parte que no puede ver, y el artículo da suficiente detalle para que esa comprobación sea posible, lo que no ocurre en la mayoría de los textos de ingeniería que abren con una cifra de titular.
Más pequeño y más rápido a la vez no es una ley
El espacio y el tiempo suelen intercambiarse, y aquí no lo hicieron: la huella cayó un 56% mientras las inserciones se aceleraron un 43% y las búsquedas un 19%. La razón es específica y no general. Menos asignaciones significa menos trabajo del asignador en la ruta de inserción, y datos contiguos significan menos búsquedas de línea de caché en la ruta de consulta, así que ambas métricas resultaron mejoradas por los mismos cambios. El tercer cambio es el contraejemplo dentro del mismo artículo: gasta memoria a propósito — guardar nombres de propietario completos en vez de seguir punteros de compresión — para mantener rápida la ruta caliente. La lección es medir ambas cosas, no esperar ambas.
El ahorro es holgura, todavía no una caché mejor
Cloudflare dice que planea gastar la memoria liberada en una caché mayor, lo que subiría las tasas de acierto y reduciría el volumen de consultas aguas arriba. Eso está escrito en futuro y sin fecha. Hasta que ocurra, lo que ha producido el trabajo son 100 terabytes de capacidad sin usar y una caché más rápida del mismo tamaño: un buen resultado, y distinto del plan. Si la reinversión llega, y qué le hace a las tasas de acierto, es lo que hay que vigilar y lo que nadie puede aún informar.
Qué resolvería el resto Nada de esto está en disputa; simplemente no se ha publicado
- Si la memoria liberada se convierte en capacidad de caché. Declarado como plan, en futuro y sin fecha. Un artículo de seguimiento con cifras de tasa de acierto lo resolvería.
- Qué versión llevó qué cambio. El artículo dice que cada una llevaba uno o varios, así que los escalones del gráfico de producción no pueden atribuirse a optimizaciones concretas.
- La especificación de memoria de Gen 13. La equivalencia de 130 servidores implica unos 769 GB por servidor; no se halló especificación publicada para comprobarlo.
- Qué parte de la flota es intensiva en ECS. El artículo dice que las ganancias son mayores donde EDNS Client Subnet multiplica las variantes cacheadas de una misma consulta, pero no da proporción.