Práctica de ajuste de rendimiento de la búsqueda de datos ES de miles de millones de niveles en la comunidad Dewu

1. Antecedentes

Desde 2020, la búsqueda de resultados de anotaciones de contenido ha sido uno de los principales escenarios de uso de alta frecuencia del negocio de back-end en la comunidad. Para respaldar la búsqueda de back-end compleja, hemos almacenado una copia adicional de la información clave. del contenido de la comunidad en Elasticsearch para su uso como índice secundario. Con la subdivisión, la iteración y el paso del tiempo en el negocio de la anotación, la cantidad de documentos indexados y el RT de la búsqueda comenzaron a aumentar paulatinamente. El siguiente es el estado actual de monitoreo de este índice.1.png

Este artículo presenta cómo la comunidad usa IndexSorting para optimizar el rendimiento de búsqueda de documentos de mil millones de niveles desde los 2000ms iniciales hasta los 50ms . Si encuentra problemas y escenarios similares, creo que después de leerlo, podrá obtener toneladas de ingresos con una línea de código.

2. Proceso de exploración

2.1 Optimización inicial

El requisito inicial es muy simple, simplemente obtenga la última pantalla de paginación dinámica . En este momento, la implementación también es simple y grosera, siempre que se cumpla la función. El enunciado de la consulta es el siguiente:


{

"track_total_hits": true,

"sort": [

{

"publish_time": {

"order": "desc"

}

}

],

"size": 10

}

Dado que no se agregaron condiciones de filtrado cuando se cargó la página de inicio, se pasó a buscar los últimos 10 contenidos publicados de la biblioteca de contenido de mil millones de niveles .

Para esta consulta, es fácil encontrar que el problema ocurre en la clasificación de grandes conjuntos de resultados.Para resolver el problema, naturalmente, se piensan dos caminos:

  1. eliminar ordenar
  2. Estrechar el conjunto de resultados

Después de sopesar las demandas de los usuarios y los costos de desarrollo, se decidió "mantenerlo primero, luego optimizar": cuando el usuario abre la página de inicio, se agrega por defecto la condición de filtro de "publicado en la última semana". En este momento, la declaración se convierte en:


{

"track_total_hits": true,

"query": {

"bool": {

"filter": [

{

"range": {

"publish_time": {

"gte": 1678550400,

"lt": 1679155200

}

}

}

]

}

},

"sort": [

{

"publish_time": {

"order": "desc"

}

}

],

"size": 10

}

Después de que se lanzó este cambio, se puede decir que el efecto fue inmediato: la velocidad de carga de la página de inicio se redujo inmediatamente a menos de 200 ms, con un RT promedio de 60 ms. Este cambio también redujo la presión del negocio para nosotros y ganó mucho tiempo de investigación para la optimización posterior.

Aunque la velocidad de carga de la página de inicio de búsqueda es obviamente más rápida, en realidad no resuelve el problema fundamental: la clasificación de campos específicos en grandes conjuntos de resultados de ES sigue siendo muy lenta . Para las empresas, la experiencia de algunas funciones de límite en la página de resultados aún no es satisfactoria, como la exportación, la búsqueda dinámica completa, etc. Este punto también se puede ver claramente en el monitoreo: todavía existen consultas lentas y van acompañadas de una pequeña cantidad de tiempos de espera de la interfaz.

2.png

Para ser honesto, nuestra comprensión de ES en este período aún es relativamente básica. Solo podemos decir que podemos usarlo, saber sobre fragmentación, índice invertido y puntaje de correlación, y luego desaparece. En resumen, tenemos una dirección y empezamos a ponernos al día.

2.2 Molienda fina

2.2.1 Acumulación de conocimientos

Con los problemas que quedaron de antes, empezamos a empezar de nuevo y a aprender ES desde cero. Para optimizar el rendimiento de la búsqueda, lo primero que debemos saber es cómo funciona la búsqueda. Tomemos la búsqueda más simple como ejemplo para desensamblar todo el proceso de solicitud de búsqueda.

(1) Solicitud de búsqueda

{

"track_total_hits":false,

"query": {

"bool": {

"filter": [

{

"term": {

"category_id.keyword": "xxxxxxxx"

}

}

]

}

},

"size": 10

}

Consulta con precisión los documentos cuya categoría_id es "xxxxxxxx", recupera 10 datos, no se requiere clasificación ni número total

El proceso general se divide en 3 pasos:

  1. El cliente inicia una solicitud al Nodo1
  2. Como nodo coordinador, Node1 reenvía la solicitud a cada fragmento primario o secundario del índice, y cada fragmento ejecuta la consulta localmente.
  3. Cada nodo devuelve sus propios datos, y el nodo coordinador los resume y los devuelve al cliente

Este proceso se puede representar aproximadamente en la figura:

3.png

Sabemos que ES depende de las capacidades provistas por Lucene. La búsqueda real ocurre en Lucene, y necesitamos continuar entendiendo el proceso de búsqueda en Lucene.

(2) Lucena

Lucene contiene cuatro tipos de datos básicos, a saber:

  • Índice: Índice, compuesto por muchos Documentos.
  • Documento: Compuesto por muchos Campos, es la unidad más pequeña de Índice y Búsqueda.
  • Campo: consta de muchos términos, incluido el nombre del campo y el valor del campo.
  • Término: consta de muchos bytes. Generalmente, cada unidad más pequeña después de la segmentación de palabras del Valor de campo del tipo Texto se denomina Término.

Antes de presentar el proceso de búsqueda del índice de Lucene, permítanme hablar sobre la unidad de almacenamiento de datos más pequeña que compone el índice de Lucene: el segmento.

El índice de Lucene se compone de muchos segmentos, y cada segmento contiene el diccionario de términos del documento, la lista invertida del diccionario de términos, el almacenamiento en columnas DocValues ​​del documento y el índice directo. Puede proporcionar de forma independiente y directa una función de búsqueda externa, que es casi una versión reducida del índice de Lucene.

(3) Diccionario de términos y lista de publicaciones

4.png

La imagen de arriba muestra la apariencia general del Diccionario de términos y su lista invertida. Por supuesto, hay algunas estructuras de datos importantes aquí, como:

  • FST: índice de términos, memoria integrada. Puede realizar rápidamente consultas de términos únicos, rangos de términos, prefijos de términos y comodines.
  • BKD-Tree: para una búsqueda rápida de tipos numéricos (incluidos los puntos espaciales).
  • SkipList: la estructura de datos de la lista invertida

Hay muchos detalles aquí, y aquellos que estén interesados ​​pueden aprender sobre ellos por separado. Esto no afecta nuestro proceso de búsqueda general, pero lo repetiré aquí. Con el Diccionario de términos y la lista invertida, podemos obtener directamente el conjunto de resultados que coincida con los criterios de búsqueda. Luego, solo necesitamos recuperar el documento completo del índice directo a través del docID y devolverlo. Esto se debe a que el disco básico de ES no será lento en teoría.Suponemos que la consulta lenta ocurre en la clasificación. Entonces, ¿qué sucede cuando agrega una clasificación a la solicitud? Por ejemplo:


{

"track_total_hits":false,

"query": {

"bool": {

"filter": [

{

"term": {

"category_id.keyword": "xxxxxxxx"

}

}

]

}

},

"sort": [

{

"publish_time": {

"order": "desc"

}

}

],

"size": 10

}

Los docIds obtenidos a través de la lista invertida están fuera de orden. Ahora que se especifica el campo de ordenación, la forma más fácil y directa es extraerlos todos y luego ordenar los 10 primeros. Esto ciertamente puede lograr el efecto, pero la eficiencia es concebible. Entonces, ¿cómo lo resuelve Lucene?

(4) Valores de documento

El índice invertido puede resolver el mapeo rápido de palabra a documento, pero necesita un mapeo rápido de número de documento a valor cuando se requieren operaciones de agregación como clasificación, clasificación y cálculo matemático de resultados de recuperación. Y el índice positivo está demasiado hinchado, ¿qué debo hacer?

En este momento, ustedes pueden pensar directamente en el almacenamiento en columnas. No tiene nada de malo. Lucene introdujo una estructura de almacenamiento en columnas basada en docId——DocValues

Número del Documento valor de la columna mapeo de valores de columna
0 2023-01-13 2
1 2023-01-12 1
2 2023-03-13 3

Por ejemplo, DocValues=[2023-01-13, 2023-01-12,2023-03-13] en la tabla anterior

Si el valor de la columna es una cadena, Lucene ordenará el valor de la cadena original de acuerdo con el diccionario para generar una identificación digital. Dicho preprocesamiento puede acelerar aún más la velocidad de clasificación. Entonces obtuvimos DocValues=[2, 1, 3]

La forma de almacenamiento en columnas de Docvalues ​​​​puede acelerar nuestro recorrido. En este punto, una solicitud de búsqueda regular para obtener los primeros N registros puede considerarse como la finalización real del desmantelamiento. El análisis de la frecuencia de palabras, puntuación de relevancia, agregación y otras funciones no se tratan aquí, por lo que este artículo simplifica enormemente todo el proceso y la estructura de datos. Si está interesado en esta parte, bienvenido a discutir juntos.

En este momento, el problema de la clasificación lenta ha surgido gradualmente: aunque Docvalues ​​​​es un almacenamiento en columnas y preprocesa valores complejos en valores simples para evitar comparaciones complejas durante las consultas, aún no puede contener el gran conjunto de datos que necesitamos clasificar. . .

Parece que ES está haciendo todo lo posible y parece que realmente no es bueno para resolver el problema de consulta lenta en nuestra escena.

Sin embargo, los lectores espirituales deben haber pensado que si la lista invertida se puede almacenar en el orden que especificamos previamente, se puede ahorrar todo el tiempo de clasificación .

2.2.2 Clasificación de índices

Pronto, el documento oficial de ES "Cómo sintonizar la velocidad de búsqueda" mencionó un método de optimización de búsqueda: Clasificación de índices (Index Sorting) apareció en nuestro campo de visión.

A partir de la descripción en el documento, podemos saber que la clasificación de índices mejora el rendimiento de búsqueda principalmente en dos aspectos:

  1. Para consultas paralelas de múltiples condiciones (a y b y ...), la clasificación de índices puede ayudarnos a almacenar documentos no calificados juntos y omitir una gran cantidad de documentos no coincidentes. Pero este truco solo funciona para campos de baja cardinalidad que a menudo se usan para filtrar.
  2. Primera ruptura: cuando el orden especificado por el tipo de búsqueda y el tipo de índice es el mismo, solo se deben comparar los primeros N documentos de cada segmento, y los otros documentos solo se deben usar para el cálculo total. Por ejemplo: hay una marca de tiempo en nuestro documento y, a menudo, necesitamos buscar y ordenar de acuerdo con la marca de tiempo. En este momento, si la ordenación del índice especificado es consistente con la ordenación de búsqueda, la eficiencia de la búsqueda y la ordenación generalmente puede ser grande. mejorado.

Interrupción temprana! ! ! Era simplemente lo que faltaba, así que comenzamos a investigar sobre esto.

(1) Habilitar clasificación de índice

{

"settings": {

"index": {

"sort.field": "publish_time", // 可指定多个字段

"sort.order": "desc"

}

},

"mappings": {

"properties": {

"content_id": {

"type": "long"

},

"publish_time": {

"type": "long"

},

...

}

}

}

Como en el ejemplo anterior, los documentos se clasifican en orden descendente del campo de tiempo de publicación cuando se escriben en el disco.

En los párrafos anteriores mencionamos repetidamente docID e índice positivo. Aquí presentamos brevemente su relación por cierto. Primero, a cada documento en el Segmento se le asignará un docID. El docID comienza desde 0 y se asigna secuencialmente. Cuando no hay IndexSorting, docID se asigna de acuerdo con el orden en que se escriben los documentos.Después de establecer IndexSorting, el orden de docID es consistente con el orden de IndexSorting.

La siguiente figura describe la relación entre docID y el índice de reenvío:

5.png

Así que mira de nuevo nuestra consulta original:


{

"track_total_hits":true,

"sort": [

{

"publish_time": {

"order": "desc"

}

}

],

"size": 10

}

Al consultar en Lucene, se encuentra que el orden de la lista invertida del conjunto de resultados es simplemente en orden descendente de tiempo_de_publicación, por lo que la consulta puede regresar después de que se consultan los primeros 10 datos, lo que logra una interrupción temprana y ahorra gastos generales de clasificación. . Entonces, ¿cuál es el precio?

(2) Consideración

IndexSorting es diferente de la clasificación en tiempo de consulta. La esencia es preprocesar los datos al escribir. Por lo tanto, los campos de clasificación solo se pueden especificar en el momento de la creación y no se pueden cambiar. Y debido a que los datos deben ordenarse al escribir, también tendrá un cierto impacto negativo en el rendimiento de la escritura.

Mencionamos antes que Lucene en sí mismo tiene varias optimizaciones para la clasificación, por lo que si el conjunto de resultados de búsqueda en sí no tiene tantos datos, incluso si esta función no está habilitada, aún puede tener un buen RT.

Además, dado que el número total aún debe calcularse la mayor parte del tiempo, después de habilitar la clasificación de índice, el proceso de clasificación solo se puede interrumpir por adelantado, o se debe contar el número total del conjunto de resultados. Si no puede verificar el número total u obtener el número total de otra manera, entonces puede hacer un mejor uso de esta función.

resumen:

  1. Para el escenario en el que los N elementos principales se ordenan para obtener un gran conjunto de resultados, la clasificación de índices puede mejorar significativamente el rendimiento de la búsqueda .
  2. La ordenación del índice sólo se puede especificar al crear el índice y no se puede cambiar . Si tiene más de un escenario de clasificación de campos especificado, es posible que deba elegir el campo de clasificación con cuidado.
  3. No obtener el número total puede hacer un mejor uso de la clasificación de índices .
  4. Habilitar la clasificación de índices reducirá el rendimiento de escritura hasta cierto punto. Aquí hay una captura de pantalla de los datos de ElaticsearchBenchmarks para su referencia.

6.png

见:Puntos de referencia de Elasticsearch

2.3 Efecto

Dado que nuestro negocio está lejos de alcanzar el cuello de botella de escritura ES, y hay pocos escenarios en los que los campos de clasificación se cambian con frecuencia. Después de una breve compensación, se determinó que la clasificación por índices era exactamente lo que necesitábamos, por lo que comenzamos a utilizar datos reales en línea para realizar una prueba de rendimiento simple sobre el efecto de la clasificación por índices.

(1) Prueba de rendimiento: página de inicio

7.png

(2) prueba de rendimiento: otro

Aquí, después de activar la clasificación de índices, se aleatoriza la prueba de combinación de búsqueda de varias condiciones generales y ventanas de tiempo.

8.png

Se puede ver que el efecto es muy obvio, no hay un pico como antes y RT también es muy estable, por lo que decidimos lanzar oficialmente esta función.

(3) Efecto en línea

consulta lenta

9.png!

Comparación general antes y después

10.png

Básicamente, como esperábamos, el RT de búsqueda se ha reducido considerablemente y la consulta lenta ha desaparecido por completo.

2.4 Optimización posterior

En el proceso de exploración, encontramos algunos otros métodos de optimización, algunos de los cuales, en vista de los costos y beneficios del desarrollo, no se han aplicado completamente al entorno de producción. Aquí están algunos de ellos, con la esperanza de darle un poco de inspiración.

  1. No obtenga el número total: en la mayoría de los escenarios, no consultar el número total puede reducir la sobrecarga y mejorar el rendimiento. La interfaz de búsqueda después de ES 7.x no devuelve el número total por defecto, lo cual es evidente.
  2. Reglas de enrutamiento personalizadas: del proceso de consulta anterior, podemos ver que ES sondeará todos los fragmentos para obtener los datos deseados. Si podemos controlar la ubicación de los fragmentos de datos, también podemos ahorrar muchos gastos generales. Por ejemplo: si tenemos una gran cantidad de escenarios en el futuro para verificar la dinámica de un determinado usuario, podemos controlar la fragmentación por usuario, lo que evita el sondeo de fragmentos y mejora la eficiencia de la búsqueda.
  3. palabra clave: no todos los números deben almacenarse como campos numéricos. Si sus valores numéricos rara vez se usan para consultas de rango, pero se usan a menudo para consultas de términos y son sensibles a la búsqueda rt. Entonces la palabra clave es el método de almacenamiento más adecuado.
  4. Preprocesamiento de datos: al igual que IndexSoting, si podemos preprocesar los datos al escribir, también puede ahorrar la sobrecarga de búsqueda. Esta combinación _ingest/pipeline puede tener efectos inesperados.

3. Escribe al final

Creo que todos los que han visto esto pueden ver que nuestra optimización no implica dificultades técnicas muy avanzadas, solo estamos en el proceso de resolución de problemas, y poco a poco cambiamos de principiante a principiante. Llegar a una gran vaca puede pasar directamente por alto nuestros desvíos desde el principio, pero un viaje de miles de millas comienza con un solo paso.Finalmente, aquí hay un resumen de experiencias y sentimientos para compartir con todos, con la esperanza de dar algunas referencias a los principiantes. como nosotros.

ES no funciona bien en escenarios en los que grandes conjuntos de resultados especifican la clasificación de campos, y debemos tratar de evitar tales escenarios al usarlo. Si no se puede evitar, la configuración adecuada de IndexSorting puede mejorar en gran medida el rendimiento de clasificación .

La optimización es interminable, debemos sopesar costos y beneficios y concentrar los recursos para resolver los problemas más prioritarios e importantes.

Texto: algas


Este artículo pertenece al original de la tecnología Dewu, fuente: sitio web oficial de la tecnología Dewu

¡Está estrictamente prohibido reimprimir sin el permiso de Dewu Technology, de lo contrario, se investigará la responsabilidad legal de acuerdo con la ley! Los derechos de autor pertenecen al autor. Para reimpresión comercial, comuníquese con el autor para obtener autorización, para reimpresión no comercial, indique la fuente.

{{o.nombre}}
{{m.nombre}}

Supongo que te gusta

Origin my.oschina.net/u/5783135/blog/8821399
Recomendado
Clasificación