脚本功能:
- 恢复时,需要指定备份的 DB_NAME 和备份日期;
- 恢复失败时,发送企业微信告警;
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
| #!/bin/bash
DB_NAME=$1; TS=$2
DB_TYPE="mariadb"
DB_VERSION="10.1.46"
STREAM_TOOL="mbstream"
BACKUP_TOOL="mariabackup"
SYSTEMD_UNIT="mariadb.service"
DECOMPRESS_PATH="/data/decompress"
RESTORE_EXTRA_ARGS="--apply-log-only"
CONF_FOO_PATH="/etc"
CONF_FILES=("$CONF_FOO_PATH/my.cnf" "$CONF_FOO_PATH/my.cnf.d/*.cnf")
_result_datadir=$(grep -s '^datadir' ${CONF_FILES[@]} | awk -F[=\ ] '{print $NF}' | sort -u)
OLD_MYSQL_DATA_PATH=${_result_datadir:-'/var/lib/mysql'}
CPU_CORES=$(grep processor /proc/cpuinfo -c)
HALF_MEM=$(awk '/^MemTotal/{print int($2/1024/1024+0.9)*1024/2"M"}' /proc/meminfo)
RCLONE="/usr/local/bin/rclone"
RCLONE_REMOTE="huawei:backup-bucket/mysql"
WECHAT_WEBHOOK_KEY="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
LAN_IP=$(hostname -I | awk '{print $1}')
[[ $# != 2 ]] && echo -e "Usage:\n\t$0 (备份库名) (时间节点)" && exit 1
raise_error() {
msg="### 恢复失败! \n#### $DB_NAME $TS $BACKUP_TYPE\n#### $1"
for i in {1..3}; do
curl -s "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=$WECHAT_WEBHOOK_KEY" \
-H "Content-Type: application/json" \
-d '{
"msgtype": "markdown",
"markdown": {
"content": "'"$msg"'"
}
}'
[[ $? == 0 ]] && break || sleep $i
done
echo "$msg"
exit 1
}
REMOTE_BACKUP_FILES=$($RCLONE lsf $RCLONE_REMOTE | grep "$DB_NAME-.*\.gz")
_ts=$TS
file_list=()
for ((i=1;i<=14;i++)); do
if echo "$REMOTE_BACKUP_FILES" | grep -q "$DB_NAME-$_ts-full.tar.gz"; then
file_list+=("$DB_NAME-$_ts-full.tar.gz")
break
elif echo "$REMOTE_BACKUP_FILES" | grep -q "$DB_NAME-$_ts-incr.gz"; then
file_list+=("$DB_NAME-$_ts-incr.gz")
fi
_ts=$(date -d"$_ts -1 day" "+%Y%m%d")
done
[[ "${file_list[@]}" =~ "full.tar.gz" ]] || raise_error '缺失full.tar.gz全量备份文件'
read -t5 -n1 -p "即将终止mysqld进程并清空$DECOMPRESS_PATH及$OLD_MYSQL_DATA_PATH目录,请确认 (5s后默认为Y) [Y/n]: " choice
choice=${choice:-Y}
echo ""
case $choice in
Y|y)
systemctl stop "$SYSTEMD_UNIT"
rm -rf $OLD_MYSQL_DATA_PATH/* $DECOMPRESS_PATH/*
rm -f ${CONF_FILES[@]}
;;
N|n)
exit 0
;;
*)
raise_error "选项错误,仅支持 [Y/y/N/n]"
;;
esac
ulimit -n 1024000
$RCLONE cat $RCLONE_REMOTE/$DB_NAME-$TS-conf.tgz | tar -xz -C $CONF_FOO_PATH
#sed -i "/^server[-_]id/c server_id = $(awk -F. '{print $3$4}' <<< $LAN_IP)" ${CONF_FILES[@]}
sed -i "/^server[-_]id/c server_id = $(awk -F. '{print $4}' <<< $LAN_IP)" ${CONF_FILES[@]}
[[ $(grep -i '^port' ${CONF_FILES[@]} | awk -F'[= ]' '{print $2}' | sort -un | head -n1) != 106* ]] && \
sed -i "/^innodb[-_]buffer[-_]pool[-_]size/c innodb_buffer_pool_size = $HALF_MEM" ${CONF_FILES[@]}
_result_datadir=$(grep '^datadir' ${CONF_FILES[@]} | awk -F[=\ ] '{print $NF}' | sort -u)
NEW_MYSQL_DATA_PATH=${_result_datadir:-'/var/lib/mysql'}
[[ -e $NEW_MYSQL_DATA_PATH ]] && rm -rf $NEW_MYSQL_DATA_PATH/* || mkdir -p $NEW_MYSQL_DATA_PATH
STREAM_PIDLIST=()
PERPARE_PIDLIST=()
function twait () { tail --pid=$1 -f /dev/null; }
for ((index=${#file_list[*]}-1; index>=0; index--)); do
filename=${file_list[$index]}
[[ $index == 0 ]] && unset RESTORE_EXTRA_ARGS
if [[ $filename =~ full.tar.gz$ ]]; then
($RCLONE cat $RCLONE_REMOTE/$filename | gzip -d -c | $STREAM_TOOL -x -C "$NEW_MYSQL_DATA_PATH") &
STREAM_PIDLIST+=("$!")
(twait ${STREAM_PIDLIST[-1]}; \
$BACKUP_TOOL --prepare --target-dir="$NEW_MYSQL_DATA_PATH" $RESTORE_EXTRA_ARGS --parallel=$CPU_CORES --use-memory=$HALF_MEM) &
PERPARE_PIDLIST+=("$!")
else
decompress_tmp_dir="$DECOMPRESS_PATH/$(basename $filename .gz)"; mkdir -p "$decompress_tmp_dir"
(twait ${STREAM_PIDLIST[-1]}; $RCLONE cat $RCLONE_REMOTE/$filename | gzip -d -c | $STREAM_TOOL -x -C "$decompress_tmp_dir") &
STREAM_PIDLIST+=("$!")
(twait ${PERPARE_PIDLIST[-1]}; twait ${STREAM_PIDLIST[-1]}; \
$BACKUP_TOOL --prepare --target-dir="$NEW_MYSQL_DATA_PATH" $RESTORE_EXTRA_ARGS --incremental-dir="$decompress_tmp_dir" --parallel=$CPU_CORES --use-memory=$HALF_MEM) &
PERPARE_PIDLIST+=("$!")
fi
done
wait ${STREAM_PIDLIST[@]} ${PERPARE_PIDLIST[@]} || raise_error "合并失败"
id -u mysql >/dev/null 2>&1 || useradd mysql
chown -R mysql:mysql $NEW_MYSQL_DATA_PATH
systemctl start "$SYSTEMD_UNIT" || raise_error "启动数据库失败"
echo "恢复成功!"
|