Tres formas en las que mejoramos la escalabilidad de Elasticsearch
"Para conocer los límites, debes forzarlos".
Herbert A. Simon
En Elastic nos enfocamos en aportar valor a los usuarios a través de resultados rápidos que operan a escala y son relevantes: la velocidad, escala y relevancia son parte de nuestro ADN. En Elasticsearch 7.16, nos enfocamos en la escala y forzamos los límites de Elasticsearch para que la búsqueda sea incluso más rápida, la memoria sea menos demandante y los clústeres sean más estables. En el camino, descubrimos una variedad de dimensiones de sharding y, en el proceso, llevamos Elasticsearch a nuevos niveles.
Históricamente recomendamos evitar crear incontables shards en tu cluster debido a los gastos en recursos que implica. Sin embargo, con la nueva estrategia de indexación de flujos de datos en Fleet, se generarán cada vez más shards más pequeños a partir de casos de uso de seguridad y observabilidad; por eso es fundamental hallar formas nuevas de hacer frente a la creciente cantidad de shards. En este blog, veremos tres desafíos de escalado en Elasticsearch y cómo estamos mejorando la experiencia en la versión 7.16 y posteriores.
Optimizar la autorización
Imagínate entrando a un bar. Te piden tu identificación en la entrada y luego cada vez que pides una bebida, debes volver a mostrarla. Así era como la autorización realizaba las comprobaciones en versiones anteriores a la 7.16, en las que cada nodo (entrada) requería una comprobación de autorización y cada shard (pedido de bebida) también requería una comprobación de autorización. ¿Y si una sola comprobación de identificación en la entrada fuera suficiente para ambas cosas? Apliquemos esa misma idea a la autorización en Elasticsearch.
Elasticsearch permite a los usuarios configurar el control de acceso basado en roles/atributos para otorgar un permiso detallado por campo, por documento o por índice. Antes, authorize
se encontraba en muchas fases de una consulta de búsqueda para garantizar que las solicitudes no autorizadas no obtuvieran acceso injustificado a los datos. Sin embargo, la vigilancia de la funcionalidad de autorización tiene un costo, y una parte de la lógica no escala horizontalmente a medida que aumenta el tamaño del cluster. Por ejemplo, obtener capacidades de campo para todos los campos en todos los índices en un cluster grande podría requerir varios segundos o incluso minutos para completarse, además de dedicar casi todo el tiempo de ejecución a trabajos relacionados con la autorización.
La versión 7.16 aborda estos problemas desde dos perspectivas:
- Las mejoras algorítmicas a la autorización aceleran la autorización de solicitudes individuales, tanto al autorizar una solicitud de REST como al autorizar durante la comunicación en la capa de transporte (es decir, toda la red interna de nodo a nodo) entre los nodos dentro de un cluster de Elasticsearch.
- La autorización de solicitudes internas se hereda de las comprobaciones anteriores o se abarata significativamente en muchos casos. Antes de la versión 7.16, Elasticsearch ejecutaba la misma lógica de autorización por la que pasaba la solicitud externa inicial al autorizar las solicitudes de transporte internas dentro del cluster. Esto se hizo para evitar introducir una superficie de ataque en la comunicación de nodo a nodo interna que permitiría que un atacante diseñe solicitudes internas para omitir la lógica de autorización. Ahora resulta mucho más económico gracias a la omisión de la expansión con comodines en subsolicitudes, la omisión de la autorización para solicitudes locales del nodo (dentro del mismo nodo) y la reducción de la cantidad total de solicitudes necesarias para acciones como la búsqueda.
Reducir solicitudes de shard en la fase pre-filter
Se implementó una estrategia de búsqueda nueva en la versión 7.16 en las fases pre-filter
para reducir la cantidad de solicitudes a una vez por nodo que coincida. Antes de la versión 7.16, la primera fase de una búsqueda que intentara filtrar a partir de una búsqueda todos esos shards que se sabe que no contienen datos relevantes requería una solicitud por shard del nodo de coordinación a un nodo de datos. Hacer búsquedas en miles de shards al mismo tiempo implicaba enviar miles de solicitudes por solicitud de búsqueda desde el nodo de coordinación, manejar miles de respuestas en el nodo de coordinación y además gestionar todas estas solicitudes en los nodos de datos y responder a ellas. Escalar el cluster a más nodos de datos mejoraría el rendimiento del manejo de tantas solicitudes en los nodos de datos, pero no ayudaría con el rendimiento de esta operación en el nodo de coordinación.
A partir de la versión 7.16, la estrategia que ejecuta la fase pre-filter
se ajustó para enviar solo una solicitud por nodo en la fase, que abarca todos los shards en el nodo. Esto se puede ver en la Figura 1 a continuación. En un cluster con miles de shards en tres nodos de datos, la cantidad de solicitudes de red en la fase inicial de búsqueda pasaría de miles a tres o menos solicitudes, independientemente de la cantidad de shards en los que se busca. Como las solicitudes por shard enviadas antes de la versión 7.16 contenían en su mayoría los mismos datos en todos los shards, más precisamente la consulta de búsqueda, enviar solo una solicitud por nodo significa que esta información ya no se duplicará en varias solicitudes y, por lo tanto, se reducirá drásticamente la cantidad de bytes que se deben enviar a través de la red.
Se realizó una implementación similar para field_caps
, la cual utilizan las búsquedas *QL y Kibana. En teoría, las solicitudes de búsqueda guardadas en la solicitud de red se redujeron de O(shards)
a O(nodes)
por búsqueda; prácticamente, nuestro resultado de evaluación comparativa muestra que buscar en los logs de meses de datos en un gran cluster de logging pasa de minutos a menos de 10 segundos. Los ahorros que se obtienen de esto ayudan no solo con la cantidad de solicitudes de red, sino también a reducir el uso de memoria y CPU asociado con dichas solicitudes.
Reducir el consumo de memoria
Puede resultar sorprendente, pero las aerolíneas pueden ahorrar un peso importante con acciones como eliminar una sola aceituna de las ensaladas, usar cristalería más delgada e imprimir las revistas en tamaños más pequeños. Estamos adoptando un enfoque similar en Elasticsearch y reducimos el costo de memoria por campo. Si bien hablamos de solo unos pocos kilobytes por campo, cuando los multiplicamos por millones de campos de todos los índices en un cluster, podemos ahorrar una gran cantidad de memoria heap.
El uso de memoria heap en los nodos de datos de Elasticsearch depende de la cantidad de índices, campos por índice y shards almacenados en estado de cluster. Tener una gran cantidad de índices significa que la memoria heap se encuentra ocupada de forma constante independientemente de la carga en el nodo. En la versión 7.16, reestructuramos los generadores de campo de los campos de texto y número, lo cual derivó en una reducción del consumo de memoria y en una reducción de la memoria de más del 90 % solo para sostener estas estructuras de campo.
Ingestamos, buscamos, conquistamos
Desde el lanzamiento de la versión, podemos observar las mejoras en clústeres con cargas de trabajo realistas. Estos son algunos gráficos en los que se muestra el efecto de la actualización en este cluster de 60 nodos de datos.
En este cluster, podemos observar una carga de trabajo constante antes y después de la actualización; sin embargo, el percentil 99 de la latencia de búsqueda se redujo de manera uniforme, la velocidad de búsqueda (rendimiento) aumentó y el uso de memoria heap en los nodos congelados es consistentemente menor debido a la reducción del consumo de memoria para almacenar la estructura de datos. Se espera que esto tenga un impacto en todos los niveles de datos, si bien sería más prominente en el nivel congelado, en el que la memoria heap se usa principalmente para almacenar la estructura de datos, a diferencia de los nodos calientes en los que la memoria heap podría usarse para indexar, buscar y otras actividades. Si hacemos la división por roles de nodos, los nodos de coordinación tienen la reducción más notoria en los recuentos de GC joven gracias a la reducción de las solicitudes de shards en la fase pre-filter. Por último, debido a las mejoras en la gestión de estado de los clústeres, se redujo en gran medida la demanda de limitación de CPU en los nodos maestros.
Investigamos los motivos por los que Elasticsearch tenía problemas de rendimiento al escalar a decenas de miles de shards y nos enfocamos en mejoras de escalabilidad en Elasticsearch 7.16. Tener incontables shards y explosiones de mapping son factores principales que hacen fallar Elasticsearch, por lo cual deberían seguir evitándose; pero con las mejoras en la versión 7.16, se espera que su impacto sea mucho menor. En esta versión, las mejoras se enfocaron en el tamaño general del cluster, lo que permite que un tamaño de nodo maestro más pequeño maneje las actualizaciones de estado del cluster y optimiza la coordinación de búsqueda en una gran cantidad de índices.
Con toda la potencia de Elasticsearch en la versión 7.16, tu motor de búsqueda ahora es más rápido, la memoria es menos demandante y la estabilidad del cluster está fortalecida, todo lo que debes hacer es actualizar. Seguimos mejorando varios aspectos en cuanto a la escalabilidad y compartiremos más logros que se incluirán en la versión 8.x.
¿Estás listo para escalar más?
Los clientes existentes de Elastic Cloud pueden acceder a muchas de estas características directamente desde la consola de Elastic Cloud. Si eres nuevo en Elastic Cloud, echa un vistazo a nuestras guías de inicio rápido (videos de capacitación breves para que puedas dar los primeros pasos rápido) o nuestros cursos de capacitación gratuitos sobre conceptos básicos. Siempre puedes comenzar sin costo con una prueba gratuita de 14 días de Elastic Cloud. O descarga la versión autogestionada del Elastic Stack de forma gratuita.
Lee sobre estas capacidades y más en las notas de lanzamiento de Elastic 7.16, y otros aspectos destacados del Elastic Stack en el blog de anuncio de Elastic 7.16.