Monday, August 15, 2011

How to create ZFS storage in FreeBSD 7.4

1. Edit /etc/rc.conf. Add
zfs_enable="YES"

2. Shutdown machine and plug all hard drives.

3. Create storage pool
#   zpool create PoolName raidz ad1 ad2 ad3 ...

4. Create volume
# zfs create PoolName/VolumeName

5. Set mount point
# zfs set mountpoint=/Path/To/Mount/Point PoolName/VolumeName

6. Setup daily check
# echo 'daily_status_zfs_enable="YES"' >> /etc/periodic.conf

7. Setup volume compression
# zfs set compression=gzip PoolName/VolumeName

8. Check ZFS pool status
# zpool status

9. Check ZFS command history
# zpool history

10. Check ZFS mounting point
# zfs get mountpoint

11. Setup volume quota
# zfs set quota=QuotaSize PoolName/VolumeName

12. Show volume setting
# zfs get all PoolName/VolumeName

13. Show ZFS I/O status
# zfs iostat 1

Sunday, August 14, 2011

一些數學公式

r : 表示圓半徑
圓周長 2πr

圓面積 πr^2

圓球體積 4/3*πr^3
x : 表示離圓心的距離
y : 表示圓球表面到球中心軸的距離
x^2 + y^2 = r^2
=> y^2 = r^2 - x^2
=> πy^2 = π(r^2 - x^2)
圓球 V = 2 * ∫πy^2  (0..r) = 2 * ∫π(r^2 - x^2) =  2 * (∫πr^2 - ∫πx^2) = 2πr^3 - 1/3*πr^3 = 4/3*πr^3

圓柱體積 πhr^2
h : 表示圓柱高度

圓錐體積 1/3*πhr^2
θ : 表示圓錐尖端夾角的一半
tanθ = r/h
x : 表示距離圓錐尖端的距離
y : 表示 x 位置的圓半徑
y = x * tanθ = xr/h = rx/h
圓錐 V = ∫πy^2  (0..h) = ∫π(rx/h)^2 = ∫(πr^2/h^2)*x^2 = (πr^2/h^2)*∫x^2 = (πr^2/h^2)* 1/3 * h^3
= 1/3*πhr^2

煙囪體積 1/3*πh*((w+y+z+x)^2-(y+x)^2-wz-wx-yz)
x : 表示煙囪頂內緣半徑
y : 表示煙囪底內緣半徑
z : 表示煙囪頂厚度
w : 表示煙囪底厚度

計算一 : 內圓錐體積 1/3*πh*(y^2+xy+x^2)
假設將內圓錐補到完整, 需要加上 a 長度的圓錐
內圓錐 V = 1/3*πy^2*(a+h) - 1/3*πx^2*a = 1/3*π(y^2-x^2)*a + 1/3*πy^2*h
= 1/3*πh*((y^2-x^2)x/(y-x) + y^2) = 1/3*πh*((y^2-x^2)x + (y-x)*y^2)/(y-x)
= 1/3*πh*(xy^2-x^3+y^3-xy^2)/(y-x) = 1/3*πh*(y^3-x^3)/(y-x)
= 1/3*πh*(y-x)(y^2+xy+x^2)/(y-x) = 1/3*πh*(y^2+xy+x^2)

計算二 : 外圓錐體積 1/3*πh*((w+y)^2+(w+y)(z+x)+(z+x)^2)
w+y : 表示煙囪底外緣半徑
z+x : 表示煙囪頂外緣半徑

計算三 : 煙囪體積 1/3*πh*((w+y+z+x)^2-(y+x)^2-wz-wx-yz)
煙囪 V = 1/3*πh*((w+y)^2+(w+y)(z+x)+(z+x)^2) - 1/3*πh*(y^2+xy+x^2)
= 1/3*πh*(((w+y)^2+(w+y)(z+x)+(z+x)^2) - (y^2+xy+x^2))
= 1/3*πh*(((w+y)+(z+x))^2-(w+y)(z+x)-((y+x)^2-xy))
= 1/3*πh*((w+y+z+x)^2-wz-wx-yz-xy-(y+x)^2+xy)
= 1/3*πh*((w+y+z+x)^2-(y+x)^2-wz-wx-yz)

Saturday, August 13, 2011

使用 crontab 管理 ZFS snapshot

近期終於將之前延遲已久的 ZFS storage 計畫實現. 已試過當 raidz 硬碟發生問題時, 使用 zfs replace 更換硬碟. 當然就會想用 snapshot 這個重要的功能. 所以就動手寫了簡單的 shell script 搭配 crontab 做自動化管理.

1. 簡單指令
觀察 zpool 清單, 狀態
   # zpool list
   # zpool status

   觀察 ZFS volume 清單
   # zfs list

   觀察 snapshot 清單 (/usr/ports/sysutils/freebsd-snapshot)
   # snapshot list

2. shell script
#!/usr/local/bin/bash

PATH=$PATH

LOGFILE="/var/log/snapshotfs.log"
TODAY=`date +"%Y%m%d"`
CHKPARA=0

if [ -n "$1" ]; then
 fstype="$1"
 shift
else
 CHKPARA=1
fi


if [ -n "$1" ]; then
 sstype="$1"
 shift
else
 CHKPARA=1
fi


if [ -n "$1" ]; then
 maxnum="$1"
 shift
else
 CHKPARA=1
fi


if [ -n "$1" ]; then
 volpath="$1"
 shift
else
 CHKPARA=1
fi

if [ $CHKPARA -eq 1 ]; then
 echo "Usage: $0 fstype sstype maxnum /filesystem|volume_path"
 echo "Example: $0 zfs [H|D|W|M|Q|Y] 7 /databackup/backup"
 exit 1
else
 touch $LOGFILE
 echo `date +"%Y/%m/%d %H:%M:%S"` >> $LOGFILE
 echo "$0 $fstype $sstype $maxnum $volpath" >> $LOGFILE
 echo "Check parameters for taking a snapshot of $volpath($fstype)." >> $LOGFILE
fi

if [ -d $volpath ]; then
 if [ $fstype = 'zfs' ]; then
  if [ -d $volpath/.zfs/snapshot ]; then
   echo "Check path : OK" >> $LOGFILE
  else
   echo "Check path : Failed, snapshot folder does not exist." >> $LOGFILE
   exit 1
  fi
 elif [ $fstype = 'ufs' ]; then
  if [ -d $volpath/.snap ]; then
   echo "Check path : OK" >> $LOGFILE
  else
   echo "Check path : Failed, snapshot folder does not exist." >> $LOGFILE
   exit 1
  fi
 else
  echo "Unsupported file system $fstype" >> $LOGFILE
  exit 1
 fi
else
 echo "Check path : Failed, filesystem|volume_path does not exist." >> $LOGFILE
 exit 1
fi

if [ $maxnum -gt 0 ]; then
 echo "Check maxnum : OK" >> $LOGFILE
else
 echo "Check maxnum : Failed, must input positive integer." >> $LOGFILE
        exit 1
fi

if [ $fstype = 'zfs' ]; then
 echo "ZFS" >> $LOGFILE

 case $sstype in
 H)  echo "Hourly Snapshot" >> $LOGFILE
   TODAY=`date +"%Y%m%d%H"`
   ;;
 D)  echo "Daily Snapshot" >> $LOGFILE
   ;;
 W)  echo "Weekly Snapshot" >> $LOGFILE
   ;;
 M)  echo "Monthly Snapshot" >> $LOGFILE
   ;;
 Q)  echo "Quaterly Snapshot" >> $LOGFILE
   ;;
 Y)  echo "Yearly Snapshot" >> $LOGFILE
   ;;
 *)  echo "sstype must be H | D | W | M | Q | Y " >> $LOGFILE
   exit 1
 esac

 #Snapshot
 if [ -d $volpath/.zfs/snapshot/$sstype$TODAY ]; then
  echo "Had snapshot($volpath $sstype$TODAY)." >> $LOGFILE
 else
  echo "Take a snapshot of $volpath." >> $LOGFILE
  zfs snapshot `zfs list -H -o name ${volpath}`@${sstype}${TODAY}
 fi

 #Remove more old snapshot

 KEEPSSNUM=$maxnum
 REALSSNUM=`ls $volpath/.zfs/snapshot/ | grep $sstype | wc -l`
 RMSSNUM=`expr $REALSSNUM - $KEEPSSNUM`
 RMSSID=""

 if [ $RMSSNUM -gt 0 ]; then
  for RMSSID in `ls $volpath/.zfs/snapshot/ | grep $sstype | sort -n | head -n $RMSSNUM | sed -e 's/\///'`
  do
   if [ -d $volpath/.zfs/snapshot/$RMSSID ]; then
    echo "Remove old snapshot($volpath $RMSSID)." >> $LOGFILE
    zfs destroy `zfs list -H -o name ${volpath}`@$RMSSID
   else
    echo "Old snapshot($volpath $RMSSID) does not exist." >> $LOGFILE
   fi
  done
 fi

elif [ $fstype = 'ufs' ]; then
 echo "UFS" >> $LOGFILE

 case $sstype in
 H) echo "Hourly Snapshot" >> $LOGFILE
  sskey='Hourly'
  ;;
 D) echo "Daily Snapshot" >> $LOGFILE
  sskey='Daily'
  ;;
 W) echo "Weekly Snapshot" >> $LOGFILE
  sskey='Weekly'
  ;;
 M) echo "Monthly Snapshot" >> $LOGFILE
  sskey='Monthly'
  ;;
 Q) echo "Quaterly Snapshot" >> $LOGFILE
  sskey='Quaterly'
  ;;
 Y) echo "Yearly Snapshot" >> $LOGFILE
  sskey='Yearly'
  ;;
 *) echo "sstype must be H | D | W | M | Q | Y " >> $LOGFILE
  exit 1
 esac
 
 #Snapshot
 echo "Take a snapshot UFS ${volpath}" >> $LOGFILE
 /usr/local/sbin/snapshot make -g${maxnum} ${volpath}:${sskey}
else
 echo "Unsupported file system $fstype" >> $LOGFILE
fi
3. crontab 排程自動化

### ZFS snapshot
### Hourly
45      *       *       *       *       root    /PATH/TO/zfs_snapshot_hourly.sh
### 3 Hourly
50      */3     *       *       *       root    /PATH/TO/zfs_snapshot_3hourly.sh
### Daily
0       23      *       *       *       root    /PATH/TO/zfs_snapshot_daily.sh
### Weekly
20      23      *       *       1       root    /PATH/TO/zfs_snapshot_weekly.sh
### Monthly
40      23      1       *       *       root    /PATH/TO/zfs_snapshot_monthly.sh
### Quaterly
53      23      1       1,4,7,10        *       *       root    /PATH/TO/zfs_snapshot_quaterly.sh
### Yearly
55      23      31      12      *       root    /PATH/TO/zfs_snapshot_yearly.sh


#!/usr/local/bin/bash

PATH=$PATH

### ZFS snapshot               SSTYPE SSCOUNT
### H for hourly or 3hourly ex: H 8
### D for daily             ex: D 7
### W for weekly            ex: W 4
### M for monthly           ex: M 6
### Q for quaterly          ex: Q 4
### Y for yearly            ex: Y 3

/root/root_scripts/snapshotfs.sh zfs SSTYPE SSCOUNT /zfs-volumn/path1
/root/root_scripts/snapshotfs.sh zfs SSTYPE SSCOUNT /zfs-volumn/path2
/root/root_scripts/snapshotfs.sh zfs SSTYPE SSCOUNT /zfs-volumn/path3