|
1 | 1 | #!/bin/bash |
2 | | - |
3 | | -# заглушка, т.к. для archive_mode = 'on' требуется перезагрузка СУБД |
| 2 | + |
| 3 | +# заглушка, т.к. при изменении значения параметра archive_mode требуется перезагрузка СУБД |
4 | 4 | # exit 0 |
5 | | - |
6 | | -# проверяем, скрипт должен запускаться с двумя параметрами |
| 5 | + |
| 6 | +function log() { |
| 7 | + # echo $(date --rfc-3339=ns) $(hostname -s) $(basename "$SRC_FILE") "$1" &>> "$WAL_DIR/archive_wal.log" |
| 8 | + return 0 |
| 9 | +} |
| 10 | + |
| 11 | +WAL_DIR="/mnt/backup_db/archive_wal/cluster" |
| 12 | +SRC_FILE="$2" # откуда будем читать WAL файл |
| 13 | +DST_FILE="$WAL_DIR/$1.zst" # куда будем сохранять WAL файл |
| 14 | +LOCK_FILE="$WAL_DIR/$1.lock" # этот файл создаётся перед архиваций WAL файла и удаляется после |
| 15 | + |
| 16 | +log "check" |
| 17 | + |
| 18 | +# скрипт должен запускаться с двумя параметрами |
7 | 19 | test "$#" -ne 2 && echo "Error: 2 number of parameters expected, $# given" >&2 && exit 2 |
8 | | - |
9 | | -FILE_SRC="$2" |
10 | | -FILE_DST="/mnt/backup_db/archive_wal/cluster/$1.zst" |
11 | | - |
12 | | -test ! -f "$FILE_SRC" && echo "Error: file '$FILE_SRC' does not exist!" >&2 && exit 1 |
13 | | -test -f "$FILE_DST" && exit |
14 | | - |
| 20 | +test ! -f "$SRC_FILE" && echo "Error: WAL file '$SRC_FILE' does not exist!" >&2 && exit 1 |
| 21 | +test -f "$DST_FILE" && test ! -f "$LOCK_FILE" && log "exists" && exit 0 |
| 22 | + |
| 23 | +log "does not exist" |
| 24 | + |
| 25 | +: <<'COMMENT' |
| 26 | + Для надёжности архивирование WAL файлов могут настроить на мастере и репликах через параметр archive_mode=always. |
| 27 | + Запрещаем от разных экземпляров СУБД конкурентную запись WAL файлов в общие сетевые папки. |
| 28 | + Например, в основном и резервном ЦОДе могут быть разные сетевые папки. |
| 29 | + Дополнительные файлы и проверки нужны для решения проблемы переполнения диска или недоступности сетевого соединения, |
| 30 | + когда WAL файл может не записаться совсем или записаться только частично. |
| 31 | +COMMENT |
| 32 | + |
| 33 | +SRV_FILE="$WAL_DIR/archive_server.$(hostname -s)" # сервер, на котором планируется архивирование WAL файла |
| 34 | +touch -m "$SRV_FILE" || exit # создаём файл или обновляем дату модификации файла |
| 35 | + |
| 36 | +# разрешаем архивацию WAL файла только при наличии жёстких связанных ссылок (единый inode) между файлами $SRV_FILE и $LOCK_FILE |
| 37 | +# для отладки и просмотра кол-ва жёстких ссылок на файл используйте утилиту stat (не используйте ls, она кеширует информацию) |
| 38 | +if ln -T "$SRV_FILE" "$LOCK_FILE" &> /dev/null; then |
| 39 | + # если удалось создать файл $LOCK_FILE, то только этот (основной) процесс будет архивировать WAL файл (первая попытка) |
| 40 | + log "locked now" |
| 41 | +elif test "$SRV_FILE" -ef "$LOCK_FILE"; then |
| 42 | + # если файлы имеют одинаковый inode, то только этот (основной) процесс будет архивировать WAL файл (повторная попытка) |
| 43 | + log "locked already" |
| 44 | +else |
| 45 | + # иначе архивировать WAL файл пытается конкурирующий процесс, ждём несколько секунд завершения работы основного процесса |
| 46 | + for i in {1..50}; do |
| 47 | + log "waiting i=$i" |
| 48 | + sleep 0.2 |
| 49 | + test -f "$DST_FILE" && test ! -f "$LOCK_FILE" && log "appeared" && exit 0 |
| 50 | + done |
| 51 | + # не дождались, значит основной процесс сломался, WAL файл мог сохраниться только частично |
| 52 | + # передаём управление другому конкурирующему процессу, который станет основным (при повторном вызове этого скрипта) |
| 53 | + rm -f "$DST_FILE" && rm -f "$LOCK_FILE" # очерёдность удаления файлов важна |
| 54 | + MESSAGE="waiting timeout, deleted, unlocked" |
| 55 | + log "$MESSAGE" |
| 56 | + echo "Error: WAL file '$DST_FILE' $MESSAGE" >&2 |
| 57 | + exit 1 |
| 58 | +fi |
| 59 | + |
15 | 60 | # кол-во потоков сжатия |
16 | 61 | ZSTD_THREADS=$(echo "$(nproc) / 4 + 1" | bc) |
17 | | - |
18 | | -# кол-во файлов в очереди на архивирование |
19 | | -ARCHIVE_STATUS_DIR=$(dirname $FILE_SRC)/archive_status |
| 62 | + |
| 63 | +# подсчитываем кол-во WAL файлов в очереди на архивирование |
| 64 | +ARCHIVE_STATUS_DIR=$(dirname "$SRC_FILE")/archive_status |
20 | 65 | WAL_FILES_QUEUE=$(find "$ARCHIVE_STATUS_DIR" -maxdepth 1 -type f -name "*.ready" -printf "." | wc --bytes) |
21 | | - |
22 | | -# чем больше файлов в очереди, тем меньше степень сжатия (но больше скорость сжатия и размер сжатого файла) |
23 | | -STEP=3 |
| 66 | + |
| 67 | +STEP=2 |
| 68 | +# чем больше WAL файлов в очереди, тем меньше степень сжатия (но больше скорость сжатия и размер сжатого файла) |
24 | 69 | # не ставьте большой уровень компрессии, это приводит к большому потреблению CPU, а экономия на размере файла несущественная |
25 | 70 | ZSTD_LEVEL=$(echo "(9 * ${STEP} - ${WAL_FILES_QUEUE}) / ${STEP}" | bc) |
26 | 71 | test "$ZSTD_LEVEL" -lt 1 && ZSTD_LEVEL=1 |
27 | | - |
28 | | -# архивируем файл |
| 72 | + |
| 73 | +# архивируем WAL файл |
29 | 74 | # в zstd без флага -B1M используются не все ядра (из-за небольшого размера файла?) |
30 | | -# в zstd флаг -f использовать нельзя, т.к. если файл существует, то должна быть ошибка (защита от дурака от перезаписи нужного файла) |
31 | | -ionice -c2 -n7 nice -n19 zstd -q -${ZSTD_LEVEL} -T${ZSTD_THREADS} -B1M "$FILE_SRC" -o "$FILE_DST" |
| 75 | +ionice -c2 -n7 -- nice -n19 -- zstd -q -f -${ZSTD_LEVEL} -T${ZSTD_THREADS} -B1M "$SRC_FILE" -o "$DST_FILE" \ |
| 76 | + && rm -f "$LOCK_FILE" && log "saved, unlocked" |
0 commit comments