Предположим, что «пятая» команда занимает своими метриками в «старом» VMetrics-кластере тенанты с номерами 12
, 13
, 14
. Это означает, что команда занимает тенанты 12:0
, 13:0
, 14:0
.
Пример копирования из старого VMetrics-кластера в новый с изменением номеров тенантов
1. Заметки
-
В старом кластере метрики различных команд хранились в тенантах без учёта номера проекта, то есть одна команда могла занимать несколько номеров
vm_account_id
. В парадигме VMetrics, где в случае пропуска номера проекта в номере тенанта, считается, что номер проекта равен нулю. -
В новом кластере «пятой» команде выдлелен лишь один номер
vm_account-id
, предположим, что это номер5
. В пределах этого номера аккаунта, команда «пять» может занять все 32 бита vm_project_id. То есть для технический метрик выделить тенант5:1
. Для каких-либо бизнес-метрик тенанты5:130
,5:131
,5:132
. И т.д.
2. Подготовка к запуску скрипта
-
В переменных скрипта
START_MONTH
иEND_MONTH
поменяйте даты начального месяца и последнего месяца копируемого диапазона. При желании скрипт можно переделать на использование в диапазоне дней, часов, и т.д. -
В переменной
ARGS_LIST
отредактируйте записи в массиве в виде:
«номер исходного тенанта в старом кластере»
«номер целевого аккаунта»
«номер целевого проекта» -
Помните, что метрики храняться чанками, поэтому при попадании какой-либо метрики в, например, последнюю минуту желаемого диапазона, будет скопирован весь чанк, то есть в новом кластере можно будет увидеть метрики, дата которых выходят за границы скопированного диапазона. Я наблюдал +несколько часов.
-
В результате копирования, в новом VMetrics-кластере могут появиться дублирующие записи. Для решения этой проблемы включите в новом VMetrics-кластере опцию дедупликации равной 1ms и на vmstorage’ах, и на vmselect’ах.
3. Запуск скрипта
Я выполнял запуск с помощью команды:
unbuffer ./vmctl-copying-16.sh | tee script.$(date +%y%m%d-%H%M%S).log
4. Содержимое скрипта
Details
#!/bin/bash exec 3>script.$(date +%y%m%d-%H%M%S).stderr.log BASH_XTRACEFD=3 set -xeuo pipefail # ------------------------------- # Constants # ------------------------------- DST_ADDRESS='https://mon-vmauth-vip.example.org' DST_BEARER_TOKEN='xxxxxxxxxxxxxxxxxxxxxxxxx' START_MONTH="2024-09" END_MONTH="2024-12" DEFAULT_CHUNK="month" LOG_FILE="vmctl-migration.$(date +%y%m%d-%H%M%S).log" DRY_RUN="${DRY_RUN:-false}" ARGS_LIST=( "0 0 1" "1 2 1" "2 2 2" "3 2 3" "4 2 4" "5 13 1" "6 7 1" "7 3 1000" "8 1 1" "9 9 1" "21 7 0" ) # ------------------------------- # Logging # ------------------------------- log() { echo "$(date '+%Y-%m-%d %H:%M:%S') $*" | tee -a "$LOG_FILE" } log_hr() { echo "--------------------------------------------------------------------------------" | tee -a "$LOG_FILE" } log_section() { echo "================================================================================" | tee -a "$LOG_FILE" } log_err() { echo "$(date '+%Y-%m-%d %H:%M:%S') $*" >&2 } # ------------------------------- # HTTP helper # ------------------------------- safe_curl() { local url="$1" log_err "CMD: curl -sf \"$url\"" local result if ! result=$(curl -sf "$url"); then log_err "❌ curl error for: $url" return 1 fi log_err "RESP: $result" printf '%s' "$result" } # ------------------------------- # Count check (no filters allowed) # ------------------------------- check_series_count() { local src_address=$1 local url="${src_address}/api/v1/series/count" log "Checking series count: $url" local response count if ! response=$(safe_curl "$url"); then log "⚠ Cannot fetch series count, skipping full-tenant copy" return 1 fi if ! count=$(echo "$response" | jq -r '.data[]' 2>/dev/null); then log "⚠ Cannot parse series count, skipping full-tenant copy" return 1 fi if [[ -z "$count" ]]; then log "⚠ Empty series count, skipping full-tenant copy" return 1 fi log "Series count: $count" if (( count >= 1000000 )); then log "⚠ Too many series ($count), skipping full-tenant copy" return 1 fi return 0 } # ------------------------------- # Run vmctl # ------------------------------- run_vmctl() { local src=$1 dst=$2 tok=$3 acc=$4 prj=$5 local ts=$6 te=$7 filt=$8 step=$9 log_hr log "▶ vmctl: step=${step}, filter=${filt:-<none>}" if [ "$DRY_RUN" = "true" ]; then log "(dry-run) skipping vmctl" return 0 fi if ! vmctl-prod vm-native -s \ -vm-native-backoff-retries 1 \ -vm-native-src-addr "$src" \ -vm-native-dst-addr "$dst" \ -vm-native-dst-bearer-token "$tok" \ -vm-extra-label "vm_account_id=${acc}" \ -vm-extra-label "vm_project_id=${prj}" \ -vm-native-filter-time-start "$ts" \ -vm-native-filter-time-end "$te" \ -vm-native-step-interval="$step" \ ${filt:+-vm-native-filter-match "$filt"}; then log "❌ vmctl failed" return 1 fi log "✔ vmctl succeeded" return 0 } # ------------------------------- # Metadata fetcher: metrics only # ------------------------------- fetch_metric_names_for_range() { local src=$1 start_ts=$2 end_ts=$3 local url="${src}/api/v1/label/__name__/values?start=${start_ts}&end=${end_ts}" log_err "Fetch metrics via: $url" local resp resp=$(safe_curl "$url") || return 1 echo "$resp" | jq -r '.data[]' 2>/dev/null | sort -u } # ------------------------------- # Main # ------------------------------- for entry in "${ARGS_LIST[@]}"; do read -r SRC_ID DST_ID PRJ_ID <<< "$entry" SRC="http://127.0.0.1:8000/select/${SRC_ID}/prometheus" TIME_START="${START_MONTH}-01T00:00:00+03:00" TIME_END=$(date -d "$(date -d "${END_MONTH}-01 +1 month" +%Y-%m-%d) -1 sec" +%Y-%m-%dT%H:%M:%S%:z) TS_START=$(date -d "$TIME_START" +%s) TS_END=$(date -d "$TIME_END" +%s) log_section log "TENANT ${SRC_ID} → ${DST_ID}:${PRJ_ID}" # 1) Full-tenant copy if check_series_count "$SRC"; then run_vmctl "$SRC" "$DST_ADDRESS" "$DST_BEARER_TOKEN" "$DST_ID" "$PRJ_ID" \ "$TIME_START" "$TIME_END" "" "month" && continue else log "⏭ skip full-tenant" fi log_hr log "▶ per-metric copy" # 2) Fetch metrics list METRICS=$(fetch_metric_names_for_range "$SRC" "$TS_START" "$TS_END") || continue for METRIC in $METRICS; do FILTER="{__name__=\"$METRIC\"}" log_hr log "Metric: $METRIC" # 3) Try steps in sequence for STEP in month week day hour minute; do if run_vmctl "$SRC" "$DST_ADDRESS" "$DST_BEARER_TOKEN" "$DST_ID" "$PRJ_ID" \ "$TIME_START" "$TIME_END" "$FILTER" "$STEP"; then # success at this granularity, go to next metric continue 2 fi done # 4) All steps failed log "❌ Failed to migrate: $METRIC" done done set +x exec 3>&-