最近重新整理了 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 的資料量太大,所以沒有這樣搞…