最近重新整理了 mail server,改用 zfs 做存 mail 的 file system,也重新調整了備份機制。
現在是透過 zfs snapshot 做資料備份,一小時打一次 snapshot 後丟到其他地方存著。
下面是參考這裡調整後的 script。
#!/bin/sh
# take the appropriately named snapshot
create_snapshot()
{
# enumerate datasets under this pool or dataset, skip excluded datasets if requested
datasets=$(zfs list -r -H -o name $pool)
# loop through datasets, do snapshots of each
for dataset in $datasets; do
snapshot="$dataset@$now"
# look for an existing snapshot with this name
if zfs list $snapshot > /dev/null 2>&1; then
echo " snapshot $snapshot already exists, skipping..."
else
# echo " taking snapshot: $snapshot"
zfs snapshot $snapshot
fi
done
}
# delete the named snapshot
delete_snapshot()
{
snapshot=$1
# echo " destroying old snapshot, $snapshot"
zfs destroy -r $snapshot
}
# backup_snapshot
backup_snapshot()
{
# enumerate datasets under this pool or dataset, skip excluded datasets if requested
datasets=$(zfs list -r -H -o name $pool)
# loop through datasets, do snapshots of each
for dataset in $datasets; do
snapshot="$dataset@$now"
# look for an existing snapshot with this name
zfs send $snapshot | gzip > $dest/$now.gz
done
}
# take a type snapshot of pool, keeping keep old ones
do_pool()
{
pool=$1
keep=$2
type=$3
dest=$4
# create the regex matching the type of snapshots we're currently working
# on
case "$type" in
hourly)
# hourly-2009-01-01-00
regex="^$pool@$type-[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]-[0-9][0-9]$"
;;
daily)
# daily-2009-01-01
regex="^$pool@$type-[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]$"
;;
weekly)
# weekly-2009-01
regex="^$pool@$type-[0-9][0-9][0-9][0-9]-[0-9][0-9]"
;;
monthly)
# monthly-2009-01
regex="^$pool@$type-[0-9][0-9][0-9][0-9]-[0-9][0-9]"
;;
*)
echo "unknown snapshot type: $type"
exit 1
esac
case "$type" in
hourly)
now=`date +"$type-%Y-%m-%d-%H"`
;;
daily)
now=`date +"$type-%Y-%m-%d"`
;;
weekly)
now=`date +"$type-%Y-%U"`
;;
monthly)
now=`date +"$type-%Y-%m"`
;;
*)
echo "unknown snapshot type: $type"
exit 1
esac
create_snapshot $pool $type $now
backup_snapshot $pool $type $now $dest
# get a list of all of the snapshots of this type sorted alpha, which
# effectively is increasing date/time
# (using sort as zfs's sort seems to have bugs)
snapshots=`zfs list -H -o name -t snapshot | sort | grep $regex`
# count them
count=`echo $snapshots | wc -w`
if [ $count -ge 0 ]; then
# how many items should we delete
delete=`expr $count - $keep`
count=0
# walk through the snapshots, deleting them until we've trimmed deleted
for snapshot in $snapshots; do
if [ $count -ge $delete ]; then
break
fi
delete_snapshot $snapshot
count=`expr $count + 1`
done
fi
}
# take snapshots of type, for pools, keeping keep old ones,
do_snapshots()
{
pools=$1
keep=$2
type=$3
dest=$4
# echo ""
# echo "Doing zfs $type snapshots:"
for pool in $pools; do
do_pool $pool $keep $type $dest
done
}
# Function to display usage:
usage() {
scriptname=`/usr/bin/basename $0`
echo "$scriptname: Take and rotate snapshots on a ZFS file system"
echo
echo " Usage:"
echo " $scriptname target perodic count dest"
echo
echo " target: ZFS file system to act on"
echo " type: hourly/daily/weekly/monthly"
echo " count: Number of snapshots with perodic keep at one time"
echo " dest: Destination of snapshot backup"
echo
exit
}
TARGET=$1
TYPE=$2
COUNT=$3
DEST=$4
# Basic argument checks:
if [ -z $TYPE ] ; then
usage
fi
if [ ! -z $5 ] ; then
usage
fi
do_snapshots "$TARGET" $COUNT $TYPE $DEST
假設把 script 丟 /usr/local/sbin/zfs-snapshot,然後用 crontab 來做自動備份
想要 hourly 備份一次,把 snapshot gzip 後丟到 /backup 下,且在 zfs 上最多留 24 份 hourly snapshot
1 * * * * root /usr/local/sbin/zfs-snapshot ZPOOL hourly 24 /backup > /dev/null 2>&1
想要 daily 備份一次,把 snapshot gzip 後丟到 /backup 下,且在 zfs 上最多留 7 份 daily snapshot
1 * * * * root /usr/local/sbin/zfs-snapshot ZPOOL daily 7 /backup > /dev/null 2>&1
想要 weekly 備份一次,把 snapshot gzip 後丟到 /backup 下,且在 zfs 上最多留 4 份 weekly snapshot
1 * * * * root /usr/local/sbin/zfs-snapshot ZPOOL weekly 4 /backup > /dev/null 2>&1
想要 monthly 備份一次,把 snapshot gzip 後丟到 /backup 下,且在 zfs 上最多留 6 份 monthly snapshot
1 * * * * root /usr/local/sbin/zfs-snapshot ZPOOL monthly 6 /backup > /dev/null 2>&1
當然,再稍加修改一下還可以有更彈性的做法,例如加密後丟上 S3 之類的…
不過因為我們家 mail server 的資料量太大,所以沒有這樣搞…