標籤:des blog http 使用 os 檔案
前言:
通過對spark叢集指令碼的研讀, 對一些重要的shell指令碼技巧, 做下筆記.
*). 取當前指令碼的目錄
sbin=`dirname "$0"` sbin=`cd "$sbin"; pwd`
代碼評註:
# 以上代碼為擷取執行指令碼所在的目錄的常用技巧
# sbin=$(dirname $0) 返回可能是相對路徑, 比如./
# sbin=$(cd $sbin; pwd) 採用pwd, 來返回指令碼所在目錄的絕對路徑
*). 迴圈遍曆指令碼參數
while (( "$#" )); do case $1 in --with-tachyon) TACHYON_STR="--with-tachyon" ;; esac shiftdone
代碼評註:
# 這是段遍曆指令碼參數的常見程式碼片段
# shell指令碼中$#表示參數個數
# 由於$0是指令碼名稱本身佔據, 因此指令碼對參數的遍曆從$1開始, 藉助shift變數左移, 方便了對變長參數列表的遍曆
# 基於事件的xml解析方式, 當採用pull方式去遍曆的時候, 差不多也是類似的代碼結構
# 當然需要注意, shift處理參數變數之後, 對後續指令碼代碼處理變數是有影響的(負作用), 因此最佳實務是集中處理指令碼參數
*). 引入配置指令碼
. "$sbin/spark-config.sh"
代碼評註:
# shell指令碼中‘.‘ 等同於source, 把呼叫指令碼作為調用方指令碼的自身的一部分執行, source <shell_file>通常用於匯入應用的配置參數
# source/exec/fork 外部指令碼的區別, 詳見這篇
*). 預設參數處理
if [ "$SPARK_MASTER_PORT" = "" ]; then SPARK_MASTER_PORT=7077fi
代碼評註:
# 對變數預設值的處理方式
# 注意對變數添加"", if [ $SPARK_MASTER_PORT = "" ] 會報錯誤: "[: =: unary operator expected"
# 類似的代碼可採用-z $SPARK_MASTER_PORT的方式
if [ -z $SPARK_MASTER_PORT ]; then SPARK_MASTER_PORT=7077fi
*). $!的使用和pid檔案的使用
nohup nice -n $SPARK_NICENESS "$SPARK_PREFIX"/bin/spark-class $command "[email protected]" >> "$log" 2>&1 < /dev/null &newpid=$!echo $newpid > $pid
代碼評註:
# nohup 表示進程脫離session運行
# nice -n 用於調整進程nice值
# 2>&1 表示把標準錯誤(stderr, 2)關聯到標準輸出(stdout, 1), 可以簡寫為 &>
# $!表示上一個shell命令(後台運行)的pid
# echo $newpid > $pid (代表檔案), 是把進程pid寫入到進程的pid檔案中去
# 很多服務(比如apache)會選擇把自身的pid(進程id)寫入到pid檔案中去, 至於為何這麼做? 各有各的應用情境, 下面的kill -0就應用到了
*). kill -0 的使用, 檢測進程是否存在, 重入(誤判)問題
if [ -f $pid ]; then if kill -0 `cat $pid` > /dev/null 2>&1; then echo $command running as process `cat $pid`. Stop it first. exit 1 fifi
代碼評註:
# kill -0 <pid> 只是簡單的向進程發送一個signal(不影響進程運行), 用來檢測進程是否存在, 存在(echo $? => 0), 不存在(echo $? => 1)
# if [ -f $pid ] 判斷pid檔案是否存在, cat $pid, 則是擷取pid值, 這與上面pid檔案相吻合
# kill -0 `cat $pid` > /dev/null 2>&1 後面的‘> /dev/null 2>&1‘用於去掉不必要資訊到控制台
疑問:
# 重入問題: 有點類似tcp的問題, socket佔據的四元組(src: ip+port, dest: ip+port), 遺留的tcp包, 對後續重新複用port的socket造成的幹擾
# 假設: pid寫入到pid檔案後, 然後進程退出, 然後有後續的新進程佔據了這個pid, 那麼指令碼根據這個pid判斷之前的進程是否存活就沒意義了, 由此導致誤判
# linux kernel對pid的分配採用了延時再分配的策略, pid被複用而導致重判, 這個需要注意
*). 並發+wait使用
for slave in `cat "$HOSTLIST"|sed "s/#.*$//;/^$/d"`; do ssh $SPARK_SSH_OPTS $slave $"${@// /\\ }" 2>&1 | sed "s/^/$slave: /" & if [ "$SPARK_SLAVE_SLEEP" != "" ]; then sleep $SPARK_SLAVE_SLEEP fidonewait
代碼評註:
# shell指令碼沒有多線程的概念, 且預設執行子shell是阻塞的, 因此只能通過後台運行多個子進程來類比
# ssh $slave "<command> " & 是把ssh命令放在後台運行
# wait, 是指等待所有的後台進程結束, 才繼續進行下去
# 這是很好的並發CountDownLatch的編程實踐
*). sed命令使用
sed "s/#.*$//;/^$/d"sed "s/^/$slave: /"
代碼評註:
# 使用流編輯器sed, 對常值內容進行替換和刪除, 贊sed