ElasticSearch Snapshot – Indexes

Negli ultimi giorni ho affrontato un interessante problematica legata alla creazione degli snapshot degli indici presenti su di un cluster nel quale gira ElasticSearch.
Ho sviluppato la funzionalità in PHP su di un task legata ad una Laravel APP application. Questo tutorial parte dal presupposto di aver già configurato in precedenza gli indici sul cluster. Pertanto partiamo 🙂
Presupponiamo di disporre di una piattaforma su cui gira ElasticSearch già configurata presso un nostro endpoint .
ElasticSearch è scritto in Jva e sotto il suo cofano nasconde Lucene ed espone presso l’endpoint cui è configurato delle API, tra queste possiamo scorgere la “PUT _snapshot//.
Questa chiamata si occupa come è facile immaginare di creare uno snapshot legato ai nostri indici, gli indici presenti sul nostro repository possono essere visualizzati utilizzando la cURL:

curl -X GET '<CLUSTER_ENDPOINT>/_cat/indices?v'

ElasticSearch Pool

Pooling creazione snapshot ElasticSeach


Okay, bene quindi voi direte facile implementazione chiamo la cURL in PUT ed il gioco è fatto, ma avete pensato a delle problematiche importanti come la concorrenza, oppure la necessità di dover gestire snapshots su degli shards o ancora backup a cadenza temporale prefissata, schedulati con dei cron?
Voi dirti no, ma nessun problema tranquillo, perchè le API di ElasticSearch espongono il parametro wait_for_completion=true, che rende la creazione degli snapshot sincrona in maniera che non mi devo preoccupare della concorrenza 🙂 Beh, a mio modesto parere, posso anche sbagliarmi ma state ma stiamo ignorando una problematica fondamentale, perché gli indici potrebbero occupare molto spazio della dimensione di svariati GByte oppure addirittura TByte e fare uno snapshot può impiegare anche alcune ore e noi per qualsì voglia motivo vogliamo vedere lo stato di avanzamento dell’operazione oppure vogliamo come detto prima rilanciare lo script di creazione dello snapshot a seguito di una determinata operazione, ecc.. perciò il nostro codice se utilizzasse la wait_for_completation diventa non performante 🙂 Va beh, direte sei bravo a trovare un problema in tutto lasciamo perdere 🙂 In parte sì, ma ripensandoci perché dobbiamo utilizzare la wait_for_completation? O meglio se lanciassimo il processo in background? Bingo 🙂
Se lanciamo il processo in background possiamo gestire noi stessi il pooling sullo stato di avanzamento dell’operazione di creazione dello snapshot 🙂
Tra le API esposte da ElasticSearch, vi è una GET, ma ve ne sono anche altre simili a questa che ci permettono di monitorare lo stato di avanzamento:

curl -X GET "<CLUSTER_ENDPOINT>/_snapshot/<REPOSITOY>/<SNAPSHOT_ID>?pretty"

Questa come da tabella di seguito ci permette di monitorare lo stato di avanzamento della creazione dello snapshot grazie al parametro JSON state.

Snapshot Status

Monitoraggio status della creazione dello snapshot ElasticSearch


Apposto gioco fatto, inserisco un breve snippet legato alla funzionalità di pooling sullo stato di creazione dello snapshot, lascio però a voi il compito di migliorarlo ed adattarlo alla vostre applicazioni 😉 Ah, consiglio non dimenticavi di fare il pooling dopo la cURL in PUT 😉

  	/**
	 * This is an recursive function that retrieve snapshot status.
	 * If it occur error it throw exception over previous stack, if approve snapshot creation return and continue previous execution.
	 * @param $endpoint, endpoint API for retrieve snapshot status.
	 * @param int $bidId, this method start with $bid=0, after it is increment if snapshot creation it is in PROGRESS mode.
	 * @throws Exception, if method it isn't in success or progress status.
	 */
	private function getSnapshotStatus($endpoint, $bidId = 0){
		/* This message on previous stack launch exception derived from many times call API. */
		if($bidId >= <strong><NUMERO_MASSIMO_DI_VOLTE_IN_CUI_EFFETTUARE_LA_RICORSIONE></strong>) 
                        throw new RuntimeException("We have try call status API for ".$bidId." bid times and we haven't obtain expected result.");
 
                // Obtain response in json format.
		$response 	= json_decode($this->callServer("GET", $endpoint),true);                         <strong>// TO-DO: implement cURL call.</strong> 
		if(gettype($data) != "array")
			throw new RuntimeException("Pay attention: pooling call it is error mode because it haven't return json data.");
 
		$state = array_get($data, "snapshots.0.state");
		if(is_null($state))
			throw new RuntimeException("An expected error occured on retrieve pretty status of snapshot.");
 
		/**
		 * We can view snapshot status follow this link:
		 * https://opendistro.github.io/for-elasticsearch-docs/docs/elasticsearch/snapshot-restore/
		 * In addition, PARTIAL status only occur if you set partial to true when taking the snapshot. We no use this parameter.
		 * -> INCOMPATIBLE, 	it is very mistake situation!
		 * -> FAILED,			the snapshot encountered an error and stored no data.
		 * -> SUCCESS,			snapshot creation it is finish in success mode.
		 * -> PROGRESS,			snapshot creation it is in progress.
		 */
		if($state == "INCOMPATIBLE")
			throw new RuntimeException("Pay attention: the snapshot configuration it is incompatible with the version of Elasticsearch running on this cluster.");
		elseif($state == "FAILED")
			throw new RuntimeException("The snapshot encountered an error and stored no data.");
		if($state == "SUCCESS"){
			//Log::info('ElasticSearch snapshot creation it is in success mode infact it have stored all shards');
			return;
		}elseif($state == "IN_PROGRESS"){
			// Recursive situation it have when return PROGRESS status.
			$bidId += 1;
			/* Before we activate recursive algorithm we attempt 2 minutes. */
			sleep(120);
			return $this->getSnapshotStatus($endpoint, $bidId);
		}else{
			throw new RuntimeException("The snapshot encountered unexpected error and it is ".$state." status.");
		}
	}
ElasticSearch Snapshot – Indexes ultima modidfica: 2020-08-27T14:07:03+02:00 da Gianluca Di Vincenzo