Decrypt Elasticsearch: exploración en profundidad de este motor de búsqueda y análisis | Equipo técnico de JD Cloud

Autor: JD Seguros Guan Shunli

apertura

Recientemente, se utilizó Elasticsearch para implementar el sistema de retratos y se realizó la capacidad de la plataforma intermedia de datos de dmp. Al mismo tiempo, se investigó la selección de la arquitectura de los productos de la competencia. Y revisé el principio de redis, etc. Por la presente hago un resumen y reseña de es. No he visto a nadie usando Elasticsearch para completar el retrato en Internet. Voy a probarlo por primera vez.

Después de los antecedentes, pensemos primero en una cosa, usar el sistema de memoria como base de datos. ¿Cuáles son sus puntos fuertes? ¿Cuáles son sus puntos de dolor?

1. Principio

Esta no es la imagen completa. Solo habla de comunicación, memoria y persistencia.

comunicación

La unidad más pequeña de un clúster es son tres nodos. La combinación de dos nodos esclavos para garantizar su alta disponibilidad también es la base del agrupamiento. Entonces, ¿qué se usa para la comunicación RPC entre nodos? Debe ser netty, es realiza el paquete de comunicación de Netty4Transport basado en netty. Cree Bootstrap después de inicializar Transport y complete la recepción y el reenvío a través de MessageChannelHandler. En es se distingue servidor y cliente, como se muestra en la Figura 1. El json utilizado para la serialización. ES tiende a ser fácil de usar, de propósito general y fácil de entender en el diseño de rpc. En lugar de simplemente perseguir el rendimiento.

Figura 1

Con la escolta de netty, se garantiza que es utilizará la serialización json.

Memoria

Figura 2

La memoria es se divide en dos partes [on heap] y [off heap]. La parte en el montón es administrada por el jvm de es. off heap es administrado por lucene. El almacenamiento dinámico se divide en dos partes, una parte se puede reciclar y la otra parte no se puede reciclar.

Parte del búfer de índice que se puede reciclar almacena nuevos documentos de índice. Cuando se llena, los documentos del búfer se escriben en el segmento del disco. Todos los fragmentos se comparten en el nodo.

No se pueden reciclar la caché de consultas de nodos, la caché de solicitudes de fragmentos, la caché de datos de archivos, la caché de segmentos

La memoria caché de consulta de nodo es una memoria caché a nivel de nodo, filtrada y almacenada en cada nodo, compartida por todos los fragmentos, utilizando la estructura de datos de conjunto de bits (versión optimizada de Bloom) para desactivar la puntuación. La estrategia de eliminación de LRU a utilizar. GC no puede reciclar.

La memoria caché de solicitud de fragmentos es una memoria caché a nivel de fragmentos, y cada fragmento lo tiene. De forma predeterminada, la memoria caché solo almacena consultas cuyo tamaño de resultado de solicitud es igual a 0. Por lo tanto, el caché no será hits, sino hits.total, agregaciones, sugerencias se almacenarán en caché. Se puede borrar a través de la API de borrado de caché. La estrategia de eliminación de LRU a utilizar. GC no puede reciclar.

El caché de datos del archivo es para almacenar en caché los datos agregados y ordenados. En los primeros días, es no tenía valores doc, por lo que después de la agregación y clasificación, se necesitaba un archivo de datos para el almacenamiento en caché para evitar la E/S del disco. Si no hay suficiente memoria para almacenar datos de archivos, es cargará continuamente datos del disco a la memoria y eliminará los datos antiguos. Estos provocan E/S de disco y activan GC. Por lo tanto, las versiones posteriores a la 2.x introducen la función de valores de documentos, crean documentos en tiempo de índice, los almacenan en el disco y acceden a ellos a través de archivos asignados a la memoria. Incluso si solo le importa hits.total, solo devuelva la identificación del documento y desactive los valores del documento. Los valores de doc admiten tipos numéricos y de palabras clave. El tipo de texto aún creará datos de archivo.

La memoria caché de segmentos se utiliza para acelerar las consultas y la FST reside en la memoria del montón para siempre. FST puede entenderse como un árbol de prefijos para acelerar las consultas. ¡pero! ! La versión es 7.3 comenzó a entregar la FST a la memoria fuera del montón, lo que permite que el nodo admita más datos. FST también tiene un archivo persistente correspondiente en el disco.

Fuera del montón es la memoria de segmentos, y Lucene utiliza la memoria fuera del montón. Por lo que se recomienda dejar al menos la mitad de la memoria para lucene.

La versión es 7.3 comienza a cargar la sugerencia (índice de términos) a través de mmp y la transfiere a la caché de páginas del sistema para su administración. Excepto tip, los archivos nvd (normas), dvd (valores doc), tim (diccionario de términos) y cfs (compuesto) se cargan y transfieren mediante mmp, y el resto son todos nio. El efecto de tip off heap es que el uso de jvm se reduce en aproximadamente un 78 %. Puede usar la API _cat/segments para ver el uso de memoria de segments.memory.

Porque la memoria externa es administrada por el pagecache del sistema operativo. Si se produce el reciclaje, la consulta FST implicará E/S de disco, lo que tendrá un gran impacto en la eficiencia de la consulta. Puede consultar la estrategia de reciclaje de linux pagecache para usar la estrategia de doble cadena.

Persistencia

La persistencia de es se divide en dos partes, una parte es similar a una instantánea y los segmentos en el caché de archivos se actualizan (fsync) en el disco. La otra parte es el registro translog, que agrega el registro de operaciones cada segundo y lo descarga en el disco cada 30 minutos de forma predeterminada. La persistencia es muy similar al modo RDB+AOF de redis. Como se muestra abajo

imagen 3

La figura de arriba es un proceso de escritura completo. El disco también registra datos en segmentos. Es muy similar a redis aquí. Pero el mecanismo interno no utiliza COW (copy-on-write). Esta es también la razón por la que la carga está llena al consultar y escribir en paralelo.

resumen

El diseño de la memoria y el disco es muy inteligente. El método mmap se usa en copia cero y los datos del disco se asignan fuera del montón, es decir, lucene. Para acelerar el acceso a los datos, cada segmento de es tiene algunos datos de índice que residen en el almacenamiento dinámico externo; por lo tanto, cuantos más segmentos haya, más almacenamiento dinámico externo se dividirá, lo que no puede ser reciclado por GC.

Combinando los dos puntos anteriores, podemos saber claramente por qué es consume tanta memoria.

2. Aplicación

Las siguientes dificultades deben resolverse en el sistema de retrato de usuario.

1. Estimación de multitudes: seleccione un grupo de personas en función de las etiquetas, como hombres de 20 a 25 años a quienes les gustan las redes sociales de comercio electrónico. 20-25 años ∩ comercio electrónico redes sociales ∩ hombre. Selecciona el número de clientIds que cumplen las características mediante operaciones AND o NOT. Este es un grupo.

Antes de nuestro grupo y grupo, también podemos hacer operaciones de intersección y diferencia. Por ejemplo, es un hombre de 20 a 25 años al que le gusta el comercio electrónico y la socialización, y un hombre en Beijing al que le gusta jugar al hierro. (20-25 años ∩ comercio electrónico redes sociales ∩ hombres) ∩ (20-25 años ∩ hierro ∩ hombres). Para tal recurrencia, se requiere devolver el número estimado de personas en segundos en la biblioteca de más de 1.700 millones de retratos.

2. Selección del círculo del paquete de multitud: el paquete de multitud seleccionado por el círculo anterior. Se requieren compilaciones de minutos.

3. Juicio del paquete de personas: juzgue si existe un ID de cliente en varios paquetes de multitudes. Requiere 10 milisegundos para devolver el resultado.

Primero tratamos de usar es para resolver todos los problemas anteriores.

Para la estimación de multitudes, la solución más fácil que se puede pensar es realizar operaciones lógicas en la memoria del servidor. Sin embargo, es muy costoso hacerlo en el lado del servidor si selecciona decenas de millones de personas y las devuelve en segundos. En este momento, puede lanzar la presión informática al lado del almacenamiento es, al igual que consultar una base de datos. Use una declaración para encontrar los datos que queremos.

por ejemplo mysql

select a.age from a where a.tel in (select b.age from b);

El dsl correspondiente de es es similar a

{"query":{"bool":{"must":[{"bool":{"must":[{"term":{"a9aa8uk0":{"value":"age18-24","boost":1.0}}},{"term":{"a9ajq480":{"value":"male","boost":1.0}}}],"adjust_pure_negative":true,"boost":1.0}},{"bool":{"adjust_pure_negative":true,"boost":1.0}}],"adjust_pure_negative":true,"boost":1.0}}}

De esta forma, el alto rendimiento de recuperación de es se utiliza para satisfacer las necesidades comerciales. Independientemente del número de grupos y cuántas etiquetas en el grupo. Todo escrito en una declaración dsl. Para garantizar que los resultados se devuelvan en segundos.

Usando el RestHighLevelClient recomendado oficialmente, hay tres métodos de implementación, uno es deletrear la cadena json y el segundo es llamar a la API para deletrear la cadena. Yo uso la tercera vía BoolQueryBuilder para lograr, más elegante. Proporciona métodos filter, must, should y mustnot. como

     /**
     * Adds a query that <b>must not</b> appear in the matching documents.
     * No {@code null} value allowed.
     */
    public BoolQueryBuilder mustNot(QueryBuilder queryBuilder) {
        if (queryBuilder == null) {
            throw new IllegalArgumentException("inner bool query clause cannot be null");
        }
        mustNotClauses.add(queryBuilder);
        return this;
    }

    /**
     * Gets the queries that <b>must not</b> appear in the matching documents.
     */
    public List<QueryBuilder> mustNot() {
        return this.mustNotClauses;
    }

El uso de la API puede mostrar en gran medida la capacidad de compilar código.

Construye el paquete de multitud. En la actualidad, el paquete más grande que hemos marcado tiene más de 70 millones de ID de clientes. Si desea completar la construcción en el nivel de minutos (70 millones de datos se completan en 35 minutos por debajo del límite condicional), debe prestar atención a dos puntos, uno es una consulta en profundidad y el otro es escritura por lotes.

Hay tres formas de paginación es, y hay dos tipos de paginación profunda, y los dos últimos se recuperan desplazándose con el cursor (scroll y search_after).

El desplazamiento debe mantener el estado del cursor, y cada subproceso creará una identificación de desplazamiento única de 32 bits, y cada consulta debe traer una identificación de desplazamiento única. Si varios subprocesos tienen que mantener varios estados de cursor. search_after es similar a scroll. Pero sus parámetros no tienen estado y siempre se analizarán con las versiones más nuevas del buscador. Su orden de clasificación cambia en el desplazamiento. El principio del desplazamiento es mantener el conjunto de resultados de ID de documento en el contexto del nodo de coordinación y obtenerlo en lotes cada vez que se desplaza. Solo necesita recuperar los resultados en orden dentro de cada fragmento según el tamaño.

Al escribir, use el grupo de subprocesos para hacerlo, preste atención al tamaño de la cola de bloqueo utilizada y elija una estrategia de rechazo adecuada (aquí no se requiere la estrategia de lanzar excepciones). Si el lote aún se escribe en es (por ejemplo, se realiza la separación de lectura y escritura), además de subprocesos múltiples, también existe una política de actualización para optimizar la escritura.

Dado que todo el enlace comercial es muy largo para la interfaz de determinación de paquetes humanos, el tiempo de fusión establecido por el servicio ascendente para esta recuperación es de 10 ms. Por lo tanto, la consulta para optimizar es (o redis) no es responsable del procesamiento lógico después de todo. Después de usar el grupo de subprocesos para resolver la optimización intensiva de IO, puede alcanzar 1 ms. tp99 alcanza su punto máximo a los 4 ms.

3. Optimización, cuellos de botella y soluciones

Lo anterior es el método de resolución de problemas que utiliza es para las necesidades comerciales. También se requiere la optimización de la respuesta. Al mismo tiempo, también encontré el cuello de botella de es.

1. El primero es la optimización del mapeo. El tipo en los campos en el mapeo de imágenes es palabra clave, y el índice debe estar desactivado. El valor doc en los campos del paquete humano está desactivado. El retrato es para la coincidencia exacta; el juicio del paquete humano solo necesita el resultado pero no el valor. El cálculo del paquete humano en la API es usa un filtro para eliminar la puntuación, y la estructura de datos Bloom del conjunto de bits se usa dentro del filtro, pero los datos deben precalentarse. Al escribir, no es fácil tener demasiados subprocesos, solo sea igual a la cantidad de núcleos; ajuste el nivel de política de actualización. Actualización manual del disco, index.refresh_interval se ajusta a -1 durante la construcción. Cabe señalar que detener la actualización del disco aumentará la memoria del montón, y la frecuencia de la actualización del disco debe ajustarse de acuerdo con el negocio. Para crear un paquete de multitud grande, puede dividir el índice en varios. El almacenamiento descentralizado puede mejorar la capacidad de respuesta. En la actualidad, todavía se pueden admitir docenas de paquetes de multitud. Si crece a varios cientos en el futuro. Debe usar un mapa de bits para crear y almacenar paquetes de multitud. es es excelente para el rendimiento de recuperación. Pero no es en lo que es bueno cuando se encuentra con operaciones de escritura y operaciones de consulta en paralelo. Por ejemplo, los datos del paquete de multitud cambian todos los días. En este momento, la memoria y el disco io de es serán muy altos. Podemos usar redis para almacenar cientos de paquetes. También puede optar por usar MongoDB para almacenar datos de paquetes.

Cuatro Resumen

Lo anterior es que usamos Elasticsearch para resolver dificultades comerciales. Al mismo tiempo, se constató que su persistencia no utilizaba el método COW (copy-on-write). Como resultado, el rendimiento de recuperación se degrada durante la escritura en tiempo real.

Usar un sistema en memoria como fuente de datos es un poco obvio, ¡solo recuperar bloques! Especialmente en escenarios en tiempo real, puede llamarse un arma afilada. Al mismo tiempo, el punto de dolor también es obvio: la escritura en tiempo real reducirá el rendimiento de recuperación. Por supuesto, podemos hacer separación de lectura y escritura, índice dividido y otras soluciones.

Además de Elasticsearch, también podemos elegir ClickHouse, y ck también admite la estructura de datos de mapa de bits. Incluso puedes ir a Pilosa, que es BitMap Database.

referencia

Práctica de construcción de la plataforma Keike DMP

Parámetros de mapeo | Referencia de Elasticsearch [7.10] | Elástico

El principio offheap de Elasticsearch 7.3

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

Supongo que te gusta

Origin my.oschina.net/u/4090830/blog/8704613
Recomendado
Clasificación