半自動化運維之動態新增資料檔案(一)

jeanron100發表於2015-06-02
在測試環境中,伺服器和資料庫例項真是多得數不勝數,自己也沒有下意識去記住那個資料庫例項在哪個伺服器上,都是出了問題直接連過去解決。
這麼多的資料庫例項需要管理,表空間的監控是極為重要的,一般來說都會在給表空間設定一個閥值,比如說表空間剩餘10%,20%等等,超出了閥值就會自動傳送郵件,提醒DBA去做相應的處理,表空間監控如此,檔案系統監控也是類似的思路。
最近處理了一些緊急的問題,看似是很小的問題,但是比較折騰人,比如說表空間超出了閥值,就會傳送警告郵件,這個時候DBA就會連過去,處理問題的思路就是新增資料檔案,這個時候就得考慮檔案系統的空間情況。
比如有下面10個掛載點。
/u01,/u02,/u03....., /u10, 資料檔案被打散分佈在這幾個掛載點上,如果對於資料檔案的位置沒有嚴格的要求,就是希望把資料檔案分散分佈,這個時候處理的思路就是使用df -k來得到對應的掛載點資訊,然後在其中選擇一個合適的,建立資料檔案,僅此而已。
但是這個過程如果細細來看,確實是沒有太多技術含量的,而且手動處理液不夠及時,能不能傳送了警告郵件,然後在資料庫層面建立資料檔案,可以在DBA稍後進行驗證,這樣問題處理也很及時,也不用DBA來總是手工處理這種看似緊急的問題。這也就是我為什麼說是半自動化運維的一個思路。
解釋了一通,來個圖看看可能就更清楚了。
下面就是一些掛載點,在不同的伺服器上會有所不同,在監控的時候如果需要新增資料檔案,就需要儘量把資料檔案分散到這些掛載點上,可以使用hash或者random的方式。

當然要實現也是看起來容易,做起來難。
先來看看錶空間監控的部分,我們先來看看錶空間監控的部分是怎麼寫的,在後續的章節補充是怎麼新增資料檔案的。
這個指令碼依賴於一個配置檔案。就是需要提供資料庫例項名和主機名,像下面的形式,資料庫TEST11G在主機oel1上。
$ cat master_sid.lst
TEST11G oel1
DG11G oel1


LOG_DIR=/home/ora11g/logs
DAY=`date +%d-%m-%Y:%H:%M" CST"`
HOST=`hostname`
SCRIPTNAME=free_tbs_alert.ksh
SCR_DIR=/home/ora11g/sid_list      --配置檔案的路徑
TARGET_CONN=n1/n1
export PATH=$ORACLE_SID/bin:$PATH
cp /dev/null $LOG_DIR/${1}_${SCRIPTNAME}_final_report_free_tablespace
cp /dev/null $LOG_DIR/${1}_${SCRIPTNAME}_final_report_free_tablespace.new
cp /dev/null $LOG_DIR/${1}_${SCRIPTNAME}_tablespace.alert

##MAIN
for SID in ` cat $SCR_DIR/master_sid.lst |grep -v "^\#"|awk '{print $1}'`
do
_hst=`grep -iw $SID $SCR_DIR/master_sid.lst |grep -v "^\#"|awk '{ print $2}'`


#if [ `grep -iw $_hst $SCR_DIR/maint_hosts| wc -l ` -eq 0 ]
#then
$ORACLE_HOME/bin/sqlplus -s /nolog << EOF
conn  ${TARGET_CONN}@$SID
set feed off head off 
set linesize 65
set pagesize 0
col TABLESPACE_NAME format a15
col "USED (MB)" format a12
col "FREE (MB)" format a10
col "PER_FREE (MB)" format a17
col "TOTAL (MB)" format a12
spool $LOG_DIR/${1}_${SCRIPTNAME}_tablespace.alert
SELECT F.TABLESPACE_NAME,
TO_CHAR ((T.TOTAL_SPACE - F.FREE_SPACE),'999999') "USED (MB)",
TO_CHAR (F.FREE_SPACE, '999999') "FREE (MB)",
TO_CHAR (T.TOTAL_SPACE, '999999') "TOTAL (MB)",
TO_CHAR ((ROUND ((F.FREE_SPACE/T.TOTAL_SPACE)*100)),'999')||' %' PER_FREE
FROM (SELECT TABLESPACE_NAME,
ROUND (SUM (BLOCKS*(SELECT VALUE/1024 FROM V\$PARAMETER
WHERE NAME = 'db_block_size')/1024)) FREE_SPACE
FROM DBA_FREE_SPACE
GROUP BY TABLESPACE_NAME) F,
(SELECT TABLESPACE_NAME,
ROUND (SUM (BYTES/1048576)) TOTAL_SPACE
FROM DBA_DATA_FILES
GROUP BY TABLESPACE_NAME) T
WHERE F.TABLESPACE_NAME = T.TABLESPACE_NAME
AND (ROUND ((F.FREE_SPACE/T.TOTAL_SPACE)*100)) < 10;
spool off
/
prompt
exit
EOF
#fi

HOST1=`$ORACLE_HOME/bin/tnsping $SID | tr -d " "|tr 'A-Z' 'a-z'|grep host |awk -F "host=" ' { print $2} '| awk -F ")" '{ print $1}'`

if [[ `cat $LOG_DIR/${1}_${SCRIPTNAME}_tablespace.alert|wc -l` -gt 0 && `grep ORA- $LOG_DIR/${1}_${SCRIPTNAME}_tablespace.alert|wc -l` -lt 1 ]]
then
cp /dev/null $LOG_DIR/${1}_${SCRIPTNAME}_free_tablespace.tmp
grep "%" $LOG_DIR/${1}_${SCRIPTNAME}_tablespace.alert|awk '{ print $3}'|sort|
while read _freeMB
do
if [[ $_freeMB -lt 2048 ]]
then
grep "%" $LOG_DIR/${1}_${SCRIPTNAME}_tablespace.alert|grep -w $_freeMB >> $LOG_DIR/${1}_${SCRIPTNAME}_free_tablespace.tmp
fi
done


cp /dev/null $LOG_DIR/${1}_${SCRIPTNAME}_free_tablespace.tmp1
#if [ `cat $LOG_DIR/${1}_${SCRIPTNAME}_free_tablespace.tmp |wc -l ` -gt 0 ]
if [ `cat $LOG_DIR/${1}_${SCRIPTNAME}_free_tablespace.tmp |grep -iv "UNDO" |wc -l ` -gt 0 ]
then 
echo "DB Name: $SID          Host: $HOST1" >> $LOG_DIR/${1}_${SCRIPTNAME}_free_tablespace.tmp1
cat $LOG_DIR/${1}_${SCRIPTNAME}_free_tablespace.tmp|sort -u >> $LOG_DIR/${1}_${SCRIPTNAME}_free_tablespace.tmp1
cat $LOG_DIR/${1}_${SCRIPTNAME}_free_tablespace.tmp1|sed "/^$/ d;" >>$LOG_DIR/${1}_${SCRIPTNAME}_final_report_free_tablespace
echo "=============================================================" >>$LOG_DIR/${1}_${SCRIPTNAME}_final_report_free_tablespace
fi
fi
done

echo "TABLESPACE_NAME USED (MB)    FREE (MB)  TOTAL (MB)   PER_FR      
--------------- ------------ ---------- ------------ ------      
" >> $LOG_DIR/${1}_${SCRIPTNAME}_final_report_free_tablespace.new
cat $LOG_DIR/${1}_${SCRIPTNAME}_final_report_free_tablespace >> $LOG_DIR/${1}_${SCRIPTNAME}_final_report_free_tablespace.new
echo "DBA Team"| tee -a $LOG_DIR/${1}_${SCRIPTNAME}_final_report_free_tablespace.new
echo "Script Location on $HOST ${SCR_DIR}/${SCRIPTNAME}" | tee -a $LOG_DIR/${1}_${SCRIPTNAME}_final_report_free_tablespace.new

if [ `cat $LOG_DIR/${1}_${SCRIPTNAME}_final_report_free_tablespace|wc -l` -gt 2 ]
then
cat $LOG_DIR/${1}_${SCRIPTNAME}_final_report_free_tablespace.new
echo 'need to notify jianrong to help ' 
mailx -s "$1  : < 10% or 2 GB Free TableSpace Report: $DAY" ' xxxxxx@xxxx.com' < $LOG_DIR/${1}_${SCRIPTNAME}_final_report_free_tablespace.new  --傳送郵件
fi

整個過程就完成了表空間的監控,當然是一個初步的指令碼還有一些不嚴謹的地方。
這個時候我們需要繼續完成作業系統級的監控,這個監控是有一定的範圍的。
我們可以先從得到資料庫中資料檔案的格式。
conn_str=n1/n1
print "
conn  $conn_str
set feedback off
set pages 0
 select file_name from dba_data_files;
" |sqlplus -s /nolog |awk -F"/" '{print   "/"$2}'|sort|uniq|awk '{print "df -k |grep -i \""$1 "\""}' > df_k_chk_tmp.ksh

比如資料檔案為 /u02/ora11g/oradata/TEST11G/sysaux01.dbf 我們需要得到掛載點,即 /u02,其他的資料檔案,掛載點可能是 /u03,/u04....
然後使用df -k來檢視這些掛載點的空間使用情況,這個地方我是使用awk '{print "df -k |grep -i \""$1 "\""}' > df_k_chk_tmp.ksh來直接生成對應的df -k的指令碼。

這個時候比如還是有10個掛載點,我們需要新增檔案,比如說需要新增2G的檔案,這個時候就需要在這些掛載點中進行校驗,首先大小要超過2G的掛載點才可以考慮。
然後對輸出的結果進行過濾。這裡有一個問題是在Unix和linux下使用df -k的時候,輸出可能會有一些不同。
版本1:
/dev/sda3             30969600  24844420   4552016  85% /u02
版本2:
                          30969600  24844420   4552016  85% /u02
這個時候可以根據要求反向得到最後三列的值,作為我們分析的基礎。
這個部分使用一個函式即可搞定,假設我們生成的動態df -k的指令碼為df_k_chk_tmp.ksh 需要新增的資料檔案大小為800M,可以這麼過濾。
function get_db_file_mount
{
ksh  $1 | awk -v file_size=$2 'NR>=1{ if($(NF-2)-$file_size>0) print $(NF-2),$(NF-1),$NF}' |sort
}
get_db_file_mount df_k_chk_tmp.ksh 8100000 > tmp_FS_mount


接下來的部分就是如何做hash或者random分佈了,怎麼儘量把資料檔案分散出去,選擇一個可用的掛載點。我們們可以定義一個random函式。


function get_random
{
    min=$1;
    max=$2
    num=$(date +%s+%N);
    ((retnum=num%max+min));
    echo $retnum;    
}

通過下面的程式碼進行過濾,能夠隨機抓取到一個合適的掛載點。
tmp_FS_mount_cnt=`cat tmp_FS_mount|wc -l`
echo $tmp_FS_mount_cnt
tmp_random=`get_random 1 ${tmp_FS_mount_cnt}`
echo $tmp_random
cat  tmp_FS_mount|sed -n "${tmp_random}p"|awk '{print $3}'

接下來的事情就是生成資料檔案的部分了。明天繼續。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/23718752/viewspace-1683250/,如需轉載,請註明出處,否則將追究法律責任。

相關文章