Copier 6 550 morceaux arretait Loki 13 s au site ; les lier prend 40 ms. Ils sont adresses par leur contenu ; chunks/index loge delete_requests.gz, qui se reecrit, et reste vraiment copie. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
84 lines
3.4 KiB
Bash
84 lines
3.4 KiB
Bash
#!/bin/bash
|
|
# Géré par Set-OPS (rôle client_backup). Ne pas éditer à la main.
|
|
#
|
|
# setops-copie-a-froid SERVICE SOURCE DESTINATION [--blocs-immuables] [--lier REL]... [--copier REL]...
|
|
#
|
|
# Copie COHERENTE d'une base qui ecrit en continu (Prometheus, Loki) : le service est
|
|
# arrete le temps de la copie, puis redemarre — QUOI QU'IL ARRIVE a la copie, et seulement
|
|
# s'il tournait avant. La destination n'est remplacee qu'une fois la copie complete.
|
|
#
|
|
# POURQUOI A FROID (decision de l'exploitant, 2026-10-07 : « on ne prend pas de risque »).
|
|
# Copier a chaud un WAL qu'on ecrit, c'est sauvegarder un fichier a moitie ecrit. L'autre
|
|
# voie — ne garder que les blocs fermes — perdait jusqu'aux deux dernieres heures de
|
|
# metriques a chaque reconstruction. Mesure au site : 2,9 Go de Prometheus se lisent en
|
|
# 4,2 s, son WAL seul en 0,3 s ; Loki entier en 2 s.
|
|
#
|
|
# `--blocs-immuables` : les sous-dossiers nommes par un ULID (26 caracteres, `01…`) sont
|
|
# les blocs de Prometheus, que rien ne reecrit apres leur fermeture. On les recopie par
|
|
# LIENS DURS — instantane, sans place — et le reste (WAL, `chunks_head`) par une vraie
|
|
# copie. Si la destination est sur un autre systeme de fichiers, on copie tout.
|
|
#
|
|
# `--lier REL` lie tout un sous-dossier ; `--copier REL` y copie vraiment un sous-dossier qui,
|
|
# lui, bouge (2026-10-07). Pour Loki : `--lier chunks --copier chunks/index`. Ses morceaux sont
|
|
# adresses par leur contenu (`debut:fin:somme`, decode sur site-mon-01) et ne bougent jamais ;
|
|
# mais `chunks/index/` loge aussi `delete_requests.gz`, la base du compacteur, mesuree
|
|
# reecrite trois semaines apres sa naissance. La lier, c'etait laisser la sauvegarde changer
|
|
# avec elle. Copier 6 550 morceaux arretait Loki 13 s ; les lier prend 40 ms.
|
|
set -euo pipefail
|
|
|
|
service="${1:?service}"
|
|
source="${2:?source}"
|
|
dest="${3:?destination}"
|
|
shift 3
|
|
blocs="" lier=() copier=()
|
|
while (( $# )); do
|
|
case "$1" in
|
|
--blocs-immuables) blocs=1; shift ;;
|
|
--lier) lier+=("$2"); shift 2 ;;
|
|
--copier) copier+=("$2"); shift 2 ;;
|
|
*) echo "copie a froid : option inconnue : $1" >&2; exit 2 ;;
|
|
esac
|
|
done
|
|
|
|
[[ -d "${source}" ]] || { echo "copie a froid : ${source} n'existe pas — rien a copier." >&2; exit 0; }
|
|
|
|
tmp="${dest}.en-cours"
|
|
rm -rf "${tmp}"
|
|
mkdir -p "$(dirname "${dest}")"
|
|
|
|
actif=0
|
|
if systemctl is-active --quiet "${service}"; then actif=1; fi
|
|
relancer() { if (( actif )); then systemctl start "${service}"; fi; }
|
|
|
|
debut=$(date +%s%N)
|
|
if (( actif )); then systemctl stop "${service}"; fi
|
|
trap relancer EXIT
|
|
|
|
lie() { cp -al "$1" "$2" 2>/dev/null || { rm -rf "$2"; cp -a "$1" "$2"; }; }
|
|
mkdir -p "${tmp}"
|
|
for e in "${source}"/* "${source}"/.[!.]*; do
|
|
[[ -e "${e}" ]] || continue
|
|
n="$(basename "${e}")"
|
|
if [[ -n "${blocs}" && -d "${e}" && ${#n} -eq 26 && "${n}" == 01* ]] \
|
|
|| [[ " ${lier[*]:-} " == *" ${n} "* ]]; then
|
|
lie "${e}" "${tmp}/${n}"
|
|
else
|
|
cp -a "${e}" "${tmp}/${n}"
|
|
fi
|
|
done
|
|
# Ce qui bouge, a l'interieur d'un dossier lie : remplace par une vraie copie.
|
|
for c in "${copier[@]:+${copier[@]}}"; do
|
|
if [[ -e "${source}/${c}" ]]; then
|
|
rm -rf "${tmp:?}/${c}"
|
|
mkdir -p "$(dirname "${tmp}/${c}")"
|
|
cp -a "${source}/${c}" "${tmp}/${c}"
|
|
fi
|
|
done
|
|
|
|
trap - EXIT
|
|
relancer
|
|
fin=$(date +%s%N)
|
|
|
|
rm -rf "${dest}"
|
|
mv "${tmp}" "${dest}"
|
|
echo "copie a froid de ${source} : ${service} $( (( actif )) && echo "arrete (jusqu a la relance, rejeu du WAL non compris) $(( (fin - debut) / 1000000 )) ms" || echo "n'etait pas actif")"
|