Ce guide explique comment migrer les données d'un cluster Elasticsearch auto-géré (hébergé sur ECS) vers une instance Alibaba Cloud Elasticsearch en utilisant l'API Reindex. L'API Reindex permet au cluster de destination d'« extraire » les données depuis un cluster source distant.
Contexte et guide de sélection
L'API Reindex est idéale pour migrer des index spécifiques ou des volumes de données faibles à moyens. Selon l'architecture de votre instance et la taille de vos données, choisissez l'outil approprié :
|
Volume de données / Besoin |
Méthode recommandée |
|
Volume faible à moyen |
API Reindex (ce guide) |
|
Volume important (> 100 Go) |
|
|
Filtrage ou transformation des données |
Migration des données Elasticsearch auto-gérées à l'aide d'Alibaba Cloud Logstash |
Prérequis
-
Connectivité réseau :
L'instance ECS (Elasticsearch auto-géré) et le cluster Alibaba Cloud Elasticsearch doivent se trouver dans le même Virtual Private Cloud (VPC).
Groupe de sécurité : Le groupe de sécurité de l'ECS doit autoriser le trafic entrant sur le port 9200 depuis les adresses IP des nœuds Alibaba Cloud Elasticsearch (disponibles dans la console Kibana).
-
Vérification de l'architecture du cluster : Vérifiez l'architecture de votre cluster Alibaba Cloud Elasticsearch dans la section Basic Information > Control Architecture Type :
Basic Control Architecture (v2) : Déployé dans votre VPC. L'accès est direct. Suivez la procédure décrite dans ce guide.
Cloud-native Control Architecture (v3) : Déployé dans un VPC de service. Vous devez utiliser PrivateLink pour établir la connexion réseau. Consultez la rubrique Migration des données Elasticsearch auto-gérées via une connexion privée.
Stabilité : Arrêtez l'écriture de données dans le cluster source pendant la migration afin de garantir une cohérence totale des données.
Notes d'utilisation
Les instances créées avant octobre 2020 (architecture v2) ne peuvent pas effectuer directement de réindexation inter-clusters avec des instances créées après octobre 2020 (architecture v3) sans utiliser de proxy ou PrivateLink. Si elles reposent sur des architectures différentes, utilisez Logstash comme intermédiaire.
Lorsque vous utilisez un nom de domaine pour accéder à un cluster Elasticsearch auto-géré ou Alibaba Cloud Elasticsearch, vous ne pouvez pas utiliser une URL incluant un path, telle que
http://host:port/path.
Procédure
Étape 1 : Établir la connectivité réseau (uniquement pour l'architecture v3)
Si votre cluster Alibaba Cloud Elasticsearch utilise l'architecture de contrôle cloud-native (v3), vous devez créer une connexion privée à l'aide de PrivateLink. Pour plus d'informations, consultez la rubrique Configuration d'une connexion PrivateLink.
Étape 2 : Créer un index de destination
Créez l'index dans le cluster Alibaba Cloud Elasticsearch de destination avec les mêmes mappages et paramètres que ceux de la source.
Script par lot (Python 2.7) : Utilisez ce script pour répliquer les structures d'index (mappages/shards) de l'ancien cluster vers le nouveau.
Dans cet exemple, le nombre de réplicas est défini sur 0 pour accélérer la migration.
#!/usr/bin/python
# -*- coding: UTF-8 -*-
# File name: indiceCreate.py
import sys
import base64
import time
import httplib
import json
## The host of the self-managed Elasticsearch cluster.
oldClusterHost = "old-cluster.com"
## The username for the self-managed Elasticsearch cluster. This can be empty.
oldClusterUserName = "old-username"
## The password for the self-managed Elasticsearch cluster. This can be empty.
oldClusterPassword = "old-password"
## The host of the Alibaba Cloud Elasticsearch cluster. You can obtain it from the Basic Information page of the Alibaba Cloud Elasticsearch instance.
newClusterHost = "new-cluster.com"
## The username for the Alibaba Cloud Elasticsearch cluster.
newClusterUser = "elastic"
## The password for the Alibaba Cloud Elasticsearch cluster.
newClusterPassword = "new-password"
DEFAULT_REPLICAS = 0
def httpRequest(method, host, endpoint, params="", username="", password=""):
conn = httplib.HTTPConnection(host)
headers = {}
if (username != "") :
'Hello {name}, your age is {age} !'.format(name = 'Tom', age = '20')
base64string = base64.encodestring('{username}:{password}'.format(username = username, password = password)).replace('\n', '')
headers["Authorization"] = "Basic %s" % base64string;
if "GET" == method:
headers["Content-Type"] = "application/x-www-form-urlencoded"
conn.request(method=method, url=endpoint, headers=headers)
else :
headers["Content-Type"] = "application/json"
conn.request(method=method, url=endpoint, body=params, headers=headers)
response = conn.getresponse()
res = response.read()
return res
def httpGet(host, endpoint, username="", password=""):
return httpRequest("GET", host, endpoint, "", username, password)
def httpPost(host, endpoint, params, username="", password=""):
return httpRequest("POST", host, endpoint, params, username, password)
def httpPut(host, endpoint, params, username="", password=""):
return httpRequest("PUT", host, endpoint, params, username, password)
def getIndices(host, username="", password=""):
endpoint = "/_cat/indices"
indicesResult = httpGet(oldClusterHost, endpoint, oldClusterUserName, oldClusterPassword)
indicesList = indicesResult.split("\n")
indexList = []
for indices in indicesList:
if (indices.find("open") > 0):
indexList.append(indices.split()[2])
return indexList
def getSettings(index, host, username="", password=""):
endpoint = "/" + index + "/_settings"
indexSettings = httpGet(host, endpoint, username, password)
print index + " The original settings are as follows:\n" + indexSettings
settingsDict = json.loads(indexSettings)
## By default, the number of shards is the same as that of the index in the self-managed Elasticsearch cluster.
number_of_shards = settingsDict[index]["settings"]["index"]["number_of_shards"]
## By default, the number of replicas is 0.
number_of_replicas = DEFAULT_REPLICAS
newSetting = "\"settings\": {\"number_of_shards\": %s, \"number_of_replicas\": %s}" % (number_of_shards, number_of_replicas)
return newSetting
def getMapping(index, host, username="", password=""):
endpoint = "/" + index + "/_mapping"
indexMapping = httpGet(host, endpoint, username, password)
print index + " The original mapping is as follows:\n" + indexMapping
mappingDict = json.loads(indexMapping)
mappings = json.dumps(mappingDict[index]["mappings"])
newMapping = "\"mappings\" : " + mappings
return newMapping
def createIndexStatement(oldIndexName):
settingStr = getSettings(oldIndexName, oldClusterHost, oldClusterUserName, oldClusterPassword)
mappingStr = getMapping(oldIndexName, oldClusterHost, oldClusterUserName, oldClusterPassword)
createstatement = "{\n" + str(settingStr) + ",\n" + str(mappingStr) + "\n}"
return createstatement
def createIndex(oldIndexName, newIndexName=""):
if (newIndexName == "") :
newIndexName = oldIndexName
createstatement = createIndexStatement(oldIndexName)
print "The settings and mapping for the new index " + newIndexName + " are as follows:\n" + createstatement
endpoint = "/" + newIndexName
createResult = httpPut(newClusterHost, endpoint, createstatement, newClusterUser, newClusterPassword)
print "Result of creating the new index " + newIndexName + ": " + createResult
## main
indexList = getIndices(oldClusterHost, oldClusterUserName, oldClusterPassword)
systemIndex = []
for index in indexList:
if (index.startswith(".")):
systemIndex.append(index)
else :
createIndex(index, index)
if (len(systemIndex) > 0) :
for index in systemIndex:
print index + " might be a system index and will not be re-created. Handle it separately if needed."
Étape 3 : Configurer la liste blanche de réindexation distante
Alibaba Cloud Elasticsearch requiert une liste blanche pour autoriser la communication distante.
Connectez-vous à la console Alibaba Cloud Elasticsearch.
Dans le volet de navigation de gauche, cliquez sur Elasticsearch Clusters.
-
Accédez au cluster cible.
Dans la barre de navigation supérieure, sélectionnez le groupe de ressources auquel appartient le cluster ainsi que la région où il se trouve.
Sur la page Elasticsearch Clusters, localisez le cluster et cliquez sur son ID.
Dans le volet de navigation de gauche, accédez à .
Dans la section YML File Configuration, cliquez sur Modify Configuration à droite.
-
Dans le panneau YML File Configuration, modifiez la section Other Configurations pour définir la liste blanche de réindexation. Pour plus d'informations, consultez la rubrique Configuration des paramètres YML.
-
Architecture v2 : Spécifiez une combinaison d'un host et d'un port. Exemple :
reindex.remote.whitelist: ["10.0.xx.xx:9200","10.0.xx.xx:9200","10.0.xx.xx:9200","10.15.xx.xx:9200","10.15.xx.xx:9200","10.15.xx.xx:9200"] -
Architecture v3 : Spécifiez une combinaison du endpoint domain name et du port correspondant à l'instance. Exemple :
ep-bp1hfkx7coy8lvu4****-cn-hangzhou-i.epsrv-bp1zczi0fgoc5qtv****.cn-hangzhou.privatelink.aliyuncs.com:9200
-
Enregistrez les modifications et redémarrez le cluster.
Étape 4 : Migrer les données
Sélectionnez le script correspondant à votre scénario de données.
Scénario A : Migration simple (petit volume de données)
Exécutez cette commande une fois pour chaque index.
#!/bin/bash
# file:reindex.sh
indexName="Your index name"
newClusterUser="Username for the Alibaba Cloud Elasticsearch cluster"
newClusterPass="Password for the Alibaba Cloud Elasticsearch cluster"
newClusterHost="Host of the Alibaba Cloud Elasticsearch cluster"
oldClusterUser="Username for the self-managed Elasticsearch cluster"
oldClusterPass="Password for the self-managed Elasticsearch cluster"
# The host of the self-managed Elasticsearch cluster must be in the format of [scheme]://[host]:[port], for example, http://10.37.*.*:9200.
oldClusterHost="Host of the self-managed Elasticsearch cluster"
curl -u ${newClusterUser}:${newClusterPass} -XPOST "http://${newClusterHost}/_reindex?pretty" -H "Content-Type: application/json" -d'{
"source": {
"remote": {
"host": "'${oldClusterHost}'",
"username": "'${oldClusterUser}'",
"password": "'${oldClusterPass}'"
},
"index": "'${indexName}'",
"query": {
"match_all": {}
}
},
"dest": {
"index": "'${indexName}'"
}
}'
Scénario B : Migration incrémentielle (volume important de données avec horodatage)
Si vous disposez d'un champ update_time, utilisez ce script en boucle pour migrer les données par lots. Cette méthode minimise les temps d'arrêt en permettant la synchronisation du « delta » (nouvelles modifications) après le transfert initial en masse.
#!/bin/bash
# file: circleReindex.sh
# CONTROLLING STARTUP:
# This is a script for remote reindexing. Requirements:
# 1. The index has been created in the Alibaba Cloud Elasticsearch cluster, or the cluster supports automatic creation and dynamic mapping.
# 2. An IP address whitelist must be configured in the YML file of the Alibaba Cloud Elasticsearch cluster, for example, reindex.remote.whitelist: 172.16.**.**:9200.
# 3. The host must be in the format of [scheme]://[host]:[port].
USAGE="Usage: sh circleReindex.sh <count>
count: The number of executions. A negative number indicates a loop for incremental execution. A positive number indicates a one-time or multiple executions.
Example:
sh circleReindex.sh 1
sh circleReindex.sh 5
sh circleReindex.sh -1"
indexName="Your index name"
newClusterUser="Username for the Alibaba Cloud Elasticsearch cluster"
newClusterPass="Password for the Alibaba Cloud Elasticsearch cluster"
oldClusterUser="Username for the self-managed Elasticsearch cluster"
oldClusterPass="Password for the self-managed Elasticsearch cluster"
## http://myescluster.com
newClusterHost="Host of the Alibaba Cloud Elasticsearch cluster"
# The host of the self-managed Elasticsearch cluster must be in the format of [scheme]://[host]:[port], for example, http://10.37.*.*:9200.
oldClusterHost="Host of the self-managed Elasticsearch cluster"
timeField="Update time field"
reindexTimes=0
lastTimestamp=0
curTimestamp=`date +%s`
hasError=false
function reIndexOP() {
reindexTimes=$[${reindexTimes} + 1]
curTimestamp=`date +%s`
ret=`curl -u ${newClusterUser}:${newClusterPass} -XPOST "${newClusterHost}/_reindex?pretty" -H "Content-Type: application/json" -d '{
"source": {
"remote": {
"host": "'${oldClusterHost}'",
"username": "'${oldClusterUser}'",
"password": "'${oldClusterPass}'"
},
"index": "'${indexName}'",
"query": {
"range" : {
"'${timeField}'" : {
"gte" : '${lastTimestamp}',
"lt" : '${curTimestamp}'
}
}
}
},
"dest": {
"index": "'${indexName}'"
}
}'`
lastTimestamp=${curTimestamp}
echo "The ${reindexTimes}th reindex. The update deadline for this execution is ${lastTimestamp}. Result: ${ret}"
if [[ ${ret} == *error* ]]; then
hasError=true
echo "An exception occurred during this execution. Subsequent operations are interrupted. Please check."
fi
}
function start() {
## If the number is negative, the loop runs continuously.
if [[ $1 -lt 0 ]]; then
while :
do
reIndexOP
done
elif [[ $1 -gt 0 ]]; then
k=0
while [[ k -lt $1 ]] && [[ ${hasError} == false ]]; do
reIndexOP
let ++k
done
fi
}
## main
if [ $# -lt 1 ]; then
echo "$USAGE"
exit 1
fi
echo "Start the reindex operation for the index ${indexName}."
start $1
echo "A total of ${reindexTimes} reindex operations were performed."
Scénario C : Migration incrémentielle (volume important de données sans horodatage)
Modifiez le code du service amont pour ajouter un champ update_time. Après avoir ajouté le champ, migrez d'abord les données historiques. Ensuite, utilisez la méthode de migration par défilement décrite dans le Scénario B : Migration incrémentielle (volume important de données avec horodatage).
#!/bin/bash
# file:miss.sh
indexName="Your index name"
newClusterUser="Username for the Alibaba Cloud Elasticsearch cluster"
newClusterPass="Password for the Alibaba Cloud Elasticsearch cluster"
newClusterHost="Host of the Alibaba Cloud Elasticsearch cluster"
oldClusterUser="Username for the self-managed Elasticsearch cluster"
oldClusterPass="Password for the self-managed Elasticsearch cluster"
# The host of the self-managed Elasticsearch cluster must be in the format of [scheme]://[host]:[port], for example, http://10.37.*.*:9200
oldClusterHost="Host of the self-managed Elasticsearch cluster"
timeField="updatetime"
curl -u ${newClusterUser}:${newClusterPass} -XPOST "http://${newClusterHost}/_reindex?pretty" -H "Content-Type: application/json" -d '{
"source": {
"remote": {
"host": "'${oldClusterHost}'",
"username": "'${oldClusterUser}'",
"password": "'${oldClusterPass}'"
},
"index": "'${indexName}'",
"query": {
"bool": {
"must_not": {
"exists": {
"field": "'${timeField}'"
}
}
}
}
},
"dest": {
"index": "'${indexName}'"
}
}'
FAQ et dépannage
-
Q : Lors de l'exécution de la commande curl, le message d'erreur
{"error":"Content-Type header [application/x-www-form-urlencoded] is not supported","status":406}s'affiche.R : Ajoutez l'option
-H "Content-Type: application/json"à la commande curl et réessayez.// Get information about all indexes in the self-managed Elasticsearch cluster. If you do not have permissions, you can remove the "-u user:pass" parameter. oldClusterHost is the host of the self-managed Elasticsearch cluster. Replace it with your actual host. curl -u user:pass -XGET http://oldClusterHost/_cat/indices | awk '{print $3}' // Based on the returned index list, obtain the settings and mapping of the user index to be migrated. Replace indexName with the name of the user index you want to query. curl -u user:pass -XGET http://oldClusterHost/indexName/_settings,_mapping?pretty=true // Based on the obtained _settings and _mapping information of the corresponding index, create the corresponding index in the Alibaba Cloud Elasticsearch cluster. You can set the number of replicas to 0 to speed up data synchronization. After the data migration is complete, reset the number of replicas to 1. // newClusterHost is the host of the Alibaba Cloud Elasticsearch cluster, testindex is the name of the created index, and testtype is the type of the corresponding index. curl -u user:pass -XPUT http://<newClusterHost>/<testindex> -d '{ "testindex" : { "settings" : { "number_of_shards" : "5", // Assume that the number of shards for the corresponding index in the self-managed Elasticsearch cluster is 5. "number_of_replicas" : "0" // Set the number of replicas for the index to 0. } }, "mappings" : { // Assume that the mappings for the corresponding index in the self-managed Elasticsearch cluster are configured as follows. "testtype" : { "properties" : { "uid" : { "type" : "long" }, "name" : { "type" : "text" }, "create_time" : { "type" : "long" } } } } } }' -
Q : Comment puis-je accélérer la migration ?
R :
Désactivez les réplicas : Définissez
number_of_replicas: 0sur l'index de destination avant de commencer.Désactivez l'actualisation : Définissez
refresh_interval: -1sur l'index de destination.-
Découpage : Utilisez le paramètre
slicesdans l'API Reindex pour paralléliser le processus :POST _reindex?slices=5&refreshPour plus d'informations, consultez la documentation relative à l'API reindex.