Cómo solucionar búsquedas lentas en Elasticsearch para una mejor experiencia de usuario

Para cualquiera que use Elasticsearch® como su motor de búsqueda, identificar y solucionar problemas de búsquedas es una habilidad crucial que hay que dominar. Ya sea en comercio electrónico, observabilidad o soluciones de búsqueda orientadas al lugar de trabajo, un Elasticsearch lento afectará negativamente la experiencia de tu usuario.
Para identificar búsquedas lentas en Elasticsearch, puede utilizar el log de demora, que captura la búsqueda ejecutada en un determinado umbral. Configurar correctamente el umbral del log de demora es un desafío en sí mismo. Por ejemplo, una búsqueda que tarda 500 milisegundos con carga completa podría ser aceptable, pero la misma búsqueda con carga baja podría ser inaceptable. El log de demora no diferencia y registra todo lo que supere los 500 milisegundos. El log de demora hace muy bien su trabajo, por lo que puede capturar diferentes niveles de granularidad según el valor del umbral. El rastreo, en cambio, puede observar todas las búsquedas, identificando cuántas de sus búsquedas se encuentran dentro de ciertos umbrales.
El monitoreo de rendimiento de aplicaciones (APM) ya no se limita solo a tu aplicación. Mediante la instrumentación en Elasticsearch, ahora podemos agregar Elasticsearch como un servicio completo en lugar de una dependencia en tu stack de aplicaciones. De esta manera, obtenemos una vista del rendimiento más matizada de la que puede proporcionar el log lento.
Para el siguiente ejemplo, nuestro corpus de datos es OpenWebText, que proporciona aproximadamente 40 GB de texto puro y cerca de 8 millones de documentos individuales que se ejecutan localmente en un Macbook M1 Max con 32 GB de RAM.
Cómo empezar
La activación del rastreo en Elasticsearch se realiza con ajustes estáticos (configurados en el elasticsearch.yml) y ajustes dinámicos, que pueden alternarse durante el tiempo de ejecución mediante un comando PUT _cluster/settings, donde uno de esos ajustes dinámicos es la tasa de muestreo. Algunos ajustes, como la tasa de muestreo, pueden alternarse durante el tiempo de ejecución. En el elasticsearch.yml queremos configurar lo siguiente:
Válido para la versión 9.x
telemetry.agent.enabled: true
telemetry.agent.server_url: "url of the APM server"Válido para la versión 7.x y 8.x
tracing.apm.enabled: true
tracing.apm.agent.server_url: "url of the APM server"El token secreto (o clave API) debe estar en el almacén de claves de Elasticsearch. La herramienta keystore debería estar disponible en <your elasticsearch install directory>/bin/elasticsearch-keystore usando el siguiente comando para las versiones 7.x y 8.x elasticsearch-keystore add tracing.apm.secret_token o tracing.apm.api_key. Para la versión 9.x, por favor usa telemetry.secret_token o telemetry.api_key en su lugar. Luego de eso, tienes que resetear Elasticsearch. Más información sobre el rastreo se puede encontrar en nuestro documento de rastreo.
Una vez que APM está activo, podemos ver la vista de APM en Kibana y observar que Elasticsearch captura varios endpoints de API REST automáticamente. Aquí, nos enfocamos principalmente en las llamadas POST /{index}/_search y vemos qué podemos obtener de ellas.

Al examinar una búsqueda sencilla directamente en el cuadro GET /{index}/_search, vemos el siguiente desglose en cascada. Esto contiene rangos internos que proporcionan información más detallada sobre lo que Elasticsearch está haciendo internamente. Y vemos la duración total de esta búsqueda (86 milisegundos).

Los metadatos que acompañan a la búsqueda incluyen información extensa sobre la cabecera HTTP, el agente de usuario, la ubicación del Node de Elasticsearch (metadatos del Proveedor Cloud, nombre de host, información del contenedor), algo de información del sistema y detalles de la URL. Utilizando algo de información básica de transacciones, podemos crear un gráfico de Lens que represente la duración promedio de las transacciones y nos permita ver si hay una tendencia al alza o a la baja.
Nuestra aplicación de búsqueda
¡Es genial no tener que usar logs lentos nunca más! Puedo determinar la duración de la transacción e identificar cuántas búsquedas se responden por debajo de cualquier umbral. Sin embargo, hay un inconveniente — Elasticsearch no captura la búsqueda enviada, por lo que sabemos que una búsqueda tomó mucho tiempo, pero no sabemos cuál fue la búsqueda.
Vamos a instrumentar una app de búsqueda de muestra. En este caso, usaremos una app de Flask simple con dos rutas, search_single y search_phrase, que representarán una búsqueda match y una match_phrase en Elasticsearch. Por ejemplo, podríamos usar las siguientes búsquedas:
{
"query": {
"match": {
"content": "support"
}
}
}
And
{
"query": {
"match_phrase": {
"content": "support protest"
}
}
}El siguiente código de Flask implementa la ruta search_single. La search_phrase es muy similar, excepto que utiliza match_phrase en lugar de match.
@app.route("/search_single", methods=["GET"])
def search_single():
query = request.args.get("q", "")
if not query.strip():
return jsonify({"error": "No search query provided"}), 400
try:
result = es.search(
index=ES_INDEX, query={"match": {"content": query}}
)
hits = result["hits"]["hits"]
response = []
for hit in hits:
response.append(
{
"score": hit["_score"],
"content": hit["_source"]["content"],
}
)
return jsonify(response)Con todo eso preparado, ahora puedo llamar a curl -XGET "http://localhost:5000/search_single?q='microphone'" para realizar una búsqueda del término microphone.
Principalmente añadimos APM a nuestra aplicación de búsqueda para observar, pero nuestros agentes de APM capturan las solicitudes salientes y las enriquecen con información de metadatos. En nuestro caso, span.db.statement contiene la búsqueda de Elasticsearch. Y en este caso a continuación, alguien buscó window.

La combinación de todo
En mi servicio Flask, configuré el tamaño de la búsqueda en 5 000, lo que significa que Elasticsearch debería darme hasta 5 000 documentos coincidentes en una sola respuesta JSON. Ese es un número grande, y gran parte del tiempo se dedica a recuperar esa cantidad de documentos del disco. Después de cambiarlo a los 100 documentos principales, puedo identificar rápidamente qué sucedió en mi dashboard al compararlo.
Mirar una transacción en la vista de APM y activar la función de labs para la ruta crítica crea una superposición que nos muestra dónde pasa el tiempo nuestra aplicación.

Después de eso, creé un dashboard usando los campos transaction.duration.us, es_query_took, transaction.name. Los filtros KQL generales contienen service.name, processor.event: transaction, transaction.name: POST /{index}/_search.
Consejo adicional: ve a la gestión de Data view > selecciona tu Data view que contiene los flujos de datos de APM > selecciona el campo transaction.duration.us > y cambia el formato a duration. Ahora lo mostrará automáticamente en una salida legible por humanos en lugar de en microsegundos.
Aprovechando la característica de anotación de Lens, podemos ver en el Lens central que el cambio a 100 documentos redujo considerablemente la transacción de búsqueda promedio. No solo eso, mira el recuento total de registros en la esquina superior derecha. Como podemos hacer búsquedas más rápido, ¡tenemos un mayor rendimiento! Realmente me gustan los histogramas, así que creé uno en el medio de la fila superior, donde tengo la duración de la transacción en el eje X y el recuento de registros en el eje Y. Además, APM ofrece métricas, por lo que podemos identificar cuánto uso de CPU % ocurre en cualquier momento, así como el uso de heap de JVM, el uso de non-heap, el recuento de hilos y más información útil.

Conclusión
En esta publicación de blog te mostramos lo importante que es tener Elasticsearch como una aplicación instrumentada e identificar cuellos de botella mucho más fácilmente. Además, puedes usar la duración de la transacción como métrica para la detección de anomalías, realizar pruebas A/B para tu aplicación y no volver a preguntarte si Elasticsearch se siente más rápido, ya que ahora tienes datos para responder a esa pregunta. Además, todos los metadatos que se recopilan desde los agentes de usuario hasta las búsquedas te ayudan a solucionar problemas.
Los dashboards y la Data view se pueden importar desde aquí.
ADVERTENCIA
Hay un problema con la duración de las transacciones dentro de Elasticsearch. Esto está corregido en la próxima versión de 8.9.1. Hasta entonces, las transacciones usan el reloj incorrecto, lo cual altera la duración total.
El momento del lanzamiento de cualquiera de las características o funcionalidades descritas en esta publicación queda a exclusivo criterio de Elastic. Es posible que algunas características o funcionalidades que no estén disponibles en este momento no se lancen a tiempo o no se lancen en absoluto.