So Tired !_! 逆水行舟, 不进则退!

5Apr/17

关于解决line 1: #!/bin/bash: No such file or directory的问题

Posted by Nick Xu

今天在执行脚本的时候,一直报这个错,虽然不影响脚本的执行,但是看见它的存在还是很不爽,然后就查了半天最终搞定

1.一般情况下,/bin下面不会不存在bash/,所以和平时我们遇到的No such file or directory并不一样

2.既然是执行的时候报错,个人感觉不是执行权限的问题

3.如果是在windows下用编辑器编写的脚本,务必检查文档格式,检查方法:用vim打开脚本,然后“:”,输入set ff,回显结果fileformat=unix为正确,若不是则输入set ff=unix即可;

4.执行第三步后如果还不行,那只能放大招,用vim打开一个新文本,将写好的脚本复制过来即可

29Mar/17

linux awk命令详解

Posted by Nick Xu

awk是行处理器: 相比较屏幕处理的优点,在处理庞大文件时不会出现内存溢出或是处理缓慢的问题,通常用来格式化文本信息
awk处理过程: 依次对每一行进行处理,然后输出
awk命令形式:
awk [-F|-f|-v] ‘BEGIN{} //{command1; command2} END{}’ file
 [-F|-f|-v]   大参数,-F指定分隔符,-f调用脚本,-v定义变量 var=value
'  '          引用代码块
BEGIN   初始化代码块,在对每一行进行处理之前,初始化代码,主要是引用全局变量,设置FS分隔符
//           匹配代码块,可以是字符串或正则表达式
{}           命令代码块,包含一条或多条命令
;          多条命令使用分号分隔
END      结尾代码块,在对每一行进行处理之后再执行的代码块,主要是进行最终计算或输出结尾摘要信息
特殊要点:
$0           表示整个当前行
$1           每行第一个字段
NF          字段数量变量
NR          每行的记录号,多文件记录递增
FNR        与NR类似,不过多文件记录不递增,每个文件都从1开始
\t            制表符
\n           换行符
FS          BEGIN时定义分隔符
RS       输入的记录分隔符, 默认为换行符(即文本是按一行一行输入)
~            匹配,与==相比不是精确比较
!~           不匹配,不精确比较
==         等于,必须全部相等,精确比较
!=           不等于,精确比较
&&      逻辑与
||             逻辑或
+            匹配时表示1个或1个以上
/[0-9][0-9]+/   两个或两个以上数字
/[0-9][0-9]*/    一个或一个以上数字
FILENAME 文件名
OFS      输出字段分隔符, 默认也是空格,可以改为制表符等
ORS        输出的记录分隔符,默认为换行符,即处理结果也是一行一行输出到屏幕
-F'[:#/]'   定义三个分隔符
print & $0
print 是awk打印指定内容的主要命令
awk '{print}'  /etc/passwd   ==   awk '{print $0}'  /etc/passwd
awk '{print " "}' /etc/passwd                                           //不输出passwd的内容,而是输出相同个数的空行,进一步解释了awk是一行一行处理文本
awk '{print "a"}'   /etc/passwd                                        //输出相同个数的a行,一行只有一个a字母
awk -F":" '{print $1}'  /etc/passwd
awk -F: '{print $1; print $2}'   /etc/passwd                   //将每一行的前二个字段,分行输出,进一步理解一行一行处理文本
awk  -F: '{print $1,$3,$6}' OFS="\t" /etc/passwd        //输出字段1,3,6,以制表符作为分隔符
-f指定脚本文件
awk -f script.awk  file
BEGIN{
FS=":"
}
{print $1}               //效果与awk -F":" '{print $1}'相同,只是分隔符使用FS在代码自身中指定
awk 'BEGIN{X=0} /^$/{ X+=1 } END{print "I find",X,"blank lines."}' test
I find 4 blank lines.
 ls -l|awk 'BEGIN{sum=0} !/^d/{sum+=$5} END{print "total size is",sum}'                    //计算文件大小
total size is 17487
-F指定分隔符
$1 指指定分隔符后,第一个字段,$3第三个字段, \t是制表符
一个或多个连续的空格或制表符看做一个定界符,即多个空格看做一个空格
awk -F":" '{print $1}'  /etc/passwd
awk -F":" '{print $1 $3}'  /etc/passwd                       //$1与$3相连输出,不分隔
awk -F":" '{print $1,$3}'  /etc/passwd                       //多了一个逗号,$1与$3使用空格分隔
awk -F":" '{print $1 " " $3}'  /etc/passwd                  //$1与$3之间手动添加空格分隔
awk -F":" '{print "Username:" $1 "\t\t Uid:" $3 }' /etc/passwd       //自定义输出
awk -F: '{print NF}' /etc/passwd                                //显示每行有多少字段
awk -F: '{print $NF}' /etc/passwd                              //将每行第NF个字段的值打印出来
 awk -F: 'NF==4 {print }' /etc/passwd                       //显示只有4个字段的行
awk -F: 'NF>2{print $0}' /etc/passwd                       //显示每行字段数量大于2的行
awk '{print NR,$0}' /etc/passwd                                 //输出每行的行号
awk -F: '{print NR,NF,$NF,"\t",$0}' /etc/passwd      //依次打印行号,字段数,最后字段值,制表符,每行内容
awk -F: 'NR==5{print}'  /etc/passwd                         //显示第5行
awk -F: 'NR==5 || NR==6{print}'  /etc/passwd       //显示第5行和第6行
route -n|awk 'NR!=1{print}'                                       //不显示第一行
//匹配代码块
//纯字符匹配   !//纯字符不匹配   ~//字段值匹配    !~//字段值不匹配   ~/a1|a2/字段值匹配a1或a2   
awk '/mysql/' /etc/passwd
awk '/mysql/{print }' /etc/passwd
awk '/mysql/{print $0}' /etc/passwd                   //三条指令结果一样
awk '!/mysql/{print $0}' /etc/passwd                  //输出不匹配mysql的行
awk '/mysql|mail/{print}' /etc/passwd
awk '!/mysql|mail/{print}' /etc/passwd
awk -F: '/mail/,/mysql/{print}' /etc/passwd         //区间匹配
awk '/[2][7][7]*/{print $0}' /etc/passwd               //匹配包含27为数字开头的行,如27,277,2777...
awk -F: '$1~/mail/{print $1}' /etc/passwd           //$1匹配指定内容才显示
awk -F: '{if($1~/mail/) print $1}' /etc/passwd     //与上面相同
awk -F: '$1!~/mail/{print $1}' /etc/passwd          //不匹配
awk -F: '$1!~/mail|mysql/{print $1}' /etc/passwd
IF语句
必须用在{}中,且比较内容用()扩起来
awk -F: '{if($1~/mail/) print $1}' /etc/passwd                                       //简写
awk -F: '{if($1~/mail/) {print $1}}'  /etc/passwd                                   //全写
awk -F: '{if($1~/mail/) {print $1} else {print $2}}' /etc/passwd            //if...else...
条件表达式
==   !=   >   >=  
awk -F":" '$1=="mysql"{print $3}' /etc/passwd
awk -F":" '{if($1=="mysql") print $3}' /etc/passwd          //与上面相同
awk -F":" '$1!="mysql"{print $3}' /etc/passwd                 //不等于
awk -F":" '$3>1000{print $3}' /etc/passwd                      //大于
awk -F":" '$3>=100{print $3}' /etc/passwd                     //大于等于
awk -F":" '$3<1{print $3}' /etc/passwd                            //小于
awk -F":" '$3<=1{print $3}' /etc/passwd                         //小于等于
逻辑运算符
&& || 
awk -F: '$1~/mail/ && $3>8 {print }' /etc/passwd         //逻辑与,$1匹配mail,并且$3>8
awk -F: '{if($1~/mail/ && $3>8) print }' /etc/passwd
awk -F: '$1~/mail/ || $3>1000 {print }' /etc/passwd       //逻辑或
awk -F: '{if($1~/mail/ || $3>1000) print }' /etc/passwd
数值运算
awk -F: '$3 > 100' /etc/passwd
awk -F: '$3 > 100 || $3 < 5' /etc/passwd
awk -F: '$3+$4 > 200' /etc/passwd
awk -F: '/mysql|mail/{print $3+10}' /etc/passwd                    //第三个字段加10打印
awk -F: '/mysql/{print $3-$4}' /etc/passwd                             //减法
awk -F: '/mysql/{print $3*$4}' /etc/passwd                             //求乘积
awk '/MemFree/{print $2/1024}' /proc/meminfo                  //除法
awk '/MemFree/{print int($2/1024)}' /proc/meminfo           //取整
输出分隔符OFS
awk '$6 ~ /FIN/ || NR==1 {print NR,$4,$5,$6}' OFS="\t" netstat.txt
awk '$6 ~ /WAIT/ || NR==1 {print NR,$4,$5,$6}' OFS="\t" netstat.txt
//输出字段6匹配WAIT的行,其中输出每行行号,字段4,5,6,并使用制表符分割字段
输出处理结果到文件
①在命令代码块中直接输出    route -n|awk 'NR!=1{print > "./fs"}'
②使用重定向进行输出           route -n|awk 'NR!=1{print}'  > ./fs
格式化输出
netstat -anp|awk '{printf "%-8s %-8s %-10s\n",$1,$2,$3}'
printf表示格式输出
%格式化输出分隔符
-8长度为8个字符
s表示字符串类型
打印每行前三个字段,指定第一个字段输出字符串类型(长度为8),第二个字段输出字符串类型(长度为8),
第三个字段输出字符串类型(长度为10)
netstat -anp|awk '$6=="LISTEN" || NR==1 {printf "%-10s %-10s %-10s \n",$1,$2,$3}'
netstat -anp|awk '$6=="LISTEN" || NR==1 {printf "%-3s %-10s %-10s %-10s \n",NR,$1,$2,$3}'
IF语句
awk -F: '{if($3>100) print "large"; else print "small"}' /etc/passwd
small
small
small
large
small
small
awk -F: 'BEGIN{A=0;B=0} {if($3>100) {A++; print "large"} else {B++; print "small"}} END{print A,"\t",B}' /etc/passwd
                                                                                                                  //ID大于100,A加1,否则B加1
awk -F: '{if($3<100) next; else print}' /etc/passwd                         //小于100跳过,否则显示
awk -F: 'BEGIN{i=1} {if(i<NF) print NR,NF,i++ }' /etc/passwd
awk -F: 'BEGIN{i=1} {if(i<NF) {print NR,NF} i++ }' /etc/passwd
另一种形式
awk -F: '{print ($3>100 ? "yes":"no")}'  /etc/passwd
awk -F: '{print ($3>100 ? $3":\tyes":$3":\tno")}'  /etc/passwd
while语句
awk -F: 'BEGIN{i=1} {while(i<NF) print NF,$i,i++}' /etc/passwd
7 root 1
7 x 2
7 0 3
7 0 4
7 root 5
7 /root 6
数组
netstat -anp|awk 'NR!=1{a[$6]++} END{for (i in a) print i,"\t",a[i]}'
netstat -anp|awk 'NR!=1{a[$6]++} END{for (i in a) printf "%-20s %-10s %-5s \n", i,"\t",a[i]}'
9523                               1
9929                               1
LISTEN                            6
7903                               1
3038/cupsd                   1
7913                               1
10837                             1
9833                               1
 
应用1
awk -F: '{print NF}' helloworld.sh                                                       //输出文件每行有多少字段
awk -F: '{print $1,$2,$3,$4,$5}' helloworld.sh                                 //输出前5个字段
awk -F: '{print $1,$2,$3,$4,$5}' OFS='\t' helloworld.sh                 //输出前5个字段并使用制表符分隔输出
awk -F: '{print NR,$1,$2,$3,$4,$5}' OFS='\t' helloworld.sh           //制表符分隔输出前5个字段,并打印行号
应用2
awk -F'[:#]' '{print NF}'  helloworld.sh                                                  //指定多个分隔符: #,输出每行多少字段
awk -F'[:#]' '{print $1,$2,$3,$4,$5,$6,$7}' OFS='\t' helloworld.sh   //制表符分隔输出多字段
应用3
awk -F'[:#/]' '{print NF}' helloworld.sh                                               //指定三个分隔符,并输出每行字段数
awk -F'[:#/]' '{print $1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12}' helloworld.sh     //制表符分隔输出多字段
应用4
计算/home目录下,普通文件的大小,使用KB作为单位
ls -l|awk 'BEGIN{sum=0} !/^d/{sum+=$5} END{print "total size is:",sum/1024,"KB"}'
ls -l|awk 'BEGIN{sum=0} !/^d/{sum+=$5} END{print "total size is:",int(sum/1024),"KB"}'         //int是取整的意思
应用5
统计netstat -anp 状态为LISTEN和CONNECT的连接数量分别是多少
netstat -anp|awk '$6~/LISTEN|CONNECTED/{sum[$6]++} END{for (i in sum) printf "%-10s %-6s %-3s \n", i," ",sum[i]}'
应用6
统计/home目录下不同用户的普通文件的总数是多少?
ls -l|awk 'NR!=1 && !/^d/{sum[$3]++} END{for (i in sum) printf "%-6s %-5s %-3s \n",i," ",sum[i]}'
mysql        199
root           374
统计/home目录下不同用户的普通文件的大小总size是多少?
ls -l|awk 'NR!=1 && !/^d/{sum[$3]+=$5} END{for (i in sum) printf "%-6s %-5s %-3s %-2s \n",i," ",sum[i]/1024/1024,"MB"}'
应用7
输出成绩表
awk 'BEGIN{math=0;eng=0;com=0;printf "Lineno.   Name    No.    Math   English   Computer    Total\n";printf "------------------------------------------------------------\n"}{math+=$3; eng+=$4; com+=$5;printf "%-8s %-7s %-7s %-7s %-9s %-10s %-7s \n",NR,$1,$2,$3,$4,$5,$3+$4+$5} END{printf "------------------------------------------------------------\n";printf "%-24s %-7s %-9s %-20s \n","Total:",math,eng,com;printf "%-24s %-7s %-9s %-20s \n","Avg:",math/NR,eng/NR,com/NR}' test0
[root@localhost home]# cat test0
Marry   2143 78 84 77
Jack    2321 66 78 45
Tom     2122 48 77 71
Mike    2537 87 97 95
Bob     2415 40 57 62

awk手册
http://www.chinaunix.net/old_jh/7/16985.html
Tagged as: , Comments Off
16Mar/17

Prusa i3 自動調平—改用 BLTouch 探針接觸感應式

Posted by Nick Xu

转自:http://www.kenming.idv.tw/prusa-i3-auto-bed-leveling_using-bltouch

我的 Prusa i3 第一個版本的自動調平,是使用電容電感近接開關,優點是便宜也容易安裝;缺點是只能探測金屬材質。可參考:Prusa i3 自動調平設定—硬體與電路部分

我的熱床是 MK3 鋁材質,原來使用上其實是可以配合。但 MK3 相當不平,即使採用了自動調平偵測還是有限,尤其是列印大面積的列印件時,兩側常無法黏住。

徵詢 Reprap.Taipei FB 社團的諸多高手所綜合的建議,在 MK3 熱床上再鋪上一片 3mm 以上的玻璃,會平坦很多。所以我從對岸淘了兩片從秦皇島店家購買的兩片鋼化高硼矽磨砂耐熱玻璃,據說可以黏住 PLA 材質的列印,而不需要塗上膠水或貼上美紋紙。

加上玻璃後,連帶電容電感近接開關就無法使用,因為無法偵測非金屬材質。我曾在玻璃後邊貼上鋁箔膠帶測試時還能偵測到,但打印幾次卻發現很不穩定,總有某些點會突然失靈,太過不穩定。

爬文作了一堆功課,發現到有種探針式的接觸感測近接開關,就沒有非金屬就無法感測的問題了。其中這一款 — BLTouch,我看從 Youtube 視頻上看到許多先進玩家的使用分享,效果挺不錯的樣子。

不過原廠價格可不便宜,且從 Amazon 還要多擔負一筆航空運費,並不划算。還是仍從對岸淘寶買的這支號稱是復刻版本的 TLTouch (BLTouch 克隆版),含順豐快遞到家共 RMB 159 (約台幣七百多元),還可以接受。

先瞧下我錄製下來的視頻,關於 BLTouch 在執行歸零與自動底床調平 (G28/G29)時的情形。

Prusa i3 with auto bed leveling using TLTouch (BLTouch Clone)

2:01 / 2:38

<div class="player-unavailable"><h1 class="message">出现错误。</h1><div class="submessage"><a href="http://www.youtube.com/watch?v=QHDz6-kx5aE" target="_blank">请尝试在 www.youtube.com 上观看此视频</a>,或者在浏览器中启用 JavaScript(如果已停用)。</div></div>

雖然是復刻版,但包裝與內附的零件與原廠是一樣的 (還附了一張原廠的原文說明紙),還裝在一個透明盒收納。

其實這些零件多是小螺絲與杜邦延長端子之類的,反正就是要自行再拉延長線接到 Ramps 1.4 的 5V servo 腳位,以及限位開關腳位的。

要如何設計一個 BLTouch 的 Holder 並盡量靠近到熱端 (Hotend)處,這類 3D繪圖設計問題,對我永遠都是挑戰。花了有大半天時間,趁此次改使用 Fusion 360 3D 繪圖,因為 123D Design 據說不再釋出新版本 (且實在不太好用)。

哇喔! 原來比較專業性質的 3D繪圖功能是這麼強大啊,早應該要轉用這套免費提供給教師/學生,以及年收入10萬美金以下的商業人士 (真是佛心來著)。大約花個半天時間熟悉下使用介面就可以上手了;然後設計了三次版本演進的 BLTouch Holder。

打印了幾次樣本,總算確定了高度與接合距離,印出來的模樣。

這是套進去後的樣子。因為螺絲鎖住的高度剛好差點頂住 X軸鋁合金安裝座 (Mount),所以我還用電烙鐵頂住螺絲讓其陷進熱熔後的列印座內,下一個版本應該要把螺絲的高度給考慮進來的,目前這樣先能用就好。

設計這 Holder 比較大的挑戰就是 BLTouch 的高度相對於噴嘴高度的問題,主要就是當探針伸出來 (pull)時要比噴嘴高,但縮回去 (push)時要比噴嘴低,原廠建議探針出口處距離噴嘴高度約 8mm 距離左右。

嗯嗯,Holder 確實可以套用後,再來就是連接線路,然後開始 Marlin 設定。

上文有提到要用杜邦延長端子連接延長線,主要就是限位開關2條 (白-觸發訊號/黑-接地),servo 電源輸入腳位3條 (橘-觸發訊號/紅-+5V/棕-接地),說明紙都有提的,顏色確實接正確連到 Ramps 1.4 主板上即可。

大概就是注意下,servo 電源輸入腳位要能供應 +5V 的電壓,就在位於 servo 前面的腳位上要用 Jumper 短路前兩根腳,這在 Ramps 1.4 的規格都有提的。

線路接完後再來就是 marlin 的設定。本來以為很簡單,結果耗費整整一天的時間 try-error,原來竟然是這克隆版與原版的電位剛好相反,限位開關的訊號觸發 (inverting)要設為 true,且不能直接開啟 1.1.0 RC8 內有個預設的 #define BLTouch,因為並不相容。

為何要與原版的相反?這反而克隆版廠商的好意,為了修正原廠因為觸發訊號時只有 5ms 脈衝,這太小很容易就會被板子上的電容給當成雜訊過濾掉,所以就反過來讓其設計為反相訊號。原廠與克隆版廠商都準備下一個版本改為 10ms 脈衝訊號,對岸我買的那家,技術客服還特別因為覺得讓我花太多時間,所以承諾下一個版本免費送給我,哈,真是不錯,當然屆時幫他們簡單開箱介紹下。

這裡就把主要與 BLTouch 相關的 marlin 設定給列出來參考 (configuration.h),其它有關自動調平與前述使用電容電感式的設定是一樣的。

#define Z_MIN_ENDSTOP_INVERTING true // set to true to invert the logic of the endstop.

#define Z_MIN_PROBE_ENDSTOP_INVERTING false // set to true to invert the logic of the endstop.

#define Z_ENDSTOP_SERVO_NR 0

#define Z_SERVO_ANGLES {10,90} // Z Servo Deploy and Stow angles

#define PROBE_DOUBLE_TOUCH

#define NUM_SERVOS 1

好啦,寫入 EPROM、Z軸高度校正等,都是與前一篇設定文一樣的方式,就是要注意下噴嘴當接近Z軸零點時,已收起來的探針不要碰觸到表面,若有就是要回頭調整 BLTouch 的高度。

設定正確後重新啟動 Marlin,此時 BLTouch 會自我測試伸縮探針,並顯示紅色燈號 (如果是閃爍的紅色燈號那代表有問題)。

新裝上磨砂玻璃,準備不塗上膠水與貼上美紋紙,只有底床加熱 (PLA 約為60度左右)。順便瞧下帶顏色的馬尾夾,從大創百貨買回來的,比起純黑色好看太多了。

執行 G28 歸零 (Homing)/G29 自動探測各點距離,然後開始打印從 thingiverse 下載底床調平校正模型,打印出來成果相當令人滿意。

試著打印小貓咪吊飾模型,直接就是打印在玻璃上,沒有塗上膠水與黏貼美紋紙,第一層仍可以牢靠黏著。

當晚我就給它整夜打印 68%縮小原比例的穿山甲,整整要花上快9個小時,但效果真的相當好,關節都不會黏住,自動調平校正後第一層平坦時就會顯現這樣的威力。

結論這 BLTouch 的克隆版在自動調平功能上頗為滿意,無怪乎國外的許多玩家對其還蠻

推薦的。

不過這物件真有些貴,其實這可以 DIY,只要有光學限位開關或霍爾感應器,加上小磁鐵

與彈簧、探針(用鐵釘或螺絲就可),成本並不高,但當然不容易能像 BLTouch 這般小巧

精緻。

Crash Probe with optical switch

<div class="player-unavailable"><h1 class="message">出现错误。</h1><div class="submessage"><a href="http://www.youtube.com/watch?v=hqBF5s-aBCQ" target="_blank">请尝试在 www.youtube.com 上观看此视频</a>,或者在浏览器中启用 JavaScript(如果已停用)。</div></div>

原理比想像的簡單,如果使用現成的光學限位開關 (機械限位應該也可以),就只是想辦法在歸零的時候讓原來黏在磁鐵的探針 (可以用釘子或迴紋針就可)落下比噴嘴還低的位置。(影片是利用穿過小彈簧的水平桿觸及左側X軸)

然後在 G28/G29 歸零/自動偵測後,噴嘴會降到Z軸0點位置,此時探針會往下壓而被頂上來,自然就會磁鐵黏回去而比噴嘴位置高了。

Thingiverse 的模型檔與基本說明:http://www.thingiverse.com/thing:1714315

當然也可以直接使用霍爾傳感器 (Hall sensor)直接取代光學限位開關,實作上會更簡單。即使不弄成自動調平偵測,當成Z軸限位開關也很不錯的方式。

16Mar/17

ngxtop:在命令行实时监控 Nginx 的神器

Posted by Nick Xu

Nginx网站服务器在生产环境中运行的时候需要进行实时监控。实际上,诸如Nagios, Zabbix, Munin 的网络监控软件是支持 Nginx 监控的。

如果你不需要以上软件提供的综合性报告或者长期数据统计功能,只是需要一种快速简便的办法去监控 Nginx 服务器的请求的话,我建议你采用一个叫 ngxtop 的命令行工具。

你马上就会发现 ngxtop 从界面和名称都借鉴了著名的top命令。ngxtop 是通过分析 Nginx 或者其他的日志文件,使用类似 top 命令的界面实时展示出来的。你可以说你知道的其他高端监控工具,但是在简洁这方面 ngxtop 无疑是最好的。简单就意味着不可替代。

本指南中,我将介绍如何使用 ngxtop 实时监控 Nginx 网站服务器。

Linux 上安装 ngxtop

首先在 Linux 系统中安装依赖库pip(LCTT译注:ngxtop是用python编写的)。

然后使用如下命令安装 ngxtop。

  1. $ sudo pip install ngxtop

ngxtop 使用

基本使用方法如下:

  1. ngxtop [options]
  2. ngxtop [options] (print|top|avg|sum) <var>
  3. ngxtop info

这里是一些通用选项。

  • -l : 指定日志文件的完整路径 (Nginx 或 Apache2)
  • -f : 日志格式
  • --no-follow: 处理当前已经写入的日志文件,而不是实时处理新添加到日志文件的日志
  • -t : 更新频率
  • -n : 显示行号
  • -o : 排序规则(默认是访问计数)
  • -a ..., --a ...: 添加表达式(一般是聚合表达式如: sum, avg, min, max 等)到输出中。
  • -v: 输出详细信息
  • -i : 只处理符合规则的记录

以下是一些内置变量,他们的含义不言自明。

  • bodybytessend
  • http_referer
  • httpuseragent
  • remote_addr
  • remote_user
  • request
  • status
  • time_local

使用 ngxtop 监控 Nginx

ngxtop 默认会从其配置文件 (/etc/nginx/nginx.conf) 中查找 Nginx 日志的地址。所以,监控 Nginx ,运行以下命令即可:

  1. $ ngxtop

这将会列出10个 Nginx 服务,按请求数量排序。

显示前20个最频繁的请求:

  1. $ ngxtop -n 20

获取Nginx基本信息:

  1. $ ngxtop info

你可以自定义显示的变量,简单列出需要显示的变量。使用 "print" 命令显示自定义请求。

  1. $ ngxtop print request http_user_agent remote_addr

显示请求最多的客户端IP地址

  1. $ ngxtop top remote_addr

显示状态码是404的请求

  1. $ ngxtop -i 'status == 404' print request status

除了Nginx,ngtop 还可以处理其他的日志文件,比如 Apache 的访问文件。使用以下命令监控 Apache 服务器:

  1. $ tail -f /var/log/apache2/access.log | ngxtop -f common
Tagged as: , , Comments Off
28Feb/17

手把手教你用Strace诊断问题

Posted by Nick Xu

早些年,如果你知道有个 strace 命令,就很牛了,而现在大家基本都知道 strace 了,如果你遇到性能问题求助别人,十有八九会建议你用 strace 挂上去看看,不过当你挂上去了,看着满屏翻滚的字符,却十有八九看不出个所以然。本文通过一个简单的案例,向你展示一下在用 strace 诊断问题时的一些套路。

strace是Linux环境下的一款程序调试工具,用来监察一个应用程序所使用的系统调用及它所接收的系统信息。追踪程序运行时的整个生命周期,输出每一个系统调用的名字,参数,返回值和执行消耗的时间等。
strace常用参数:
-p 跟踪指定的进程
-f 跟踪由fork子进程系统调用
-F 尝试跟踪vfork子进程系统调吸入,与-f同时出现时, vfork不被跟踪
-o filename 默认strace将结果输出到stdout。通过-o可以将输出写入到filename文件中
-ff 常与-o选项一起使用,不同进程(子进程)产生的系统调用输出到filename.PID文件
-r 打印每一个系统调用的相对时间
-t 在输出中的每一行前加上时间信息。 -tt 时间确定到微秒级。还可以使用-ttt打印相对时间
-v 输出所有系统调用。默认情况下,一些频繁调用的系统调用不会输出
-s 指定每一行输出字符串的长度,默认是32。文件名一直全部输出
-c 统计每种系统调用所执行的时间,调用次数,出错次数。
-e expr 输出过滤器,通过表达式,可以过滤出掉你不想要输出

如下真实案例,如有雷同,实属必然!让我们看一台高负载服务器的 top 结果:

top

技巧:运行 top 时,按「1」打开 CPU 列表,按「shift+p」以 CPU 排序。

在本例中大家很容易发现 CPU 主要是被若干个 PHP 进程占用了,同时 PHP 进程占用的比较多的内存,不过系统内存尚有结余,SWAP 也不严重,这并不是问题主因。

不过在 CPU 列表中能看到 CPU 主要消耗在内核态「sy」,而不是用户态「us」,和我们的经验不符。Linux 操作系统有很多用来跟踪程序行为的工具,内核态的函数调用跟踪用「strace」,用户态的函数调用跟踪用「ltrace」,所以这里我们应该用「strace」:

shell> strace -p <PID>

不过如果直接用 strace 跟踪某个进程的话,那么等待你的往往是满屏翻滚的字符,想从这里看出问题的症结并不是一件容易的事情,好在 strace  可以按操作汇总时间:

shell> strace -cp <PID>

通过「c」选项用来汇总各个操作的总耗时,运行后的结果大概如下图所示:

strace -cp <PID>

很明显,我们能看到 CPU 主要被 clone 操作消耗了,还可以单独跟踪一下 clone:

shell> strace -T -e clone -p <PID>

通过「T」选项可以获取操作实际消耗的时间,通过「e」选项可以跟踪某个操作:

strace -T -e clone -p <PID>

很明显,一个 clone 操作需要几百毫秒,至于 clone 的含义,参考 man 文档:

clone() creates a new process, in a manner similar to fork(2). It is actually a library function layered on top of the underlying clone() system call, hereinafter referred to as sys_clone. A description of sys_clone is given towards the end of this page.

Unlike fork(2), these calls allow the child process to share parts of its execution context with the calling process, such as the memory space, the table of file descriptors, and the table of signal handlers. (Note that on this manual page, “calling process” normally corresponds to “parent process”. But see the description of CLONE_PARENT below.)

简单来说,就是创建一个新进程。那么在 PHP 里什么时候会出现此类系统调用呢?查询业务代码看到了 exec 函数,通过如下命令验证它确实会导致 clone 系统调用:

shell> strace -eclone php -r 'exec("ls");'

如果想要追踪多个fpm进程可以用以下脚本:

strace -eall -c $(ps auxf|grep -E '(9013|9014|9015)'|awk '{if ($1="www-data") print "-p "$2}')

 

最后再考大家一个题:如果我们用 strace 跟踪一个进程,输出结果很少,是不是说明进程很空闲?其实试试 ltrace,可能会发现别有洞天。记住有内核态和用户态之分。

Filed under: Linux Comments Off
17Jan/17

Ubuntu解决RTNETLINK answers: File exists

Posted by Nick Xu

出现这种问题有两种原因

1.有两个网关时候

在ip地址配置中有两个网关

    auto eth0
    iface eth0 inet static
    address 192.168.5.21
    netmask 255.255.2550
    gateway 192.168.5.1

    # VM traffic interface
    auto eth1
    iface eth1 inet static
    address 192.168.5.22
    netmask 255.255.255.0
    gateway 192.168.5.1

eth0eth1有不同ip但是有都配置的网关,这时候一个启动后,另一个启动失败

RTNETLINK answers: File exists
Failed to bring up eth2.

如果你修改后,还是出现这种情况,就要对eth0eth1进行下刷新

    ip addr flush dev eth0
    ip addre flush dev eth1
    ifdown eth0 && ifup eth0 && ifdown eth1 && ifup eth1

2.当删除桥接或者其他,把网络改正确,还是出现这种问题

#确保网络配置已经正确的情况下
ip addr flush dev eth0
#重启网络配置

ip addr flush also dumps all the deleted addresses in the format described in the previous subsection
这个命令刷新已经删除的先前已经选择的地址格式

13Jan/17

tsar 的使用说明

Posted by Nick Xu

系统模块

cpu

字段含义

  • user: 表示CPU执行用户进程的时间,通常期望用户空间CPU越高越好.
  • sys: 表示CPU在内核运行时间,系统CPU占用率高,表明系统某部分存在瓶颈.通常值越低越好.
  • wait: CPU在等待I/O操作完成所花费的时间.系统部应该花费大量时间来等待I/O操作,否则就说明I/O存在瓶颈.
  • hirq: 系统处理硬中断所花费的时间百分比
  • sirq: 系统处理软中断所花费的时间百分比
  • util: CPU总使用的时间百分比
  • nice: 系统调整进程优先级所花费的时间百分比
  • steal: 被强制等待(involuntary wait)虚拟CPU的时间,此时hypervisor在为另一个虚拟处理器服务
  • ncpu: CPU的总个数

采集方式

CPU的占用率计算,都是根据/proc/stat计数器文件而来,stat文件的内容基本格式是:

cpu  67793686 1353560 66172807 4167536491 2705057 0 195975 609768
cpu0 10529517 944309 11652564 835725059 2150687 0 74605 196726
cpu1 14380773 127146 13908869 832565666 150815 0 31780 108418

cpu是总的信息,cpu0,cpu1等是各个具体cpu的信息,共有8个值,单位是ticks,分别是

User time, 67793686 Nice time, 1353560 System time, 66172807 Idle time, 4167536491 Waiting time, 2705057 Hard Irq time, 0 SoftIRQ time, 195975 Steal time, 609768

CPU总时间=user+system+nice+idle+iowait+irq+softirq+Stl
各个状态的占用=状态的cpu时间%CPU总时间*100%
比较特殊的是CPU总使用率的计算(util),目前的算法是:
util = 1 - idle - iowait - steal

mem

字段含义

  • free: 空闲的物理内存的大小
  • used: 已经使用的内存大小
  • buff: buff使用的内存大小,buffer is something that has yet to be "written" to disk.
  • cach: 操作系统会把经常访问的东西放在cache中加快执行速度,A cache is something that has been "read" from the disk and stored for later use
  • total: 系统总的内存大小
  • util: 内存使用率

采集方法

内存的计数器在/proc/meminfo,里面有一些关键项

    MemTotal:      7680000 kB
    MemFree:        815652 kB
    Buffers:       1004824 kB
    Cached:        4922556 kB

含义就不解释了,主要介绍一下内存使用率的计算算法:
util = (total - free - buff - cache) / total * 100%

load

字段含义

  • load1: 一分钟的系统平均负载
  • load5: 五分钟的系统平均负载
  • load15:十五分钟的系统平均负载
  • runq: 在采样时刻,运行队列的任务的数目,与/proc/stat的procs_running表示相同意思
  • plit: 在采样时刻,系统中活跃的任务的个数(不包括运行已经结束的任务)

采集方法

/proc/loadavg文件中保存的有负载相关的数据
0.00 0.01 0.00 1/271 23741
分别是1分钟负载,五分钟负载,十五分钟负载,运行进程/总进程 最大的pid
只需要采集前五个数据既可得到所有信息
注意:只有当系统负载除cpu核数>1的时候,系统负载较高

traffic

字段含义

  • bytin: 入口流量byte/s
  • bytout: 出口流量byte/s
  • pktin: 入口pkt/s
  • pktout: 出口pkt/s

采集方法

流量的计数器信息来自:/proc/net/dev

    face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed
    lo:1291647853895 811582000    0    0    0     0          0         0 1291647853895 811582000    0    0    0     0       0          0
    eth0:853633725380 1122575617    0    0    0     0          0         0 1254282827126 808083790    0    0    0     0       0          0

字段的含义第一行已经标示出来,每一行代表一个网卡,tsar主要采集的是出口和入口的bytes/packets
注意tsar只对以eth和em开头的网卡数据进行了采集,像lo这种网卡直接就忽略掉了,流量的单位是byte

tcp

字段含义

  • active:主动打开的tcp连接数目
  • pasive:被动打开的tcp连接数目
  • iseg: 收到的tcp报文数目
  • outseg:发出的tcp报文数目
  • EstRes:Number of resets that have occurred at ESTABLISHED
  • AtmpFa:Number of failed connection attempts
  • CurrEs:当前状态为ESTABLISHED的tcp连接数
  • retran:系统的重传率

采集方法

tcp的相关计数器文件是:/proc/net/snmp

    Tcp: RtoAlgorithm RtoMin RtoMax MaxConn ActiveOpens PassiveOpens AttemptFails EstabResets CurrEstab InSegs OutSegs RetransSegs InErrs OutRsts
    Tcp: 1 200 120000 -1 31702170 14416937 935062 772446 16 1846056224 1426620266 448823 0 5387732

我们主要关注其中的ActiveOpens/PassiveOpens/AttemptFails/EstabResets/CurrEstab/InSegs/OutSegs/RetransSegs
主要关注一下重传率的计算方式:
retran = (RetransSegs-last RetransSegs) / (OutSegs-last OutSegs) * 100%

udp

字段含义

  • idgm: 收到的udp报文数目
  • odgm: 发送的udp报文数目
  • noport:udp协议层接收到目的地址或目的端口不存在的数据包
  • idmerr:udp层接收到的无效数据包的个数

采集方法

UDP的数据来源文件和TCP一样,也是在/proc/net/snmp

    Udp: InDatagrams NoPorts InErrors OutDatagrams
    Udp: 31609577 10708119 0 159885874

io

字段含义

  • rrqms: The number of read requests merged per second that were issued to the device.
  • wrqms: The number of write requests merged per second that were issued to the device.
  • rs: The number of read requests that were issued to the device per second.
  • ws: The number of write requests that were issued to the device per second.
  • rsecs: The number of sectors read from the device per second.
  • wsecs: The number of sectors written to the device per second.
  • rqsize:The average size (in sectors) of the requests that were issued to the device.
  • qusize:The average queue length of the requests that were issued to the device.
  • await: The average time (in milliseconds) for I/O requests issued to the device to be served. This includes the time spent by the requests in queue and the time spent servicing them.
  • svctm: The average service time (in milliseconds) for I/O requests that were issued to the device.
  • util: Percentage of CPU time during which I/O requests were issued to the device (bandwidth utilization for the device).Device saturation occurs when this value is close to 100%.

采集方法

IO的计数器文件是:/proc/diskstats,比如:

    202    0 xvda 12645385 1235409 416827071 59607552 193111576 258112651 3679534806 657719704 0 37341324 717325100
    202    1 xvda1 421 2203 3081 9888 155 63 421 1404 0 2608 11292

每一行字段的含义是:

  • major: 主设备号
  • minor: 次设备号,设备号是用来区分磁盘的类型和厂家信息
  • name: 设备名称
  • rd_ios: 读完成次数,number of issued reads. This is the total number of reads completed successfully
  • rd_merges: 合并读完成次数,为了效率可能会合并相邻的读和写.从而两次4K的读在它最终被处理到磁盘上之前可能会变成一次8K的读,才被计数(和排队),因此只有一次I/O操作
  • rd_sectors: 读扇区的次数,number of sectors read. This is the total number of sectors read successfully.
  • rd_ticks: 读花费的毫秒数,number of milliseconds spent reading. This is the total number of milliseconds spent by all reads
  • wr_ios: 写完成次数,number of writes completed. This is the total number of writes completed successfully
  • wr_merges: 合并写完成次数,number of writes merged Reads and writes which are adjacent to each other may be merged for efficiency. Thus two 4K reads may become one 8K read before it is ultimately handed to the disk, and so it will be counted (and queued) as only one I/O.
  • wr_sectors: 写扇区次数,number of sectors written. This is the total number of sectors written successfully
  • wr_ticks: 写花费的毫秒数,number of milliseconds spent writing. This is the total number of milliseconds spent by all writes.
  • cur_ios: 正在处理的输入/输出请求数,number of I/Os currently in progress. The only field that should go to zero. Incremented as requests are given to appropriate request_queue_t and decremented as they finish.
  • ticks: 输入/输出操作花费的毫秒数
  • aveq: 输入/输出操作花费的加权毫秒数

通过这些计数器可以算出来上面的每个字段的值

double n_ios = rd_ios + wr_ios;
double n_ticks = rd_ticks + wr_ticks;
double n_kbytes = (rd_sectors + wr_sectors) / 2;
st_array[0] = rd_merges / (inter * 1.0);
st_array[1] = wr_merges / (inter * 1.0);
st_array[2] = rd_ios / (inter * 1.0);
st_array[3] = wr_ios / (inter * 1.0);
st_array[4] = rd_sectors / (inter * 2.0);
st_array[5] = wr_sectors / (inter * 2.0);
st_array[6] = n_ios ? n_kbytes / n_ios : 0.0;
st_array[7] = aveq / (inter * 1000);
st_array[8] = n_ios ? n_ticks / n_ios : 0.0;
st_array[9] = n_ios ? ticks / n_ios : 0.0;
st_array[10] = ticks / (inter * 10.0); 


注意:

扇区一般都是512字节,因此有的地方除以2了 ws是指真正落到io设备上的写次数, wrqpms是指系统调用合并的写次数, 它们之间的大小关系没有可比性,因为不知道多少请求能够被合并,比如发起了100个read系统调用,每个读4K,假如这100个都是连续的读,由于硬盘通常允许最大的request为256KB,那么block层会把这100个读请求合并成2个request,一个256KB,另一个144KB,rrqpm/s为100,因为100个request都发生了合并,不管它最后合并成几个;r/s为2,因为最后的request数为2

paritition

字段含义

  • bfree: 分区空闲的字节
  • bused: 分区使用中的字节
  • btotl: 分区总的大小
  • util: 分区使用率

采集方法

首先通过/etc/mtab获取到分区信息,然后通过statfs访问该分区的信息,查询文件系统相关信息,包含:

    struct statfs {
    long f_type; 
    long f_bsiz
    e; 
    long f_blocks; 
    long f_bfree; 
    long f_bavail; 
    long f_files; 
    long f_ffree; 
    fsid_t f_fsid; 
    long f_namelen; 
    };

然后就可以计算出tsar需要的信息,分区的字节数=块数*块大小=f_blocks * f_bsize

pcsw

字段含义

  • cswch: 进程切换次数
  • proc: 新建的进程数

采集方法

计数器在/proc/stat:

    ctxt 19873315174
    processes 296444211

分别代表进程切换次数,以及进程数

tcpx

字段含义

recvq sendq est twait fwait1 fwait2 lisq lising lisove cnest ndrop edrop rdrop pdrop kdrop
分别代表
tcprecvq tcpsendq tcpest tcptimewait tcpfinwait1 tcpfinwait2 tcplistenq tcplistenincq tcplistenover tcpnconnest tcpnconndrop tcpembdrop tcprexmitdrop tcppersistdrop tcpkadrop

采集方法

计数器来自:/proc/net/netstat /proc/net/snmp 里面用到的数据有:

    TcpExt: SyncookiesSent SyncookiesRecv SyncookiesFailed EmbryonicRsts PruneCalled RcvPruned OfoPruned OutOfWindowIcmps LockDroppedIcmps ArpFilter TW TWRecycled TWKilled PAWSPassive PAWSActive PAWSEstab DelayedACKs DelayedACKLocked DelayedACKLost ListenOverflows ListenDrops TCPPrequeued TCPDirectCopyFromBacklog TCPDirectCopyFromPrequeue TCPPrequeueDropped TCPHPHits TCPHPHitsToUser TCPPureAcks TCPHPAcks TCPRenoRecovery TCPSackRecovery TCPSACKReneging TCPFACKReorder TCPSACKReorder TCPRenoReorder TCPTSReorder TCPFullUndo TCPPartialUndo TCPDSACKUndo TCPLossUndo TCPLoss TCPLostRetransmit TCPRenoFailures TCPSackFailures TCPLossFailures TCPFastRetrans TCPForwardRetrans TCPSlowStartRetrans TCPTimeouts TCPRenoRecoveryFail TCPSackRecoveryFail TCPSchedulerFailed TCPRcvCollapsed TCPDSACKOldSent TCPDSACKOfoSent TCPDSACKRecv TCPDSACKOfoRecv TCPAbortOnSyn TCPAbortOnData TCPAbortOnClose TCPAbortOnMemory TCPAbortOnTimeout TCPAbortOnLinger TCPAbortFailed TCPMemoryPressures
    TcpExt: 0 0 0 80 539 0 0 0 0 0 3733709 51268 0 0 0 80 5583301 5966 104803 146887 146887 6500405 39465075 2562794034 0 689613557 2730596 540646233 234702206 0 44187 2066 94 240 0 114 293 1781 7221 60514 185158 2 2 3403 400 107505 5860 24813 174014 0 2966 7 168787 106151 40 32851 2 0 2180 9862 0 15999 0 0 0

具体字段找到并且获取即可

percpu ncpu

字段含义

字段含义等同cpu模块,只不过能够支持采集具体的每一个cpu的信息

采集方法

等同于cpu模块

pernic

字段含义

字段含义等同traffic模块,只不过能够支持采集具体的每一个网卡的信息

采集方法

等同于traffic模块

应用模块

proc

字段含义

  • user: 某个进程用户态cpu消耗
  • sys: 某个进程系统态cpu消耗
  • total:某个进程总的cpu消耗
  • mem: 某个进程的内存消耗百分比
  • RSS: 某个进程的虚拟内存消耗,这是驻留在物理内存的一部分.它没有交换到硬盘.它包括代码,数据和栈
  • read: 进程io读字节
  • write:进程的io写字节

采集方法

计数器文件

/proc/pid/stat:获取进程的cpu信息
/proc/pid/status:获取进程的mem信息
/proc/pid/io:获取进程的读写IO信息

注意,需要将采集的进程名称配置在/etc/tsar/tsar.conf总的mod_proc on procname,这样就会找到procname的pid,并进行数据采集

nginx

字段含义

  • Accept:总共接收的新连接数目
  • Handle:总共处理的连接数目
  • Reqs:总共产生请求数目
  • Active:活跃的连接数,等于read+write+wait
  • Read:读取请求数据的连接数目
  • Write:向用户写响应数据的连接数目
  • Wait:长连接等待的连接数目
  • Qps:每秒处理的请求数
  • Rt:平均响应时间ms

采集方法

通过nginx的采集模块配置,访问特定地址,具体参见:https://github.com/taobao/tsar-mod_nginx

    location = /nginx_status {
        stub_status on;
    }

请求到的数据是:

    Active connections: 1
    server accepts handled requests request_time
    24 24 7 0
    Reading: 0 Writing: 1 Waiting: 0

需要确保nginx配置该location,并且能够访问curl http://localhost/nginx_status得到上面的数据
如果nginx的端口不是80,则需要在配置文件中指定端口,配置文件是/etc/tsar/tsar.conf,修改mod_nginx on为mod_nginx on 8080

类似的有nginx_code, nginx_domain模块,相应的配置是:

    req_status_zone server "$host" 20M;
    req_status server;
    location /traffic_status {
            req_status_show;
    } 

通过访问curl http://localhost/traffic_status能够得到如下字段的数据
localhost,0,0,2,2,2,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0

请求到的数据每个字段的含义是:

  • kv 计算得到的req_status_zone指令定义变量的值,此时为domain字段
  • bytes_in_total 从客户端接收流量总和
  • bytes_out_total 发送到客户端流量总和
  • conn_total 处理过的连接总数
  • req_total 处理过的总请求数
  • 2xx 2xx请求的总数
  • 3xx 3xx请求的总数
  • 4xx 4xx请求的总数
  • 5xx 5xx请求的总数
  • other 其他请求的总数
  • rt_total rt的总数
  • upstream_req 需要访问upstream的请求总数
  • upstream_rt 访问upstream的总rt
  • upstream_tries upstram总访问次数
  • 200 200请求的总数
  • 206 206请求的总数
  • 302 302请求的总数
  • 304 304请求的总数
  • 403 403请求的总数
  • 404 404请求的总数
  • 416 416请求的总数
  • 499 499请求的总数
  • 500 500请求的总数
  • 502 502请求的总数
  • 503 503请求的总数
  • 504 504请求的总数
  • 508 508请求的总数
  • detail_other 非以上13种status code的请求总数

如果domain数量太多,或者端口不是80,需要进行专门的配置,配置文件内容如下:
port=8080 #指定nginx的端口
top=10 #指定最多采集的域名个数,按照请求总个数排列
domain=a.com b.com #指定特定需要采集的域名列表,分隔符为空格,逗号,或者制表符
在/etc/tsar/tsar.conf中指定配置文件的路径:mod_nginx_domain on /tmp/my.conf

squid

字段含义

  • qps: 每秒请求数
  • rt: 访问平均相应时间
  • r_hit: 请求命中率
  • b_hit: 字节命中率
  • d_hit: 磁盘命中率
  • m_hit: 内存命中率
  • fdused: Number of file desc currently in use
  • fdque: Files queued for open
  • objs: StoreEntries
  • inmem: StoreEntries with MemObjects
  • hot: Hot Object Cache Items
  • size: Mean Object Size

采集方法

访问squid的mgrinfo信息获取,有些字段经过了一些patch,可能不适用外部版本

haproxy

字段含义

  • stat: 状态,1正常
  • uptime:启动持续时间
  • conns: 总的连接数
  • qps: 每秒请求数
  • hit: haproxy开启cache时的命中率
  • rt: 平均响应时间ms

采集方法

haproxy经过了patch,能够在多进程模式下进行统计信息的汇总,然后通过haproxy的本地访问其状态页面admin分析得到

lvs

字段含义

  • stat: lvs状态,1正常
  • conns: 总的连接数
  • pktin: 收到的包数
  • pktout:发出的包数
  • bytin: 收到的字节数
  • bytout:发出的字节数

采集方法

访问lvs的统计文件:/proc/net/ip_vs_stats

apache

参见:https://github.com/kongjian/tsar-apache

tcprt

私有应用,略

swift

私有应用,略

cgcpu/cgmem/cgblkio

私有应用,略

trafficserver

待补充

tmd

私有应用,略

Tagged as: Comments Off
21Dec/16

linux 下使用 rsync 进行文件 同步

Posted by Nick Xu

rsync 介绍

rsync是类unix系统下的数据镜像备份工具——remote sync。

rsync是一个功能非常强大的工具,其命令也有很多功能特色选项,我们下面就对它的选项一一进行分析说明。

它的特性如下:

可以镜像保存整个目录树和文件系统。

可以很容易做到保持原来文件的权限、时间、软硬链接等等。

无须特殊权限即可安装。

快速:第一次同步时 rsync 会复制全部内容,但在下一次只传输修改过的文件。rsync 在传输数据的过程中可以实行压缩及解压缩操作,

因此可以使用更少的带宽。

安全:可以使用scp、ssh等方式来传输文件,当然也可以通过直接的socket连接。

支持匿名传输,以方便进行网站镜像。

rysnc 的官方网站:http://rsync.samba.org/,可以从上面得到最新的版本。关于rsync算法的介绍点这里,还有陈皓blog.

rsync的使用

Rsync的命令格式可以为以下六种:

rsync [OPTION]... SRC DEST

rsync [OPTION]... SRC [USER@]HOST:DEST

rsync [OPTION]... [USER@]HOST:SRC DEST

rsync [OPTION]... [USER@]HOST::SRC DEST

rsync [OPTION]... SRC [USER@]HOST::DEST

rsync [OPTION]... rsync://[USER@]HOST[:PORT]/SRC [DEST]

rsync有六种不同的工作模式:

1. 拷贝本地文件;当SRC和DEST路径信息都不包含有单个冒号":"分隔符时就启动这种工作模式。

2.使用一个远程shell程序(如rsh、ssh)来实现将本地机器的内容拷贝到远程机器。当DEST

路径地址包含单个冒号":"分隔符时启动该模式。

3.使用一个远程shell程序(如rsh、ssh)来实现将远程机器的内容拷贝到本地机器。当SRC

地址路径包含单个冒号":"分隔符时启动该模式。

4. 从远程rsync服务器中拷贝文件到本地机。当SRC路径信息包含"::"分隔符时启动该模式。

5. 从本地机器拷贝文件到远程rsync服务器中。当DEST路径信息包含"::"分隔符时启动该模式。

6. 列远程机的文件列表。这类似于rsync传输,不过只要在命令中省略掉本地机信息即可。

可以man rsync 参考 rsync 文档,了解详细的使用方法,下面解析一些参数的使用:

rsync参数的具体解释如下:

-v, --verbose 详细模式输出

-q, --quiet 精简输出模式

-c, --checksum 打开校验开关,强制对文件传输进行校验

-a, --archive 归档模式,表示以递归方式传输文件,并保持所有文件属性,等于-rlptgoD

-r, --recursive 对子目录以递归模式处理

-R, --relative 使用相对路径信息

-b, --backup 创建备份,也就是对于目的已经存在有同样的文件名时,将老的文件重新命名为~filename。可以使用--suffix选项来指定不同的备份文件前缀。

--backup-dir 将备份文件(如~filename)存放在在目录下。

-suffix=SUFFIX 定义备份文件前缀

-u, --update 仅仅进行更新,也就是跳过所有已经存在于DST,并且文件时间晚于要备份的文件。(不覆盖更新的文件)

-l, --links 保留软链结

-L, --copy-links 想对待常规文件一样处理软链结

--copy-unsafe-links 仅仅拷贝指向SRC路径目录树以外的链结

--safe-links 忽略指向SRC路径目录树以外的链结

-H, --hard-links 保留硬链结

-p, --perms 保持文件权限

-o, --owner 保持文件属主信息

-g, --group 保持文件属组信息

-D, --devices 保持设备文件信息

-t, --times 保持文件时间信息

-S, --sparse 对稀疏文件进行特殊处理以节省DST的空间

-n, --dry-run现实哪些文件将被传输

-W, --whole-file 拷贝文件,不进行增量检测

-x, --one-file-system 不要跨越文件系统边界

-B, --block-size=SIZE 检验算法使用的块尺寸,默认是700字节

-e, --rsh=COMMAND 指定使用rsh、ssh方式进行数据同步

--rsync-path=PATH 指定远程服务器上的rsync命令所在路径信息

-C, --cvs-exclude 使用和CVS一样的方法自动忽略文件,用来排除那些不希望传输的文件

--existing 仅仅更新那些已经存在于DST的文件,而不备份那些新创建的文件

--delete 删除那些DST中SRC没有的文件

--delete-excluded 同样删除接收端那些被该选项指定排除的文件

--delete-after 传输结束以后再删除

--ignore-errors 及时出现IO错误也进行删除

--max-delete=NUM 最多删除NUM个文件

--partial 保留那些因故没有完全传输的文件,以是加快随后的再次传输

--force 强制删除目录,即使不为空

--numeric-ids 不将数字的用户和组ID匹配为用户名和组名

--timeout=TIME IP超时时间,单位为秒

-I, --ignore-times 不跳过那些有同样的时间和长度的文件

--size-only 当决定是否要备份文件时,仅仅察看文件大小而不考虑文件时间

--modify-window=NUM 决定文件是否时间相同时使用的时间戳窗口,默认为0

-T --temp-dir=DIR 在DIR中创建临时文件

--compare-dest=DIR 同样比较DIR中的文件来决定是否需要备份

-P 等同于 --partial

--progress 显示备份过程

-z, --compress 对备份的文件在传输时进行压缩处理

--exclude=PATTERN 指定排除不需要传输的文件模式

--include=PATTERN 指定不排除而需要传输的文件模式

--exclude-from=FILE 排除FILE中指定模式的文件

--include-from=FILE 不排除FILE指定模式匹配的文件

--version 打印版本信息

等等...

下面举例说明rsync的六种不同工作模式:

1)拷贝本地文件。当SRC和DES路径信息都不包含有单个冒号":"分隔符时就启动这种工作模式。
如:rsync -a  ./test.c  /backup

2)使用一个远程shell程序(如rsh、ssh)来实现将本地机器的内容拷贝到远程机器。当DES路径地址包含单个冒号":"分隔符时启动该模式。

如:rsync -avz  test.c  user@172.16.0.11:/home/user/src

3)使用一个远程shell程序(如rsh、ssh)来实现将远程机器的内容拷贝到本地机器。当SRC地址路径包含单个冒号":"分隔符时启动该模式。

如:rsync -avz user@172.16.0.11:/home/user/src  ./src

4)从远程rsync服务器中拷贝文件到本地机。当SRC路径信息包含"::"分隔符时启动该模式。

如:rsync -av user@172.16.0.11::www  /databack

5)从本地机器拷贝文件到远程rsync服务器中。当DES路径信息包含"::"分隔符时启动该模式。

如:rsync -av /databack user@172.16.0.11::www

6)列远程机的文件列表。这类似于rsync传输,不过只要在命令中省略掉本地机信息即可。

如:rsync -v rsync://172.16.78.192  /www

常见问题举例:

ssh端口更改后rsync的用法

rsync有两种常用的认证方式,一种为rsync-daemon方式,另外一种则是ssh。

ssh方式比较缺乏灵活性 一般为首选,但当远端服务器的ssh默认端口被修改后,rsync时找不到一个合适的方法来输入对方ssh服务端口号。

比如现在向机器 172.16.0.172 传送文件,但此时172.16.0.172的ssh端口已经不是 默认的22 端口。

键入命令 rsync test.c ustc@172.16.0.172:/home/ustc  出现如下的错误:

我们注意到rsync中的命令 参数  -e, --rsh=COMMAND 指定使用rsh、ssh方式进行数据同步。

参数的作用是可以使用户自由选择欲使用的shell程序来连接远端服务器,当然也可以设置成使用默认的ssh来连接,但是这样我们就可以加入ssh的参数了。

现在命令可以这样写了: rsync  -e  'ssh -p 3333'  test.c  ustc@172.16.0.172:/home/ustc

可见这是 文件传送修改ssh端口后的机器上成功,上面语句中使用了单引号,目的是为了使引号内的参数为引号内的命令所用。没有引号的话系统就会

识别-p是给rsync的一个参数了。

更多例子。。。

参考:

http://blog.csdn.net/jackdai/article/details/460460

 

 

##场景
服务器 A 192.168.1.1
服务器 B 192.168.1.2
要将 A 服务器的 /data/logs 目录同步到 B 服务器的 /home/logs 下

##执行环境
操作系统: centos 6.2

##配置
我们将使用 rsync 的 daemon 方式来完成任务
登录到 A 服务器,执行 vim /etc/rsyncd.conf
添加

uid = root
gid = root
max connections = 4
pid file = /var/run/rsyncd.pid
lock file = /var/run/rsync.lock
log file = /var/log/rsyncd.log

[logs]
path = /data/logs
ignore errors
read only = true
list = true
auth users = backup
secrets file = /etc/rsyncd.pwd

保存文件,执行vim /etc/rsyncd.pwd ,添加

backup:dahouduan.com

保存退出,执行 chmod 600 /etc/rsyncd.pwd
启动 rsync 服务 执行 rsync --daemon
登录 B 服务器 ,执行 vim /etc/rsyncd.pwd ,添加

dahouduan.com

保存退出,执行 chmod 600 /etc/rsyncd.pwd
好了,配置已经完成了,现在 A 服务器为服务端 B 服务器为客户端,现在就可以在 B 服务器上执行同步操作了

配置说明

uid = root #设置执行rsync的本地用户
gid = root #设置执行rsync的本地组
max connections = 4 #最大同时连接数
pid file = /var/run/rsyncd.pid #指定rsync服务进程的pid file
lock file = /var/run/rsync.lock #指定rsync服务端锁定文件log file = /var/log/rsyncd.log #指定rsync的log输出路径

[logs] #模块设定,可设置多个模块
path = /data/logs #同步文件的真实路径
ignore errors
read only = true #是否只读
list = true
auth users = backup #身份验证用户。这不是系统用户,而是rsync服务自定的
secrets file = /etc/rsyncd.pwd #当前模块的密码文件

开始同步

登录 B 服务器,执行

rsync -avzP --password-file=/etc/rsyncd.pwd backup@192.168.1.1::logs  /home/logs

so easy!

注意

1.如果 /home/下 logs 目录不存在将会创建,如果已经存在了, 会将 A 机器上的 /data/logs 目录下的内容同步到 B 机器上的 /home/logs/ 下
2.假如 A 机器上有一个文件 /home/logs/1.txt , 在第二次执行同步时没有修改,则不会同步
3.假如 B 机器上有一个文件 /home/logs/2.txt , A 上没有,同步时不会被删除
4.如果 B 机器上有一个文件 /home/logs/1.txt 被修改了,同步时会被 A 上对应的文件覆盖

扩展

如果要同步别的目录,只需要修改 A 服务器上的 /etc/rsyncd.conf 将 logs 部分修改或者复制一份,改成你想同步的目录就可以了,

One more thing

下面是 rsync 的语法说明:
rsync [-avrlptgoD] [-e ssh] [user@host:/dir] [/local/path]
-v :观察模式,可以列出更多的信息;
-q :与 -v 相反,安静模式,输出的信息比较少;
-r :递归复制!可以针对『目录』来处理!很重要!
-u :仅更新 (update),不会覆盖目标的新档案;
-l :复制连结文件的属性,而非连结的目标源文件内容;
-p :复制时,连同属性 (permission) 也保存不变!
-g :保存源文件的拥有群组;
-o :保存源文件的拥有人;
-D :保存源文件的装置属性 (device)
-t :保存源文件的时间参数;
-I :忽略更新时间 (mtime) 的属性,档案比对上会比较快速;
-z :加上压缩的参数!
-e :使用的信道协议,例如使用 ssh 通道,则 -e ssh
-a :相当于 -rlptgoD ,所以这个 -a 是最常用的参数了!

Tagged as: , Comments Off
25Nov/16

Mac原生系统对ntfs格式写操作支持

Posted by Nick Xu

弹出移动硬盘
执行 hdiutil eject /Volumes/Toshiba\ Portable\ Hard\ Drive/,如下输出
"disk1" unmounted.
"disk1" ejected.

创建一个目录,稍后将mount到这个目录
sodu mkdir /Volumes/MYHD

将移动硬盘以NTFS格式mount到上面的目录
sudo mount_ntfs -o rw,nobrowse /dev/disk1s1 /Volumes/MYHD/
执行完上面命令后,你可以看到你的移动硬盘灯又两起来了,没有任何输出,表示成功。

此时,你的移动硬盘可写了。 不过你不能在Finder里面操作,因为上面加了nobrowse选项。但是这个选项是必须的,否则你无法写。

Tagged as: , , Comments Off
15Nov/16

KVM虚拟机Linux系统增加硬盘

Posted by Nick Xu

Linux虚拟机在使用过程中,硬盘空间不够使用。由于前期没有做LVM,所以只能手动添加新的硬盘。

给虚拟机添加硬盘有两种方法:

1、通过virsh attach-disk命令添加一块硬盘到系统中,即时生效,但系统重启后新硬盘会消失。

2、通过修改虚拟机配置文件进行添加,永久生效。

现在我来一一介绍方法一和方法二。

方法一、通过virsh attach-disk命令添加硬盘

首先看看在未添加新硬盘系统的分区情况。

fdisk –l

df –h

clip_image001

从上图我们可以看到目前系统中只有一块硬盘vda,而且被分成3个分区,其中vda1为系统启动分区。

下面开始添加硬盘:

先使用 qemu-img添加一块新的硬盘

qemu-img create -f raw /vhost/testdisk.img 20G

clip_image002

现在开始使用virsh attach-disk命令把新硬盘添加到虚拟机上。

virsh attach-disk ilanni01 /vhost/testdisk.img vdb

clip_image003

该命令的意思是把/vhost/testdisk.img硬盘添加到虚拟机ilanni01中,并且该硬盘在虚拟机系统中显示的硬盘名称为vdb。

现在在系统中查看是否已经挂载该硬盘,使用fdisk命令,如下图:

clip_image004

以上操作是在虚拟机运行是,进行操作的。

现在我们把虚拟机关闭然后,再添加看看。

virsh destroy ilanni01

virsh list –all

clip_image005

再次使用virsh attach-disk添加新的硬盘vdc,如下命令:

virsh attach-disk ilanni01 /vhost/test1.img vdc

clip_image006

通过上图我们可以发现,通过virsh attach-disk添加硬盘时,只能是虚拟机运行时才能添加,而且是即时生效的。

现在我们重新启动虚拟机看看,如下图:

fdisk –l

clip_image007

通过上图,我们可以看到通过virsh attach-disk命令添加的硬盘在重启系统后,添加的新硬盘失效。

那么现在我们来看第二种方法通过修改配置文件来添加新硬盘。

要通过修改配置文件来添加硬盘,我们首先要关闭虚拟机,否则无法正常添加。

关闭虚拟机,然后使用virsh edit命令修改虚拟机的主配置文件。

虚拟机的所有配置文件都存放在/etc/libvirt/qemu,如下图:

clip_image008

编辑虚拟机配置文件,如下图:

clip_image009

配置文件中,我们找到有关硬盘的代码:

<disk type=’file’ device=’disk’>

<driver name=’qemu’ type=’qcow2′ cache=’none’/>

<source file=’/vhost/ilanni01.img’/>

<target dev=’vda’ bus=’virtio’/>

<address type=’pci’ domain=’0x0000′ bus=’0x00′ slot=’0x04′ function=’0x0’/>

</disk>

现在我们在</disk>这之后,添加如下的代码

<disk type=’file’ device=’disk’>

<driver name=’qemu’ type=’qcow2′ cache=’none’/>

<source file=’/vhost/testdisk.img’/>

<target dev=’vdb’ bus=’virtio’/>

</disk>

注意其中type表示硬盘的格式

file表示硬盘所在的路径

dev表示硬盘在系统中显示的硬盘名称

bus表示硬盘的接线类型,如果是windows系统一般是ide。

clip_image010

clip_image011

添加完毕后,我们来启动虚拟机看看实际的效果。

clip_image012

clip_image013

可以看到硬盘已经被添加进来了。

第一种方法和第二种方法的区别,以上两种方法都能添加硬盘。

但是如果是使用第一种方法添加的硬盘,使用virsh edit ilanni01编辑时,是无法看到第一种方法添加的硬盘的,同时在系统重启添加的硬盘会消失。也就是说使用第一种方法添加的硬盘是在ilanni01.xml这个配置文件中看不到的。

除此之外,如果是卸载硬盘,通过第一种方法添加的一定要在虚拟机运行时卸载。否则会报错,但是还会把该磁盘卸载掉。而且在此之前对硬盘的操作、分区,等都还存在。

卸载硬盘我们可以使用virsh detach-disk命令,如下图:

virsh detach-disk ilanni01 –target vdb

clip_image014

使用virsh detach-disk ilanni01 –target vdb 也可以卸载通过virsh edit ilanni01添加的硬盘。但是此时配置文件ilanni01.xml中还是有此信息的。使用 virsh attach-disk ilanni01 /vhost/testdisk.img vdb命令可以再增加,系统重启后还是存在的。

综上所述,在我们添加硬盘时,建议还是使用第二种方法。

Tagged as: Comments Off
site
site
test