Ausgangslage
Für den Abgleich eines großen Datenbestands zwischen zwei Synology-NAS-Systemen (an zwei Standorten) war ursprünglich geplant, Snapshots durch Snapshot Replication direkt auf das entfernte NAS replizieren zu lassen.
Leider war jedoch die Übertragungsgeschwindigkeit 🐌-langsam und für ~20TB (Initialsync) an Daten keine Option. Erste Tests mit rclone zeigten dann zum Glück, dass da deutlich mehr möglich wäre:
| Methode |
Übertragungsrate |
| Synology Snapshot Replication |
~8 MB/s |
| rsync |
~8 MB/s |
| rclone mit mehreren parallelen Transfers über SFTP |
~40 MB/s |
Der Vorteil von rclone liegt hier vor allem in der Parallelisierung:
1
2
3
4
|
--transfers 8 \
--checkers 16 \
--multi-thread-streams 4 \
--multi-thread-cutoff 256M
|
Dadurch lassen sich mehrere Dateien gleichzeitig übertragen und größere Dateien zusätzlich über mehrere Streams verarbeiten.
Ziel
Die fertige Lösung soll:
- von NAS A nach NAS B replizieren
- über den DSM-Aufgabenplaner gestartet werden
- parallele Läufe verhindern
- das Log während des Syncs live schreiben
- verschobene Dateien möglichst als Move erkennen
- alle fünf Minuten einen Fortschrittsstatus erzeugen
- genau eine ntfy-Live-Statusnachricht aktualisieren
- diese Live-Nachricht nach Abschluss wieder löschen
- anschließend eine separate Erfolgs-, Fehler- oder Abbruchmeldung senden
Auf beiden NAS-Systemen laufen zusätzlich lokale Snapshots.
Architektur
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
NAS A
│
│ DSM Aufgabenplaner
▼
sync-replica.sh
│
┌────────┴────────┐
│ │
flock rclone
│
│ SFTP
▼
NAS B
rclone stdout/stderr
│
▼
status_filter
│
├──── alle 5 Minuten ───► ntfy Live-Status
│
▼
tee
┌─┴─────────────┐
▼ ▼
dauerhaftes temporäres
Log Log
│
▼
Abschlussstatistik
│
▼
ntfy Abschlussmeldung
|
Verzeichnisstruktur auf NAS A
Eine mögliche Struktur sieht so aus:
1
2
3
4
5
6
7
8
|
/volume1/Tools/
├── rclone
├── sync-replica.sh
├── rclone-sync.log
├── rclone-sync.lock
└── rclone-config/
├── rclone.conf
└── .env
|
Bedeutung der Dateien:
/volume1/Tools/rclone –> rclone-Binary
/volume1/Tools/sync-replica.sh –> Sync-Script
/volume1/Tools/rclone-sync.log –> Dauerhaftes Live-Log aller Läufe
/volume1/Tools/rclone-sync.lock –> Lock-Datei, damit nicht zwei Syncs gleichzeitig laufen
/volume1/Tools/rclone-config/rclone.conf –> rclone-Konfiguration mit dem SFTP-Remote
/volume1/Tools/rclone-config/.env –> Konfigurationsdatei für ntfy-URL und Token
Berechtigungen
Die sensiblen Dateien sollten nur für root lesbar sein:
1
2
3
4
|
chmod 700 /volume1/Tools/sync-replica.sh
chmod 700 /volume1/Tools/rclone
chmod 600 /volume1/Tools/rclone-config/rclone.conf
chmod 600 /volume1/Tools/rclone-config/.env
|
rclone installieren
Die passende rclone -Binary wird auf NAS A abgelegt:
Danach ausführbar machen:
1
|
chmod +x /volume1/Tools/rclone
|
Version prüfen:
1
|
/volume1/Tools/rclone version
|
SFTP-Remote konfigurieren
Die rclone-Konfiguration liegt unter:
1
|
/volume1/Tools/rclone-config/rclone.conf
|
Ein anonymisiertes Beispiel:
1
2
3
4
5
6
7
|
[backup-nas]
type = sftp
host = 10.0.0.20
user = backupuser
port = 22
key_file = /root/.ssh/id_ed25519
shell_type = unix
|
Der Remote-Name lautet in diesem Beispiel:
Verbindung testen:
1
2
3
|
/volume1/Tools/rclone lsd \
--config /volume1/Tools/rclone-config/rclone.conf \
backup-nas:/
|
Wenn die Verzeichnisse des Ziel-NAS erscheinen, funktioniert die Verbindung.
.env-Datei
Private Werte kommen nicht direkt ins Script, sondern in:
1
|
/volume1/Tools/rclone-config/.env
|
Beispiel:
1
2
|
NTFY_URL="https://ntfy.example.com/synology"
NTFY_TOKEN="tk_REPLACE_ME"
|
Danach:
1
|
chmod 600 /volume1/Tools/rclone-config/.env
|
Das Script lädt diese Datei beim Start.
ntfy.sh-Benachrichtigungen
Seit ntfy.sh v2.16.0 lassen sich Benachrichtigungen nachträglich aktualisieren – wie gemacht für einen regelmäßig aktualisierten Synchronisationsstatus.
Statt alle paar Minuten eine neue Meldung zu erzeugen, wird einfach immer dieselbe aktualisiert. Das wollte natürlich unbedingt ausprobiert werden.
rclone kann dafür regelmäßig Statistiken ausgeben:
1
2
|
--stats 5m \
--stats-log-level NOTICE
|
Ein typischer Block sieht ungefähr so aus:
1
2
3
4
|
Transferred: 465.178 GiB / 588.182 GiB, 79%, 23.190 MiB/s, ETA 1h30m31s
Checks: 1168704 / 1168704, 100%, Listed 2432377
Transferred: 22489 / 30600, 73%
Elapsed time: 5h40m0.0s
|
Um eine ntfy.sh-Nachricht nachträglich bearbeiten zu können, muss man sie zusätzlich mit einer Sequence-ID versenden.
Das Script generiert sich eine feste, welche sich aus rclone-sync- sowie dem Hostname zusammensetzt:
1
|
NTFY_STATUS_SID="rclone-sync-${HOST}"
|
und sendet anschliessend:
1
|
-H "X-Sequence-ID: $NTFY_STATUS_SID"
|
Dadurch wird immer dieselbe Live-Statusnachricht aktualisiert.
Nach Abschluss wird diese Live-Statusnachricht wieder gelöscht und durch eine normale Abschlussmeldung ersetzt.
Verschobene Dateien erkennen
Ein normaler Sync kann eine verschobene Datei als:
1
2
3
|
alter Pfad gelöscht
+
neuer Pfad hinzugefügt
|
interpretieren.
Dann würde dieselbe Datei unter Umständen erneut übertragen werden.
rclone kann solche Fälle mit:
erkennen.
Da beim verwendeten SFTP-Setup keine brauchbaren kompatiblen Hashes zur Verfügung stehen, wird folgende Strategie genutzt:
1
2
|
--track-renames \
--track-renames-strategy modtime,leaf
|
Damit werden insbesondere Dateiname und Änderungszeit zur Erkennung genutzt. Die Dateigröße wird beim Rename-Tracking ebenfalls berücksichtigt.
Das ist für Datenbestände interessant, bei denen Dateien häufig lediglich in andere Ordner verschoben werden.
Live-Logging mit tee
Mit tee landet die Ausgabe gleichzeitig im dauerhaften und im temporären Log:
1
2
3
4
5
6
7
8
9
|
rclone
│
▼
status_filter
│
▼
tee
├── /volume1/Tools/rclone-sync.log
└── /tmp/rclone-sync.xxxxxx
|
Das Hauptlog kann damit live angesehen werden:
1
|
tail -f /volume1/Tools/rclone-sync.log
|
Wichtig bei Pipes: echter Exit-Code
Bei:
liefert $? den Exit-Code des letzten Pipeline-Kommandos.
Im Script interessiert aber der Exit-Code von rclone.
Unter Bash wird deshalb verwendet:
Da im fertigen Script noch status_filter zwischen rclone und tee sitzt, sieht die Pipeline so aus:
1
2
3
|
[0] rclone
[1] status_filter
[2] tee
|
Damit bleibt:
korrekt.
Vollständiges Script
/volume1/Tools/sync-replica.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
|
#!/bin/bash
# =============================================================================
# Konfiguration
# =============================================================================
RCLONE=/volume1/Tools/rclone
CONFIG=/volume1/Tools/rclone-config/rclone.conf
ENV_FILE=/volume1/Tools/rclone-config/.env
SRC=/volume1/Daten
DST=backup-nas:/Daten
LOG=/volume1/Tools/rclone-sync.log
LOCK=/volume1/Tools/rclone-sync.lock
NTFY_ON_SUCCESS=1
NTFY_ON_SKIP=0
# =============================================================================
# .env laden
# =============================================================================
if [ -r "$ENV_FILE" ]; then
# shellcheck disable=SC1090
. "$ENV_FILE"
fi
: "${NTFY_URL:=}"
: "${NTFY_TOKEN:=}"
# =============================================================================
# Host / Live-Status-ID
# =============================================================================
HOST=$(hostname -s 2>/dev/null || hostname)
NTFY_STATUS_SID="rclone-sync-${HOST}"
LIVE_STATUS_DELETED=0
# =============================================================================
# Normale ntfy-Nachricht
# =============================================================================
notify() {
[ -n "$NTFY_URL" ] || return 0
if ! command -v curl >/dev/null 2>&1; then
echo "$(date): curl nicht gefunden" >> "$LOG"
return 0
fi
local args=(
-sS
-f
-o /dev/null
--max-time 20
--retry 3
--retry-delay 5
-H "Title: $1"
-H "Priority: $2"
-H "Tags: $3"
--data-binary @-
)
[ -n "$NTFY_TOKEN" ] &&
args+=(-H "Authorization: Bearer $NTFY_TOKEN")
if ! printf '%s' "$4" |
curl "${args[@]}" "$NTFY_URL" 2>> "$LOG"; then
echo "$(date): ntfy-Benachrichtigung fehlgeschlagen" >> "$LOG"
fi
}
# =============================================================================
# ntfy Live-Status aktualisieren
# =============================================================================
notify_status() {
[ -n "$NTFY_URL" ] || return 0
command -v curl >/dev/null 2>&1 || return 0
local args=(
-sS
-f
-o /dev/null
--max-time 20
--retry 3
--retry-delay 5
-H "Title: Daten-Sync läuft ($HOST)"
-H "Priority: 2"
-H "Tags: hourglass_flowing_sand,floppy_disk"
-H "X-Sequence-ID: $NTFY_STATUS_SID"
--data-binary @-
)
[ -n "$NTFY_TOKEN" ] &&
args+=(-H "Authorization: Bearer $NTFY_TOKEN")
if ! printf '%s' "$1" |
curl "${args[@]}" "$NTFY_URL" 2>> "$LOG"; then
echo "$(date): ntfy-Live-Status fehlgeschlagen" >> "$LOG"
return 1
fi
}
# =============================================================================
# ntfy Live-Status löschen
# =============================================================================
delete_status() {
[ "$LIVE_STATUS_DELETED" -eq 0 ] || return 0
[ -n "$NTFY_URL" ] || return 0
command -v curl >/dev/null 2>&1 || return 0
local args=(
-sS
-o /dev/null
--max-time 20
-X DELETE
)
[ -n "$NTFY_TOKEN" ] &&
args+=(-H "Authorization: Bearer $NTFY_TOKEN")
if ! curl "${args[@]}" \
"${NTFY_URL}/${NTFY_STATUS_SID}" \
2>> "$LOG"; then
echo "$(date): Live-Status konnte nicht gelöscht werden" >> "$LOG"
return 1
fi
LIVE_STATUS_DELETED=1
}
# =============================================================================
# Überlappung verhindern
# =============================================================================
exec 9>"$LOCK"
if ! flock -n 9; then
echo "=== $(date): Lauf übersprungen, vorheriger Lauf aktiv ===" >> "$LOG"
if [ "$NTFY_ON_SKIP" = "1" ]; then
notify \
"Sync übersprungen ($HOST)" \
2 \
"hourglass" \
"Der vorherige Sync ist noch aktiv."
fi
exit 0
fi
# =============================================================================
# Logrotation bei 50 MB
# =============================================================================
if [ -f "$LOG" ] &&
[ "$(stat -c%s "$LOG")" -gt 52428800 ]; then
mv "$LOG" "${LOG}.old"
fi
# =============================================================================
# Temporäres Log
# =============================================================================
TMPLOG=$(mktemp /tmp/rclone-sync.XXXXXX) ||
TMPLOG="/tmp/rclone-sync.$$"
# =============================================================================
# Cleanup
# =============================================================================
cleanup() {
delete_status
rm -f "$TMPLOG"
}
trap cleanup EXIT
# =============================================================================
# Start
# =============================================================================
START_TS=$(date +%s)
echo "=== Start $(date) ===" >> "$LOG"
START_MSG="Quelle: $SRC
Ziel: $DST
Status: Sync gestartet
Start: $(date '+%d.%m.%Y %H:%M:%S')
Fortschritt: wird ermittelt ..."
notify_status "$START_MSG"
# =============================================================================
# Statistikfilter
# =============================================================================
status_filter() {
local line
local clean
local bytes=""
local checks=""
local files=""
local deleted=""
local errors=""
local elapsed=""
local in_stats=0
while IFS= read -r line; do
# Originalzeile unverändert an tee weiterreichen
printf '%s\n' "$line"
# Datum/Uhrzeit/Log-Level entfernen
clean=$(printf '%s\n' "$line" |
sed -E \
's/^[0-9]{4}\/[0-9]{2}\/[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2} [A-Z]+:[[:space:]]*//')
# Beginn Statistikblock
if printf '%s\n' "$clean" |
grep -Eq '^Transferred:[[:space:]]+[0-9.]+ ?[KMGTPE]?i?B'; then
bytes=$(printf '%s\n' "$clean" |
sed -E 's/^Transferred:[[:space:]]+//')
checks=""
files=""
deleted=""
errors=""
elapsed=""
in_stats=1
continue
fi
[ "$in_stats" -eq 1 ] || continue
if printf '%s\n' "$clean" | grep -Eq '^Checks:'; then
checks=$(printf '%s\n' "$clean" |
sed -E 's/^Checks:[[:space:]]+//')
continue
fi
if printf '%s\n' "$clean" | grep -Eq '^Deleted:'; then
deleted=$(printf '%s\n' "$clean" |
sed -E 's/^Deleted:[[:space:]]+//')
continue
fi
if printf '%s\n' "$clean" |
grep -Eq '^Transferred:[[:space:]]+[0-9]+ / [0-9]+'; then
files=$(printf '%s\n' "$clean" |
sed -E 's/^Transferred:[[:space:]]+//')
continue
fi
if printf '%s\n' "$clean" | grep -Eq '^Errors:'; then
errors=$(printf '%s\n' "$clean" |
sed -E 's/^Errors:[[:space:]]+//')
continue
fi
# Ende des Statistikblocks
if printf '%s\n' "$clean" | grep -Eq '^Elapsed time:'; then
elapsed=$(printf '%s\n' "$clean" |
sed -E 's/^Elapsed time:[[:space:]]+//')
[ -n "$bytes" ] || bytes="keine Angabe"
[ -n "$files" ] || files="keine Angabe"
[ -n "$checks" ] || checks="keine Angabe"
[ -n "$deleted" ] || deleted="0 (files), 0 (dirs)"
[ -n "$errors" ] || errors="0"
STATUS_MSG="Quelle: $SRC
Ziel: $DST
Daten: $bytes
Dateien: $files
Prüfungen: $checks
Gelöscht: $deleted
Fehler: $errors
Laufzeit: $elapsed
Stand: $(date '+%d.%m.%Y %H:%M:%S')"
notify_status "$STATUS_MSG"
in_stats=0
fi
done
}
# =============================================================================
# rclone
# =============================================================================
"$RCLONE" sync \
--config "$CONFIG" \
"$SRC" "$DST" \
--track-renames \
--track-renames-strategy modtime,leaf \
--transfers 8 \
--checkers 16 \
--multi-thread-streams 4 \
--multi-thread-cutoff 256M \
--exclude "@eaDir/" \
--exclude "#recycle/" \
--exclude "#snapshot/" \
--exclude "@tmp/" \
--exclude ".DS_Store" \
--exclude "Thumbs.db" \
--stats 5m \
--stats-log-level NOTICE \
--log-level INFO \
2>&1 | status_filter | tee -a "$LOG" "$TMPLOG"
RC=${PIPESTATUS[0]}
# =============================================================================
# Laufzeit
# =============================================================================
END_TS=$(date +%s)
DUR=$((END_TS - START_TS))
DAUER=$(printf '%02d:%02d:%02d' \
$((DUR / 3600)) \
$((DUR % 3600 / 60)) \
$((DUR % 60)))
# =============================================================================
# Exit-Code
# =============================================================================
case $RC in
0) STATUS="OK" ;;
1) STATUS="FEHLER: nicht näher bestimmt" ;;
2) STATUS="FEHLER: Syntax- oder Nutzungsfehler" ;;
3) STATUS="FEHLER: Verzeichnis nicht gefunden" ;;
4) STATUS="FEHLER: Datei nicht gefunden" ;;
5) STATUS="FEHLER: nach Wiederholungsversuchen fehlgeschlagen" ;;
6) STATUS="FEHLER: nicht wiederholbar" ;;
7) STATUS="FEHLER: Abbruch wegen fatalem Problem" ;;
8) STATUS="FEHLER: Transferlimit erreicht" ;;
130) STATUS="ABGEBROCHEN: SIGINT" ;;
143) STATUS="ABGEBROCHEN: SIGTERM" ;;
*) STATUS="FEHLER: unbekannter Code $RC" ;;
esac
# =============================================================================
# Abschlussstatistik
# =============================================================================
S_BYTES=$(
grep -E 'Transferred:[[:space:]]+[0-9.]+ ?[KMGTPE]?i?B' "$TMPLOG" |
tail -n 1 |
sed -E 's/^.*Transferred:[[:space:]]+//'
)
S_FILES=$(
grep -E 'Transferred:[[:space:]]+[0-9]+ / [0-9]+' "$TMPLOG" |
tail -n 1 |
sed -E 's/^.*Transferred:[[:space:]]+//'
)
S_CHECKS=$(
grep -E 'Checks:[[:space:]]+' "$TMPLOG" |
tail -n 1 |
sed -E 's/^.*Checks:[[:space:]]+//'
)
S_DELETED=$(
grep -E 'Deleted:[[:space:]]+' "$TMPLOG" |
tail -n 1 |
sed -E 's/^.*Deleted:[[:space:]]+//'
)
S_ERRORS=$(
grep -E 'Errors:[[:space:]]+' "$TMPLOG" |
tail -n 1 |
sed -E 's/^.*Errors:[[:space:]]+//'
)
S_ELAPSED=$(
grep -E 'Elapsed time:[[:space:]]+' "$TMPLOG" |
tail -n 1 |
sed -E 's/^.*Elapsed time:[[:space:]]+//'
)
[ -n "$S_BYTES" ] || S_BYTES="keine Angabe"
[ -n "$S_FILES" ] || S_FILES="0 / 0"
[ -n "$S_CHECKS" ] || S_CHECKS="0 / 0"
[ -n "$S_DELETED" ] || S_DELETED="0 (files), 0 (dirs)"
[ -n "$S_ERRORS" ] || S_ERRORS="0"
echo "=== Ende $(date) | Exit-Code $RC | $STATUS ===" >> "$LOG"
# =============================================================================
# Abschlussmeldung
# =============================================================================
MSG="Quelle: $SRC
Ziel: $DST
Daten: $S_BYTES
Dateien: $S_FILES
Prüfungen: $S_CHECKS
Gelöscht: $S_DELETED
Fehler: $S_ERRORS
Dauer: $DAUER${S_ELAPSED:+ (rclone: $S_ELAPSED)}
Exit-Code: $RC ($STATUS)"
delete_status
if [ "$RC" -eq 0 ]; then
if [ "$NTFY_ON_SUCCESS" = "1" ]; then
notify \
"Daten-Sync OK ($HOST)" \
3 \
"white_check_mark,floppy_disk" \
"$MSG"
fi
else
ERRLINES=$(
grep -E '(ERROR|CRITICAL)' "$TMPLOG" |
tail -n 5
)
if [ -n "$ERRLINES" ]; then
MSG="$MSG
Letzte Meldungen:
$ERRLINES"
fi
if [ "$RC" -eq 130 ] || [ "$RC" -eq 143 ]; then
notify \
"Daten-Sync ABGEBROCHEN ($HOST)" \
4 \
"stop_sign,warning" \
"$MSG"
else
notify \
"Daten-Sync FEHLGESCHLAGEN ($HOST)" \
5 \
"rotating_light,warning" \
"$MSG"
fi
fi
exit "$RC"
|
Script installieren
Script speichern:
1
|
/volume1/Tools/sync-replica.sh
|
Ausführbar machen:
1
|
chmod 700 /volume1/Tools/sync-replica.sh
|
Manuell testen:
1
|
/volume1/Tools/sync-replica.sh
|
Log parallel ansehen:
1
|
tail -f /volume1/Tools/rclone-sync.log
|
DSM-Aufgabenplaner einrichten
In DSM:
1
2
3
4
5
|
Systemsteuerung
→ Aufgabenplaner
→ Erstellen
→ Geplanter Task
→ Benutzerdefiniertes Skript
|
Als Benutzer wird ein Account benötigt, der Zugriff auf:
- Quelldaten
- rclone-Binary
- rclone-Konfiguration
- SSH-Key
- Log-Verzeichnis
hat.
Als Befehl reicht:
1
|
bash /volume1/Tools/sync-replica.sh
|
Danach den gewünschten Zeitplan festlegen.
Snapshots auf beiden NAS-Systemen
Auf NAS A und NAS B werden unabhängig vom rclone-Sync lokale Snapshots erzeugt.
Damit ergibt sich praktisch folgende Struktur:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
NAS A
┌─────────────────┐
│ aktuelle Daten │
│ + Snapshots │
└────────┬────────┘
│
│ rclone / SFTP
▼
┌─────────────────┐
│ aktuelle Kopie │
│ + Snapshots │
└─────────────────┘
NAS B
|
Damit bleibt auf beiden Seiten eine lokale Snapshot-Historie erhalten, während rclone die eigentliche Replikation übernimmt.
Im konkreten Setup ergibt sich damit funktional der gewünschte Nutzen der ursprünglichen Snapshot-Replication-Idee, aber mit deutlich höherer beobachteter Übertragungsrate.
Fazit
Ausgangspunkt war eine einfache Anforderung:
Daten von Synology NAS A nach Synology NAS B replizieren
Snapshot Replication brachte alles dafür mit, war mir mit ~6 MB/s aber deutlich zu langsam. Auch rsync war ähnlich 🐌-lahm.
Mit rclone und parallelen Transfers waren dagegen Werte von ~40 MB/s möglich.
Das fertige Setup ergänzt rclone um die Funktionen, die für einen dauerhaften DSM-Job praktisch sind:
flock gegen parallele Läufe
- Live-Logging mit
tee
- Logrotation
- SFTP als Transport
- Rename-Erkennung mit
modtime,leaf
- Statistik alle fünf Minuten via
ntfy.sh
- separate Abschlussmeldung
- Fehlerauswertung
- Behandlung von SIGINT und SIGTERM
Damit übernimmt rclone die schnelle Replikation, während die Snapshot-Historie weiterhin lokal auf beiden Synology-Systemen geführt wird.