Carga resiliente de datos en elasticsearch usando alias

0
1849

En este tutorial veremos cómo usar los alias de elasticsearch para poder hacer cargas de datos periódicas o sustituir los datos de un índice, teniendo tolerancia a fallos y sin perder la alta disponibilidad.

Es probable que tengamos un cluster de elasticsearch con índices que recarguemos periódicamente, por ejemplo, cada día o cada semana, con datos de otros sistemas y/o los suyos propios.

Pero, ¿cómo hacemos para refrescar un índice con nuevos datos en un proceso que puede ser largo y sin perder la disponibilidad del servicio?, lo veremos en este tutorial.

Índice de contenidos


1. Entorno

El tutorial está escrito usando el siguiente entorno:

  • Hardware: Portátil MacBook Pro 15′ (2.5 GHz Intel Core i7, 16GB DDR3)
  • Sistema Operativo: Mac OS Sierra 10.12.5
  • Docker 17.09.1-ce
  • Postman 5.5.0


2. Instalación

Para este tutorial, he elegido hacer un ejemplo con un índice de deportes. Todas las peticiones http las haremos con Postman y usaremos la versión 6.1.1 de elasticsearch.

A partir de docker lanzaremos el elasticsearch con el siguiente comando.

docker run -d -p 9200:9200 -p 9300:9300 --name elastic-6.1.1 docker.elastic.co/elasticsearch/elasticsearch:6.1.1

De esta manera ya tendremos corriendo un cluster de elasticsearch.


3. Creación del primer índice y asignación de alias

En primer lugar crearemos un índice al que le añadiremos la fecha para poder identificarlo y usarlo en caso de que haya algún error o que queramos volver a esta versión.

PUT http://localhost:9200/deportes_2018_01_03_11_06_38/

Rellenamos este índice con datos.

POST http://localhost:9200/deportes_2018_01_03_11_06_38/deporte/_bulk
Header: Content-Type:application/x-ndjson
Body:
{"create":{"_id":1}}
{"nombre":"CrossFit"}
{"create":{"_id":2}}
{"nombre":"MTB"}
{"create":{"_id":3}}
{"nombre":"Fútbol"}
{"create":{"_id":4}}
{"nombre":"Pádel"}
{"create":{"_id":5}}
{"nombre":"Surf"}
{"create":{"_id":6}}
{"nombre":"Esquí"}

Cuando el índice ya esté creado con sus datos disponibles y listo para poder hacer consultas, le asignaremos un alias, en mi ejemplo elegiré “deportes_des”.

GET http://localhost:9200/deportes_2018_01_03_11_06_38/_alias/deportes_des

De esta manera, ya podremos hacer todas las consultas sobre este índice como si tuviera el nombre “deportes_des”. Lanzamos la siguiente consulta para comprobarlo.

GET http://localhost:9200/deportes_des/_search

Esta consulta debería devolver un resultado parecido al siguiente:

{
	"took": 3,
	"timed_out": false,
	"_shards": {
		"total": 5,
		"successful": 5,
		"skipped": 0,
		"failed": 0
	},
	"hits": {
		"total": 6,
		"max_score": 1,
		"hits": [
			{
				"_index": "deportes_2018_01_03_11_06_38",
				"_type": "deporte",
				"_id": "5",
				"_score": 1,
				"_source": {
					"nombre": "Surf"
				}
			},
			{
				"_index": "deportes_2018_01_03_11_06_38",
				"_type": "deporte",
				"_id": "2",
				"_score": 1,
				"_source": {
					"nombre": "MTB"
				}
			},
			{
				"_index": "deportes_2018_01_03_11_06_38",
				"_type": "deporte",
				"_id": "4",
				"_score": 1,
				"_source": {
					"nombre": "Pádel"
				}
			},
			{
				"_index": "deportes_2018_01_03_11_06_38",
				"_type": "deporte",
				"_id": "6",
				"_score": 1,
				"_source": {
					"nombre": "Esquí"
				}
			},
			{
				"_index": "deportes_2018_01_03_11_06_38",
				"_type": "deporte",
				"_id": "1",
				"_score": 1,
				"_source": {
					"nombre": "CrossFit"
				}
			},
			{
				"_index": "deportes_2018_01_03_11_06_38",
				"_type": "deporte",
				"_id": "3",
				"_score": 1,
				"_source": {
					"nombre": "Fútbol"
				}
			}
		]
	}
}

Como hemos comprobado podemos hacer las consultas sobre el alias en vez de sobre el índice.

Una vez que ya tenemos el índice creado y con su alias configurado, puede llegar el momento en el que queremos recargar este índice con nuevos datos pero sin perder el servicio mientras insertamos, cambiamos o eliminamos dichos datos. Como ya podemos suponer a estas alturas, lo que haremos, será crear un nuevo índice y cuando el nuevo índice esté completamente cargado, cambiaremos el alias para que las nuevas consultas sobre “deportes_des” se hagan sobre el nuevo índice. El índice antiguo podemos eliminarlo o guardarlo por si necesitamos volver a la versión anterior.


4. Recarga del alias

Empezaremos creando un nuevo índice.

PUT http://localhost:9200/deportes_2018_01_03_12_11_19/

Rellenamos el nuevo índice con datos diferentes, estos datos pueden salir del antiguo índice o de cualquier otra fuente.

POST http://localhost:9200/deportes_2018_01_03_12_11_19/deporte/_bulk
Header: Content-Type:application/x-ndjson
Body:
{"create":{"_id":1}}
{"nombre":"CrossFit"}
{"create":{"_id":2}}
{"nombre":"Tenis"}
{"create":{"_id":3}}
{"nombre":"MTB"}
{"create":{"_id":6}}
{"nombre":"Patinaje"}
{"create":{"_id":8}}
{"nombre":"Frontón"}
	

En este momento, ya tenemos el nuevo índice (deportes_2018_01_03_12_11_19) preparado para poder sustituir al anterior (deportes_2018_01_03_11_06_38).

Comprobamos qué índices tienen el alias “deportes_des”.

GET http://localhost:9200/_alias/deportes_des

La consulta nos devuelve el siguiente resultado que podemos usar para saber el índice del que debemos eliminar el alias.

{
	"deportes_2018_01_03_11_06_38": {
		"aliases": {
			"deportes_des": {}
		}
	}
}

Eliminamos el alias del índice anterior.

DEL http://localhost:9200/deportes_2018_01_03_12_06_38/_alias/deportes_des

Y creamos el nuevo alias.

PUT http://localhost:9200/deportes_2018_01_03_12_11_19/_alias/deportes_des

Si en este momento volvemos a lanzar la consulta de todos los datos sobre “deportes_des”.

GET http://localhost:9200/deportes_des/_search

Nos devolverá solo los datos del nuevo índice:

{
	"took": 2,
	"timed_out": false,
	"_shards": {
		"total": 5,
		"successful": 5,
		"skipped": 0,
		"failed": 0
	},
	"hits": {
		"total": 5,
		"max_score": 1,
		"hits": [
			{
				"_index": "deportes_2018_01_03_12_11_19",
				"_type": "deporte",
				"_id": "8",
				"_score": 1,
				"_source": {
					"nombre": "Frontón"
				}
			},
			{
				"_index": "deportes_2018_01_03_12_11_19",
				"_type": "deporte",
				"_id": "2",
				"_score": 1,
				"_source": {
					"nombre": "Tenis"
				}
			},
			{
				"_index": "deportes_2018_01_03_12_11_19",
				"_type": "deporte",
				"_id": "6",
				"_score": 1,
				"_source": {
					"nombre": "Patinaje"
				}
			},
			{
				"_index": "deportes_2018_01_03_12_11_19",
				"_type": "deporte",
				"_id": "1",
				"_score": 1,
				"_source": {
					"nombre": "CrossFit"
				}
			},
			{
				"_index": "deportes_2018_01_03_12_11_19",
				"_type": "deporte",
				"_id": "3",
				"_score": 1,
				"_source": {
					"nombre": "MTB"
				}
			}
		]
	}
}


5. Conclusiones

Hemos visto un ejemplo de cómo podemos recargar un índice simplemente creando uno nuevo y usando alias. Esto es extensible a varios índices y podemos ver en la documentación de elastic.co como eliminar y añadir alias a varios índices en la misma consulta. En la documentación, también podemos ver cómo los alias pueden tener filtros y usarse en varios índices a la vez, pero este no era nuestro caso de uso.

En nuestro caso de uso, si hay un fallo en la carga de datos del nuevo índice, esto no afecta al servicio ya que simplemente no le pondremos el alias al nuevo índice en el que hemos tenido el fallo de carga. Además, si la carga funciona correctamente, podemos quedarnos con el antiguo índice por si queremos volver a la versión anterior.

Como se indica en la introducción, este método se puede usar tanto para hacer cargas periódicas en elasticsearch como para sustituir índices puntualmente.

Os dejo un enlace a todas las peticiones usadas para importar en Postman.

Tutorial_elastic_alias.postman.json


6. Referencias

Un saludo.

Carlos.

DEJA UNA RESPUESTA

Por favor ingrese su comentario!

He leído y acepto la política de privacidad

Por favor ingrese su nombre aquí

Información básica acerca de la protección de datos

  • Responsable:
  • Finalidad:
  • Legitimación:
  • Destinatarios:
  • Derechos:
  • Más información: Puedes ampliar información acerca de la protección de datos en el siguiente enlace:política de privacidad