loki : les morceaux sont lies, pas copies ; chunks/index reste copie
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>
This commit is contained in:
parent
3e2846cc5f
commit
9a4b63544e
4 changed files with 86 additions and 17 deletions
25
CHANGELOG.md
25
CHANGELOG.md
|
|
@ -1,5 +1,30 @@
|
||||||
# CHANGELOG — Set-OPS
|
# CHANGELOG — Set-OPS
|
||||||
|
|
||||||
|
## 2026-10-07 (109) — Les morceaux de Loki sont liés, pas copiés ; sa base de suppressions, si
|
||||||
|
|
||||||
|
**94 preuves.** Au site, la copie à froid arrêtait Loki **13 s**, pour copier 6 550 petits
|
||||||
|
fichiers. Ses morceaux de journal sont adressés par leur contenu : un nom décodé donne
|
||||||
|
`1a0d123a4e8:1a0d1918235:6b5feaac` (début, fin, somme de contrôle). Ils ne bougent donc
|
||||||
|
jamais, et les lier prend **40 ms** (mesuré sur `site-mon-01`).
|
||||||
|
|
||||||
|
### Le fichier qui bougeait parmi les morceaux
|
||||||
|
|
||||||
|
Un contrôle d'immuabilité, refait avec `stat` (le `find` de la machine ne connaît pas `%W` :
|
||||||
|
le premier passage ne mesurait rien), a trouvé **un fichier sur 6 550** modifié après sa
|
||||||
|
naissance : `chunks/index/delete_requests/delete_requests.gz`, né le 2026-09-12 et réécrit le
|
||||||
|
2026-10-07. Ce n'est pas un morceau : c'est la base des demandes de suppression du compacteur,
|
||||||
|
rangée dans le même stockage objet. Lier tout `chunks/` aurait laissé la sauvegarde changer
|
||||||
|
avec elle.
|
||||||
|
|
||||||
|
**Fait** : `setops-copie-a-froid` accepte `--lier REL` (lier tout un sous-dossier) et
|
||||||
|
`--copier REL` (y copier vraiment ce qui bouge). Loki : `--lier chunks --copier chunks/index`.
|
||||||
|
|
||||||
|
**Éprouvé** : `test_restauration.py` ; morceau lié (même inode), `chunks/index` copié (autre
|
||||||
|
inode), une réécriture après la copie ne touche pas la sauvegarde. Témoin : sans `--copier`,
|
||||||
|
les deux derniers échouent. `shellcheck` propre. `make verifier` conforme, **94/94**.
|
||||||
|
|
||||||
|
**Pas encore déployé** : la durée réelle se mesurera au prochain dépôt.
|
||||||
|
|
||||||
## 2026-10-07 (108) — Le site recevait encore la sauvegarde d'avant le 2026-09-30
|
## 2026-10-07 (108) — Le site recevait encore la sauvegarde d'avant le 2026-09-30
|
||||||
|
|
||||||
**94 preuves.** Déployer la copie à froid de Prometheus et Loki au site (`site-mon-01`) a
|
**94 preuves.** Déployer la copie à froid de Prometheus et Loki au site (`site-mon-01`) a
|
||||||
|
|
|
||||||
|
|
@ -104,7 +104,7 @@ client_backup_catalogue:
|
||||||
/usr/local/sbin/setops-copie-a-froid
|
/usr/local/sbin/setops-copie-a-froid
|
||||||
{{ serveur_loki_service | default('loki') }}
|
{{ serveur_loki_service | default('loki') }}
|
||||||
{{ serveur_loki_chemin | default('/var/lib/loki') }}
|
{{ serveur_loki_chemin | default('/var/lib/loki') }}
|
||||||
{{ client_backup_staging }}/loki/donnees
|
{{ client_backup_staging }}/loki/donnees --lier chunks --copier chunks/index
|
||||||
chemins: ["{{ client_backup_staging }}/loki"]
|
chemins: ["{{ client_backup_staging }}/loki"]
|
||||||
serveur_icinga:
|
serveur_icinga:
|
||||||
# L'AC D'ICINGA FAIT L'IDENTITE DE SA BASE (2026-10-07). Icinga 2 derive l'environnement
|
# L'AC D'ICINGA FAIT L'IDENTITE DE SA BASE (2026-10-07). Icinga 2 derive l'environnement
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# Géré par Set-OPS (rôle client_backup). Ne pas éditer à la main.
|
# Géré par Set-OPS (rôle client_backup). Ne pas éditer à la main.
|
||||||
#
|
#
|
||||||
# setops-copie-a-froid SERVICE SOURCE DESTINATION [--blocs-immuables]
|
# 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
|
# 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
|
# arrete le temps de la copie, puis redemarre — QUOI QU'IL ARRIVE a la copie, et seulement
|
||||||
|
|
@ -17,12 +17,28 @@
|
||||||
# les blocs de Prometheus, que rien ne reecrit apres leur fermeture. On les recopie par
|
# 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
|
# 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.
|
# 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
|
set -euo pipefail
|
||||||
|
|
||||||
service="${1:?service}"
|
service="${1:?service}"
|
||||||
source="${2:?source}"
|
source="${2:?source}"
|
||||||
dest="${3:?destination}"
|
dest="${3:?destination}"
|
||||||
blocs="${4:-}"
|
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; }
|
[[ -d "${source}" ]] || { echo "copie a froid : ${source} n'existe pas — rien a copier." >&2; exit 0; }
|
||||||
|
|
||||||
|
|
@ -38,20 +54,26 @@ debut=$(date +%s%N)
|
||||||
if (( actif )); then systemctl stop "${service}"; fi
|
if (( actif )); then systemctl stop "${service}"; fi
|
||||||
trap relancer EXIT
|
trap relancer EXIT
|
||||||
|
|
||||||
if [[ "${blocs}" == "--blocs-immuables" ]]; then
|
lie() { cp -al "$1" "$2" 2>/dev/null || { rm -rf "$2"; cp -a "$1" "$2"; }; }
|
||||||
mkdir -p "${tmp}"
|
mkdir -p "${tmp}"
|
||||||
for e in "${source}"/* "${source}"/.[!.]*; do
|
for e in "${source}"/* "${source}"/.[!.]*; do
|
||||||
[[ -e "${e}" ]] || continue
|
[[ -e "${e}" ]] || continue
|
||||||
n="$(basename "${e}")"
|
n="$(basename "${e}")"
|
||||||
if [[ -d "${e}" && ${#n} -eq 26 && "${n}" == 01* ]]; then
|
if [[ -n "${blocs}" && -d "${e}" && ${#n} -eq 26 && "${n}" == 01* ]] \
|
||||||
cp -al "${e}" "${tmp}/${n}" 2>/dev/null || cp -a "${e}" "${tmp}/${n}"
|
|| [[ " ${lier[*]:-} " == *" ${n} "* ]]; then
|
||||||
else
|
lie "${e}" "${tmp}/${n}"
|
||||||
cp -a "${e}" "${tmp}/${n}"
|
else
|
||||||
fi
|
cp -a "${e}" "${tmp}/${n}"
|
||||||
done
|
fi
|
||||||
else
|
done
|
||||||
cp -a "${source}" "${tmp}"
|
# Ce qui bouge, a l'interieur d'un dossier lie : remplace par une vraie copie.
|
||||||
fi
|
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
|
trap - EXIT
|
||||||
relancer
|
relancer
|
||||||
|
|
|
||||||
|
|
@ -395,6 +395,28 @@ exit 0
|
||||||
verifier(r.returncode == 0 and "stop prometheus" not in appels and "start prometheus" not in appels,
|
verifier(r.returncode == 0 and "stop prometheus" not in appels and "start prometheus" not in appels,
|
||||||
"un service inactif n'est ni arrete ni relance")
|
"un service inactif n'est ni arrete ni relance")
|
||||||
|
|
||||||
|
# LOKI (2026-10-07) : les morceaux sont lies, `chunks/index/` copie. Il loge la base
|
||||||
|
# du compacteur (`delete_requests.gz`), qui se reecrit : liee, la sauvegarde
|
||||||
|
# changerait avec elle.
|
||||||
|
loki, prep = d / "loki", d / "prep" / "donnees"
|
||||||
|
(loki / "chunks" / "fake").mkdir(parents=True)
|
||||||
|
(loki / "chunks" / "fake" / "MWEw").write_text("morceau")
|
||||||
|
(loki / "chunks" / "index" / "delete_requests").mkdir(parents=True)
|
||||||
|
(loki / "chunks" / "index" / "delete_requests" / "delete_requests.gz").write_text("v1")
|
||||||
|
(loki / "wal").mkdir()
|
||||||
|
(loki / "wal" / "00000001").write_text("wal")
|
||||||
|
r = subprocess.run(["bash", str(outil), "loki", str(loki), str(prep), "--lier", "chunks",
|
||||||
|
"--copier", "chunks/index"], env=env, capture_output=True, text=True)
|
||||||
|
verifier(r.returncode == 0 and (prep / "chunks" / "fake" / "MWEw").stat().st_ino
|
||||||
|
== (loki / "chunks" / "fake" / "MWEw").stat().st_ino,
|
||||||
|
f"Loki : un morceau est lie (meme inode) ({r.stderr.strip()[-120:]})")
|
||||||
|
base = loki / "chunks" / "index" / "delete_requests" / "delete_requests.gz"
|
||||||
|
copie = prep / "chunks" / "index" / "delete_requests" / "delete_requests.gz"
|
||||||
|
verifier(copie.exists() and copie.stat().st_ino != base.stat().st_ino,
|
||||||
|
"Loki : chunks/index est vraiment copie (un autre inode)")
|
||||||
|
base.write_text("v2") # le compacteur reecrit sa base sur place
|
||||||
|
verifier(copie.read_text() == "v1", "une reecriture apres la copie ne change pas la sauvegarde")
|
||||||
|
|
||||||
|
|
||||||
def main() -> int:
|
def main() -> int:
|
||||||
couverture()
|
couverture()
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue