Toda una red de sitios web se volvió lenta a la vez, y ni un solo servidor estaba ocupado.
Una red de portales de empleo se sintió sobrecargada de golpe. Todos los servidores estaban inactivos. Una sola búsqueda de ciudad era más de la mitad de todo el tiempo de base de datos. Así la encontramos y la corregimos con un único índice online.
En este artículo 8 secciones
- Todos los sitios de una red de portales de empleo se ralentizaron a la vez mientras los servidores estaban inactivos, y el instinto era comprar otros más grandes.
- Todos los niveles estaban inactivos salvo uno: los balanceadores de carga y los servidores web apenas trabajaban. Toda la granja esperaba a la base de datos, y la base de datos esperaba a una consulta.
- Esa consulta, una simple búsqueda de ciudad, era más de la mitad de todo el tiempo de base de datos, y escaneaba una tabla entera en cada llamada para devolver una sola fila.
- Un índice online, aplicado sin interrumpir los sitios, convirtió el escaneo en una búsqueda directa. Sin servidores más grandes.
Una red de portales de empleo se volvió blanda al mismo tiempo. No una página, no un sitio: todos, juntos, esa niebla a escala de granja que hace que un operador suponga que los servidores se ahogan y que toca comprar otros más grandes. Esa suposición es cara, es habitual, y en este caso era errónea. Todas las máquinas de la granja se aburrían. Toda la granja esperaba a la base de datos, y la base de datos esperaba a una sola consulta.
Todos los niveles estaban inactivos salvo uno
En una ralentización de toda la granja, lea la utilización de cada nivel antes que nada, y vea cuál está realmente al límite. Los balanceadores de carga estaban al ralentí. Los servidores web se aburrían. Nada en la ruta de la petición trabajaba lo bastante como para explicar un sitio lento.
- Balanceadores de carga
- inactivos
- Servidores web
- apenas trabajando
- Base de datos
- esperando a una consulta
Esta es la pista que zanja la discusión sobre capacidad antes de que empiece. Si todos los niveles están inactivos salvo la base de datos, un servidor web más grande le compra una máquina inactiva más rápida. La limitación nunca fue el cómputo, y ningún pedido de hardware iba a arreglarlo.
La respuesta cara era comprar más máquinas
| El instinto | La medición |
|---|---|
| Toda la granja va lenta, así que los servidores están sobrecargados. Compre otros más grandes. | Todos los niveles salvo la base de datos estaban inactivos. La capacidad nunca fue la limitación. |
| LO QUE DECÍAN LOS DATOSTiene que ser un problema de hardware. | El hardware estaba sano y era demostrable: balanceadores de carga y servidores web apenas trabajando. |
| Reparta la carga entre más máquinas. | Una consulta era más de la mitad de todo el tiempo de base de datos. Más máquinas la ejecutarían más a menudo, escaneando igual. |
Más hardware habría escalado el desperdicio, no eliminado. El único paso siguiente honesto era averiguar en qué estaba gastando realmente su tiempo la base de datos.
Agregamos el historial de consultas por huella
Una aplicación rara vez escribe la misma consulta de la misma forma dos veces. La misma búsqueda aparece parametrizada de varias maneras distintas, así que contar el texto bruto de las consultas esconde al culpable entre el ruido. La solución es agregar por una huella que sobreviva a esa inconsistencia, y después clasificar cada sentencia por su parte del tiempo total de base de datos. Lo ejecutamos sobre el historial completo de consultas.
-- reconstructed, de-identified rendering of cleared facts. not a real capture.
-- full query history, grouped by query_hash
-- (a fingerprint that survives inconsistent parameterisation)
SELECT TOP 5
query_hash,
SUM(execution_count) AS calls,
SUM(total_logical_reads) AS pages_read,
SUM(total_elapsed_time) * 100.0
/ SUM(SUM(total_elapsed_time)) OVER () AS pct_of_db_time
FROM sys.dm_exec_query_stats
GROUP BY query_hash
ORDER BY pct_of_db_time DESC;Una fila destacaba: más de la mitad de todo lo que hacía la base de datos, gastado en una sola sentencia. El método es aburrido a propósito, no adivina, y es el mismo cada vez.
Una consulta era más de la mitad de la base de datos
La sentencia que salió es de las que nunca miraría dos veces. Una búsqueda de ciudad, dos columnas, un filtro.
-- reconstructed, de-identified. table/column names renamed from the real schema.
SELECT CityID, CityName
FROM Cities
WHERE RoutingPath = @p;
-- Execution plan: Clustered Index Scan (a full scan)
-- Returns: ONE row
-- Filtered column: RoutingPath --> no indexLa columna por la que filtraba no tenía índice. Así que cada llamada escaneaba la tabla entera para entregar una sola fila. Por sí solo es un coste pequeño; repetido en cada vista de página de toda la red, se convirtió en lo más grande que hacía la base de datos.
Una respuesta de una fila debería leer un par de páginas, no la tabla entera
“Una respuesta de una fila debería leer dos o tres páginas, no cientos.”
Esa frase es todo el diagnóstico, comprimido en algo que se le puede decir a la persona responsable del código. Nada más hace que una búsqueda de una sola fila lea tanto. Ni un disco lento, ni una CPU ocupada, ni una mala noche. Una respuesta de una fila que lee la tabla entera es un escaneo completo, y un escaneo completo sobre una columna filtrada es una firma inconfundible: la columna necesita un índice. No hizo falta discutir sobre hardware, solo mostramos las lecturas.
Un índice online, de un escaneo a una búsqueda directa
- Un escaneo completo de la tabla, para una fila
- Sin índice en la columna filtrada
- Más de la mitad de todo el tiempo de base de datos
- Una búsqueda por índice, un par de páginas para la misma fila
- Una pequeña fracción del trabajo por llamada
- El índice entró online, sin interrumpir los sitios
-- reconstructed, de-identified. index name illustrative, on the renamed identifiers.
-- Index the column in the WHERE clause; cover the two columns it returns
CREATE NONCLUSTERED INDEX IX_Cities_RoutingPath
ON Cities (RoutingPath)
INCLUDE (CityID, CityName)
WITH (ONLINE = ON); -- applied without interrupting the site
-- New execution plan: Index SeekUn índice, sobre la única columna por la que la aplicación filtraba realmente. Se aplicó online, sin interrumpir los sitios, y la búsqueda que había dominado la base de datos se convirtió en una de las cosas más baratas que hacía.
El ingeniero del cliente sumó al diagnóstico
Lo mejor de este trabajo no fue nuestro índice. Fue lo que ocurrió cuando el propio ingeniero de bases de datos del cliente se unió y sumó al diagnóstico: trajo un patrón de bloqueo lector/escritor desde su lado del sistema. Integramos su corrección con la nuestra, y las dos entraron juntas.
“El ingeniero del cliente salió de la llamada como colaborador.”
Esa es la diferencia entre un ticket de soporte y un diagnóstico. Cuando el hallazgo es cierto y se muestran las pruebas, las dos partes dejan de defender posiciones y empiezan a mejorar la plataforma juntas.
Cuando todos los niveles están inactivos salvo uno, deje de mirar la capacidad
La lección es corta y es lo contrario del reflejo. Lentitud en toda la granja con máquinas inactivas no es un problema de capacidad, es una cuestión de software disfrazada de capacidad. Esto es lo que hay que comprobar antes de firmar un pedido de hardware.
Lea primero la utilización de cada nivel.
Balanceadores de carga, web, base de datos. Si todo está inactivo salvo un nivel, la capacidad no es su problema y un servidor más grande no lo arreglará.
Agregue las estadísticas de consultas por huella.
Agrupe su historial por un hash que sobreviva a la parametrización inconsistente, de modo que la misma sentencia escrita de varias formas cuente como una. El peor infractor suele destacar por un amplio margen.
Compare páginas leídas con filas devueltas.
Una respuesta de una fila que lee cientos de páginas está escaneando, no buscando. Esa brecha es la firma de un índice que falta.
Indexe la columna por la que la aplicación filtra realmente.
No todas las columnas. La de la cláusula WHERE que se ejecuta millones de veces. Aplíquelo online, sin interrumpir el sitio.
Cachee las pequeñas tablas calientes.
Las tablas de consulta pequeñas y que rara vez cambian pertenecen a la caché, no a la ruta crítica de la base de datos en cada vista de página.
Durante todo el proceso, la máquina se mantuvo tranquila. Los balanceadores de carga al ralentí, los servidores web aburridos, y la corrección fue un índice sobre la columna por la que filtraba la aplicación. El servidor de base de datos estaba sano; una sentencia dentro de él necesitaba un índice.
Respuestas directas
¿Cómo puede una consulta ser más de la mitad de la carga de una base de datos?+
Cuando una consulta se ejecuta con la frecuencia suficiente y hace demasiado trabajo cada vez, domina todo lo demás. Esta se ejecutaba en cada vista de página y escaneaba una tabla entera en cada llamada para devolver una sola fila, porque la columna por la que filtraba no tenía índice. Multiplique un pequeño desperdicio por millones de llamadas y se convierte en toda la base de datos.
¿Por qué estaban inactivos los servidores si los sitios iban lentos?+
Porque el cuello de botella estaba dentro de la base de datos, esperando a una consulta. Los balanceadores de carga y los servidores web apenas trabajaban. Toda la granja esperaba a la base de datos, y la base de datos esperaba a una búsqueda que debería haber sido instantánea. Añadir servidores solo habría añadido más máquinas inactivas.
¿Cómo se encuentra la consulta que es realmente el problema?+
Se agrega el historial completo de consultas por una huella que sobreviva a la parametrización inconsistente, y después se clasifica por la parte del tiempo total de base de datos. El método es aburrido y no adivina.
¿Cuál es la firma de un índice que falta?+
Una respuesta de una fila que lee cientos de páginas. Si una consulta devuelve una fila y el plan muestra un escaneo sobre toda la tabla, la columna por la que filtra no está indexada.
¿Arreglarlo requirió downtime?+
No. El índice entró online, aplicado sin interrumpir los sitios, y convirtió el escaneo en una búsqueda directa.
¿Quién lo arregló, ustedes o el cliente?+
Los dos, juntos. Nosotros encontramos la búsqueda y añadimos el índice; el propio ingeniero de bases de datos del cliente se unió al diagnóstico y trajo un patrón de bloqueo lector/escritor desde su lado. Integramos su corrección con la nuestra.
¿Sitio lento, servidores inactivos? Encontraremos la causa real.
Hable con un ingeniero que lee planes de consulta, no solo dashboards, sobre lo que realmente está ralentizando su plataforma.
Hable con un ingenieroEl instinto ante una granja lenta es comprar la salida. La respuesta honesta casi siempre es más barata: lea cada nivel, encuentre el que está al límite, y vaya a leer sus consultas.
Ha llegado al final.
Ponga la lectura a trabajar
¿Qué está ejecutando?
Cuéntenos la carga de trabajo, el tráfico y los requisitos de recuperación. Empiece por el configurador de servidores o repase los detalles con un ingeniero.
Escrito por los ingenieros que construyen y operan la infraestructura que describe.Hable con un ingeniero
