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

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
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
18May/16

How To Mount a Remote Directory With SSHFS on a Linux

Posted by Nick Xu

How can I mount a remote directory with ssh on a Linux bases system? How do I use SSHFS to mount remote file systems over SSH on a Ubuntu or Debian/RHEL/CentOS/Arch Linux system?

SSH is a secure protocol and you can use it to mount a directory on a remote server or local laptop with the help of the SSHF service. With SSHFS you can mount remote server file system to your local development workstation/laptop powered by Linux.

More on SSHFS

sshfs is a filesystem based on the SSH file transfer protocol. It is used on a client system i.e. you need to install sshfs package on your local computer/laptop powered by CentOS/RHEL/Ubuntu/Debian/Arch Linux. No need to install anything on server (server1.cyberciti.biz). You only need an openssh server installed on server side. Our sample setup:

Fig.01: Our sample setup

Fig.01: Our sample setup

Installing SSHFS on a Ubuntu/Debian/Mint Linux

Type the following apt-get command:

sudo apt-get install sshfs

Sample outputs:

[sudo] password for nixcraft:
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following NEW packages will be installed:
  sshfs
0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
Need to get 41.7 kB of archives.
After this operation, 138 kB of additional disk space will be used.
Get:1 http://mirror.ox.ac.uk/sites/archive.ubuntu.com/ubuntu/ trusty/main sshfs amd64 2.5-1ubuntu1 [41.7 kB]
Fetched 41.7 kB in 1s (27.8 kB/s)
Selecting previously unselected package sshfs.
(Reading database ... 247545 files and directories currently installed.)
Preparing to unpack .../sshfs_2.5-1ubuntu1_amd64.deb ...
Unpacking sshfs (2.5-1ubuntu1) ...
Processing triggers for man-db (2.6.7.1-1ubuntu1) ...
Setting up sshfs (2.5-1ubuntu1) ...

Installing SSHFS on an Arch Linux

Type the following command:

sudo pacman -S sshfs fuse

Installing SSHFS on a RHEL (Red Hat)/CentOS Linux

First, turn on EPEL repo and then type the following yum command to install FUSE-Filesystem to access remote filesystems via SSH on a CentOS/RHEL:

sudo yum install fuse-sshfs

Sample outputs:

Loaded plugins: auto-update-debuginfo, protectbase, rhnplugin, security
This system is receiving updates from RHN Classic or RHN Satellite.
Setting up Install Process
0 packages excluded due to repository protections
Resolving Dependencies
--> Running transaction check
---> Package fuse-sshfs.x86_64 0:2.4-1.el6 will be installed
--> Processing Dependency: fuse >= 2.2 for package: fuse-sshfs-2.4-1.el6.x86_64
--> Running transaction check
---> Package fuse.x86_64 0:2.8.3-4.el6 will be installed
--> Finished Dependency Resolution
 
Dependencies Resolved
 
=======================================================================================================================
 Package                   Arch                  Version                     Repository                           Size
=======================================================================================================================
Installing:
 fuse-sshfs                x86_64                2.4-1.el6                   epel                                 52 k
Installing for dependencies:
 fuse                      x86_64                2.8.3-4.el6                 rhel-x86_64-server-6                 71 k
 
Transaction Summary
=======================================================================================================================
Install       2 Package(s)
 
Total download size: 123 k
Installed size: 115 k
Is this ok [y/N]: y
Downloading Packages:
(1/2): fuse-2.8.3-4.el6.x86_64.rpm                                                              |  71 kB     00:00
(2/2): fuse-sshfs-2.4-1.el6.x86_64.rpm                                                          |  52 kB     00:00
-----------------------------------------------------------------------------------------------------------------------
Total                                                                                  173 kB/s | 123 kB     00:00
Running rpm_check_debug
Running Transaction Test
Transaction Test Succeeded
Running Transaction
  Installing : fuse-2.8.3-4.el6.x86_64                                                                             1/2
  Installing : fuse-sshfs-2.4-1.el6.x86_64                                                                         2/2
  Verifying  : fuse-sshfs-2.4-1.el6.x86_64                                                                         1/2
  Verifying  : fuse-2.8.3-4.el6.x86_64                                                                             2/2
 
Installed:
  fuse-sshfs.x86_64 0:2.4-1.el6
 
Dependency Installed:
  fuse.x86_64 0:2.8.3-4.el6
 
Complete!

How do I mount the remote file system?

The syntax is

sshfs user@server /path/to/mountpoint
sshfs user@server /path/to/mountpoint options

First, create a directory using mkdir command:

sudo mkdir /mnt/server1

I’m going to mount file system using root user and you need to type root password when prompted:

sudo sshfs root@192.168.1.142:/ /mnt/server1/
 
##  OR use ssh key based login ##
sudo sshfs -o IdentityFile=~/.ssh/keyfile /mnt/server1/

Sample outputs:

Password for root@freebsd10:

Verify it:

sudo df -h

Sample outputs:

Filesystem              Size  Used Avail Use% Mounted on
/dev/mapper/wks05-root  487G  114G  350G  25% /
none                    4.1k     0  4.1k   0% /sys/fs/cgroup
udev                     17G  4.1k   17G   1% /dev
tmpfs                   3.4G  1.9M  3.4G   1% /run
none                    5.3M     0  5.3M   0% /run/lock
none                     17G  160k   17G   1% /run/shm
none                    105M   50k  105M   1% /run/user
/dev/sda1               239M   89M  138M  40% /boot
root@192.168.1.142:/     20G   12G  6.8G  64% /mnt/server1

To access and/or to see the remote file system, run:

sudo -s
cd /mnt/server1
ls -l

Sample ouputs:

Fig. 02: sshfs in action

Fig. 02: sshfs in action

Dealing with “Permission denied” error and recommended procedure for mounting the remote directory

If you get an error that read as cannot access server1: Permission denied, add yourself to a group called fuse:

$ sudo gpasswd -a "$USER" fuse
Adding user nixcraft to group fuse

Next, create a mount point inside your own home directory:

$ mkdir $HOME/server1
$ ls -ld !$
ls -ld $HOME/server1
drwxrwxr-x 2 nixcraft nixcraft 4096 Mar  8 04:34 /home/nixcraft/server1

To mount the remote file system, enter:

sshfs -o idmap=user  root@192.168.1.142:/ $HOME/server1
df
ls -l $HOME/server1
Fig.03: Using sshfs without root access on local laptop/desktop

Fig.03: Using sshfs without root access on local laptop/desktop

How do I unmount the remote file system?

The syntax is:

sudo umount /mnt/server1
 
## OR ##
fusermount -u /mnt/server1

Verify it:

df -h

How can I permanently mount the remote file system by updating /etc/fstab?

Edit the /etc/fstab file, enter:

sudo vi /etc/fstat

The syntax is:

userNameHere@FQDN_OR_IP_HERE:/path/to/source/  /local/mountdir/  fuse.sshfs  defaults,_netdev  0  0

Examples

Add the following entry at the bottom of the file:

sshfs#root@192.168.1.142:/ /mnt/server1

Another example with additional options:

sshfs#$root@192.168.1.142:/ /mnt/server1 fuse defaults,idmap=user,allow_other,reconnect,_netdev,users,IdentityFile=/path/to/.ssh/keyfile 0 0

Recommend option for on-demand mounting if you are using systemd:

vivek@server1.cyberciti.biz:/project/www/ /mnt/server1  fuse.sshfs noauto,x-systemd.automount,_netdev,users,idmap=user,IdentityFile=/home/vivek/.ssh/id_rsa,allow_other,reconnect 0 0

Save and close the file. Where,

  1. root@192.168.1.142 : Remote server with sshd
  2. fuse : File system type.
  3. idmap=user : Only translate UID of connecting user.
  4. allow_other : Allow access to other users.
  5. reconnect : Reconnect to server.
  6. _netdev : The filesystem resides on a device that requires network access (used to prevent the system from attempting to mount these filesystems until the network has been enabled on the system).
  7. users : Allow every user to mount and unmount the filesystem.
  8. IdentityFile=/path/to/.ssh/keyfile – SSH key file.
12Nov/15

NUMA架构的CPU — 你真的用好了么?

Posted by Nick Xu

本文从NUMA的介绍引出常见的NUMA使用中的陷阱,继而讨论对于NUMA系统的优化方法和一些值得关注的方向。

文章欢迎转载,但转载时请保留本段文字,并置于文章的顶部
作者:卢钧轶(cenalulu)
本文原文地址:http://cenalulu.github.io/linux/numa/

NUMA简介

这部分将简要介绍下NUMA架构的成因和具体原理,已经了解的读者可以直接跳到第二节。

为什么要有NUMA

在NUMA架构出现前,CPU欢快的朝着频率越来越高的方向发展。受到物理极限的挑战,又转为核数越来越多的方向发展。如果每个core的工作性质都是share-nothing(类似于map-reduce的node节点的作业属性),那么也许就不会有NUMA。由于所有CPU Core都是通过共享一个北桥来读取内存,随着核数如何的发展,北桥在响应时间上的性能瓶颈越来越明显。于是,聪明的硬件设计师们,先到了把内存控制器(原本北桥中读取内存的部分)也做个拆分,平分到了每个die上。于是NUMA就出现了!

NUMA是什么

NUMA中,虽然内存直接attach在CPU上,但是由于内存被平均分配在了各个die上。只有当CPU访问自身直接attach内存对应的物理地址时,才会有较短的响应时间(后称Local Access)。而如果需要访问其他CPU attach的内存的数据时,就需要通过inter-connect通道访问,响应时间就相比之前变慢了(后称Remote Access)。所以NUMA(Non-Uniform Memory Access)就此得名。

numa

我们需要为NUMA做什么

假设你是Linux教父Linus,对于NUMA架构你会做哪些优化?下面这点是显而易见的:

既然CPU只有在Local-Access时响应时间才能有保障,那么我们就尽量把该CPU所要的数据集中在他local的内存中就OK啦~

没错,事实上Linux识别到NUMA架构后,默认的内存分配方案就是:优先尝试在请求线程当前所处的CPU的Local内存上分配空间。如果local内存不足,优先淘汰local内存中无用的Page(Inactive,Unmapped)。
那么,问题来了。。。


NUMA的“七宗罪”

几乎所有的运维都会多多少少被NUMA坑害过,让我们看看究竟有多少种在NUMA上栽的方式:

究其原因几乎都和:“因为CPU亲和策略导致的内存分配不平均”及“NUMA Zone Claim内存回收”有关,而和数据库种类并没有直接联系。所以下文我们就拿MySQL为例,来看看重内存操作应用在NUMA架构下到底会出现什么问题。

MySQL在NUMA架构上会出现的问题

几乎所有NUMA + MySQL关键字的搜索结果都会指向:Jeremy Cole大神的两篇文章

大神解释的非常详尽,有兴趣的读者可以直接看原文。博主这里做一个简单的总结:

  • CPU规模因摩尔定律指数级发展,而总线发展缓慢,导致多核CPU通过一条总线共享内存成为瓶颈
  • 于是NUMA出现了,CPU平均划分为若干个Chip(不多于4个),每个Chip有自己的内存控制器及内存插槽
  • CPU访问自己Chip上所插的内存时速度快,而访问其他CPU所关联的内存(下文称Remote Access)的速度相较慢三倍左右
  • 于是Linux内核默认使用CPU亲和的内存分配策略,使内存页尽可能的和调用线程处在同一个Core/Chip中
  • 由于内存页没有动态调整策略,使得大部分内存页都集中在CPU 0
  • 又因为Reclaim默认策略优先淘汰/Swap本Chip上的内存,使得大量有用内存被换出
  • 当被换出页被访问时问题就以数据库响应时间飙高甚至阻塞的形式出现了

imbalance

解决方案

Jeremy Cole大神推荐的三个方案如下,如果想详细了解可以阅读 原文

  • numactl --interleave=all
  • 在MySQL进程启动前,使用sysctl -q -w vm.drop_caches=3清空文件缓存所占用的空间
  • Innodb在启动时,就完成整个Innodb_buffer_pool_size的内存分配

这三个方案也被业界普遍认可可行,同时在 Twitter 的5.5patchPercona 5.5 Improved NUMA Support 中作为功能被支持。

不过这种三合一的解决方案只是减少了NUMA内存分配不均,导致的MySQL SWAP问题出现的可能性。如果当系统上其他进程,或者MySQL本身需要大量内存时,Innodb Buffer Pool的那些Page同样还是会被Swap到存储上。于是又在这基础上出现了另外几个进阶方案

  • 配置vm.zone_reclaim_mode = 0使得内存不足时去remote memory分配优先于swap out local page
  • echo -15 > /proc/<pid_of_mysqld>/oom_adj调低MySQL进程被OOM_killer强制Kill的可能
  • memlock
  • 对MySQL使用Huge Page(黑魔法,巧用了Huge Page不会被swap的特性)

重新审视问题

如果本文写到这里就这么结束了,那和搜索引擎结果中大量的Step-by-Step科普帖没什么差别。虽然我们用了各种参数调整减少了问题发生概率,那么真的就彻底解决了这个问题么?问题根源究竟是什么?让我们回过头来重新审视下这个问题:

NUMA Interleave真的好么?

为什么Interleave的策略就解决了问题?
借用两张 Carrefour性能测试 的结果图,可以看到几乎所有情况下Interleave模式下的程序性能都要比默认的亲和模式要高,有时甚至能高达30%。究其根本原因是Linux服务器的大多数workload分布都是随机的:即每个线程在处理各个外部请求对应的逻辑时,所需要访问的内存是在物理上随机分布的。而Interleave模式就恰恰是针对这种特性将内存page随机打散到各个CPU Core上,使得每个CPU的负载和Remote Access的出现频率都均匀分布。相较NUMA默认的内存分配模式,死板的把内存都优先分配在线程所在Core上的做法,显然普遍适用性要强很多。
perf1
perf2

也就是说,像MySQL这种外部请求随机性强,各个线程访问内存在地址上平均分布的这种应用,Interleave的内存分配模式相较默认模式可以带来一定程度的性能提升。
此外 各种 论文 中也都通过实验证实,真正造成程序在NUMA系统上性能瓶颈的并不是Remote Acess带来的响应时间损耗,而是内存的不合理分布导致Remote Access将inter-connect这个小水管塞满所造成的结果。而Interleave恰好,把这种不合理分布情况下的Remote Access请求平均分布在了各个小水管中。所以这也是Interleave效果奇佳的一个原因。

那是不是简简单单的配置个Interleave就已经把NUMA的特性和性能发挥到了极致呢?
答案是否定的,目前Linux的内存分配机制在NUMA架构的CPU上还有一定的改进空间。例如:Dynamic Memory Loaction, Page Replication。

Dynamic Memory Relocation
我们来想一下这个情况:MySQL的线程分为两种,用户线程(SQL执行线程)和内部线程(内部功能,如:flush,io,master等)。对于用户线程来说随机性相当的强,但对于内部线程来说他们的行为以及所要访问的内存区域其实是相对固定且可以预测的。如果能对于这把这部分内存集中到这些内存线程所在的core上的时候,就能减少大量Remote Access,潜在的提升例如Page Flush,Purge等功能的吞吐量,甚至可以提高MySQL Crash后Recovery的速度(由于recovery是单线程)。
那是否能在Interleave模式下,把那些明显应该聚集在一个CPU上的内存集中在一起呢?
很可惜,Dynamic Memory Relocation这种技术目前只停留在理论和实验阶段。我们来看下难点:要做到按照线程的行为动态的调整page在memory的分布,就势必需要做线程和内存的实时监控(profile)。对于Memory Access这种非常异常频繁的底层操作来说增加profile入口的性能损耗是极大的。在 关于CPU Cache程序应该知道的那些事的评论中我也提到过,这个道理和为什么Linux没有全局监控CPU L1/L2 Cache命中率工具的原因是一样的。当然优化不会就此停步。上文提到的Carrefour算法和Linux社区的Auto NUMA patch都是积极的尝试。什么时候内存profile出现硬件级别,类似于CPU中 PMU 的功能时,动态内存规划就会展现很大的价值,甚至会作为Linux Kernel的一个内部功能来实现。到那时我们再回过头来审视这个方案的实际价值。

Page Replication
再来看一下这些情况:一些动态加载的库,把他们放在任何一个线程所在的CPU都会导致其他CPU上线程的执行效率下降。而这些共享数据往往读写比非常高,如果能把这些数据的副本在每个Memory Zone内都放置一份,理论上会带来较大的性能提升,同时也减少在inter-connect上出现的瓶颈。实时上,仍然是上文提到的Carrefour也做了这样的尝试。由于缺乏硬件级别(如MESI协议的硬件支持)和操作系统原生级别的支持,Page Replication在数据一致性上维护的成本显得比他带来的提升更多。因此这种尝试也仅仅停留在理论阶段。当然,如果能得到底层的大力支持,相信这个方案还是有极大的实际价值的。

究竟是哪里出了问题

NUMA的问题?
NUMA本身没有错,是CPU发展的一种必然趋势。但是NUMA的出现使得操作系统不得不关注内存访问速度不平均的问题。

Linux Kernel内存分配策略的问题?
分配策略的初衷是好的,为了内存更接近需要他的线程,但是没有考虑到数据库这种大规模内存使用的应用场景。同时缺乏动态调整的功能,使得这种悲剧在内存分配的那一刻就被买下了伏笔。

数据库设计者不懂NUMA?
数据库设计者也许从一开始就不会意识到NUMA的流行,或者甚至说提供一个透明稳定的内存访问是操作系统最基本的职责。那么在现状改变非常困难的情况下(下文会提到为什么困难)是不是作为内存使用者有义务更好的去理解使用NUMA?

总结

其实无论是NUMA还是Linux Kernel,亦或是程序开发他们都没有错,只是还做得不够极致。如果NUMA在硬件级别可以提供更多低成本的profile接口;如果Linux Kernel可以使用更科学的动态调整策略;如果程序开发人员更懂NUMA,那么我们完全可以更好的发挥NUMA的性能,使得无限横向扩展CPU核数不再是一个梦想。

Tagged as: , , Comments Off
11May/15

mac下的strace命令 

Posted by Nick Xu

strace在linux下用来跟踪某个进程的系统调用
在solaris下,对应的是dtrace
在mac下,对应的命令是:dtruss

24Jun/14

linux升级openssl和php_openssl模块

Posted by Nick Xu

一、OpenSSL源码升级

2014年4月8日,XP宣布正式停止服务的日子,也是OpenSSL爆出大漏洞的日子。

OpenSSL主要是负责在一些敏感的数据提交上面被广泛使用,不乏大家经常访问的一些网站:支付宝、微信、淘宝、网银、社交、门户等知名网站。

官方上面推荐大家将OpenSSL升级到OpenSSL 1.0.1g

这不火急火燎的加入的升级大军,先查看下自己机器上的OpenSSL版本。

1
2
openssl version
#OpenSSL 1.0.0-fips 29 Mar 2010

很明显不是官方所说的版本,必须要升级好吧,我们以源码的形式。先去下载相对应的OpenSSL版本。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
cd /usr/local/src/
wget http://www.openssl.org/source/openssl-1.0.1g.tar.gz
tar -zxvf openssl-1.0.1g.tar.gz
cd  openssl-1.0.1g
./config shared zlib
make && make install
#修改历史的OpenSSL文件设置备份
mv /usr/bin/openssl /usr/bin/openssl.old
mv /usr/include/openssl /usr/include/openssl.old
#设置软连接使其使用新的OpenSSL版本 刚刚安装的OpenSSL默认安装在/usr/local/ssl
ln -s /usr/local/ssl/bin/openssl /usr/bin/openssl
ln -s /usr/local/ssl/include/openssl /usr/include/openssl
#更新动态链接库数据
echo "/usr/local/ssl/lib" >> /etc/ld.so.conf
ldconfig -v

我们再来看看OpenSSL版本信息.

1
2
3
openssl version
#OpenSSL 1.0.1g 7 Apr 2014

如果是1.0.1g,说明你安装正确了。

二、php_openssl组件版本更新

1、与php一同设置的编译参数情况

如果你和我一样很久很久以前安装了php的版本,而且又是在编译php版本的时候直接使用“–with-openssl”的话,似乎也没有添加什么路径的话,那么你现在可能需要重新再编译你的php版本了,首先我们要获取到当时编译php的参数,注意你的php源码版本要一致哦,当然你可以重新升级你的php版本也无妨(如果你选择升级php版本可能会导致你安装的一些组件无法使用,或者在启动php-fpm时候会有错误提示,我还是不太建议大家升级php版本,最好是找当前版本一直的源码进行重新编译)。

1
2
3
4
5
6
7
#查看php版本
/usr/local/php/bin/php -v
#获取php编译时的参数
/usr/local/php/bin/php -i | grep Command
#./configure'  '--prefix=/usr/local/php' '--with-mysql' '--with-mysqli' '--with-iconv-dir' '--with-zlib' '--with-libxml-dir' '--enable-xml' '--with-curl' '--enable-fpm' '--enable-mbstring' '--with-gd' '--with-openssl' '--with-mhash' '--enable-sockets' '--with-xmlrpc' '--enable-zip' '--enable-soap' '--disable-fileinfo'

注意把这些“’”都去掉,因为我们采用了源码升级OpenSSL的方式,所以新的OpenSSL安装路径在上面提到了

1
2
3
4
5
cd /usr/local/src/php-5.5.6
./configure  --prefix=/usr/local/php --with-mysql --with-mysqli --with-iconv-dir --with-zlib --with-libxml-dir --enable-xml --with-curl --enable-fpm --enable-mbstring --with-gd --with-openssl=/usr/local/ssl/ --with-mhash --enable-sockets --with-xmlrpc --enable-zip --enable-soap --disable-fileinfo
make && make install

你采用的是和之前源码安装一样的版本库无非就是重新编译一次需要点时间,其他都不需要修改就可以安装对openssl的升级了。我们重启下php-fpm服务。

1
service php-fpm restart

然后我们去phpinfo()函数输出里面去找找openssl的版本是否是OpenSSL 1.0.1g,是的话就证明一切操作都顺利了。
到这里或许你可能会说我为什么不用phpize了,这不是有点累死人的节奏,我是尝试过了,一开始就对php_openssl进行单独模块编译,编译好了之后,重新去启动php-fpm告诉我下面这个提示。

1
PHP Warning: Module 'openssl' already loaded in Unknown on line 0 ……

也就是说OpenSSL已经被加载了请不要重复加载,可是我将php.ini文件仔细查看也没有重复添加openssl组件,我的猜想应该是在php编译的时候配置了,所以你使用phpize添加进去的模块当然是重复的模块了。

2、未启用php_openssl模块

貌似这种情况有点差强人意的感觉,因为你从来没有使用过openssl,何必要升级呢?除非你有新的业务需要。咳咳,扯淡了。
如果你没有上面第一种情况的话,那么这种方式应该是你的最佳方式了。

1
2
3
4
5
6
7
cd /usr/local/src/php-5.5.6/ext/openssl
/usr/local/php/bin/phpize
./configure --with-openssl=/usr/local/ssl/ --with-php-config=/usr/local/php/bin/php-config
make && make install

最后就在/usr/local/php/lib/php.ini文件中添加一行

1
extension=openssl.so

重启php-fpm,去phpinfo()找找openssl的版本看看。

openssl_php_update

12Dec/13

ssh证书登录方式

Posted by Nick Xu

在/etc/ssh/sshd_config中将以下注释去掉(去掉行首的#号)

 

  1. RSAAuthentication yes
  2. PubkeyAuthentication yes
  3. AuthorizedKeysFile  %h/.ssh/authorized_keys

  4. PasswordAuthentication no

 

加入登录通知机制:

/etc/pam.d/sshd

加入 session optional pam_exec.so seteuid /root/notify.sh

linux下ssh登录限制ip的方法

vi /etc/hosts.allow
sshd:192.168.0.100:allow          //允许IP 192.168.0.100 登录
sshd:192.168.0.:allow            //允许IP 192.168.0.  网段登录
sshd:all:deny                     //禁止其他的所有IP登录
或者
sshd:223.227.223.*:allow              //允许IP 223.227.223.*   网段登录
sshd:192.168.0.*:allow                //允许IP 192.168.0.*  网段登录
sshd:all:deny                                //禁止其他的所有IP登录

fedora下 修改后保存后生效

 

客户端

ssh可以使用密钥对互相建立信任,以后再链接信任的计算机就不需要输入密码了。

1、建立密钥对
niu@niu:~$ ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/niu/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/niu/.ssh/id_rsa.
Your public key has been saved in /home/niu/.ssh/id_rsa.pub.
The key fingerprint is:
27:00:f4:ce:a0:6f:61:a8:55:27:af:9a:bc:2b:d5:21 niu@niu
niu@niu:~$
过程中就一直按回车即可。此时会在 /home/niu/.ssh/ 目录下生成一对文件 id_rsa, id_rsa.pub

2、配置远程计算机
将id_ras.pub文件复制到远程计算机待登录用户个人目录下的.ssh目录中(如不存在自己创建),并将文件名改为 authorized_keys

3、完成

 

 

18Jul/12

在linux下编译安装nginx+php(fastcgi)

Posted by Nick Xu

nginx使用fastcgi方式连接php,在linux下面编译安装时要编译php支持fastcgi方式,其他的一些东西,照着原来的方式装就可以了。

分为以下步骤:

1、安装php的fastcgi版
2、使用spawn-fcgi启动php的fastcgi引擎
3、配置nginx连接php的fastcgi引擎

1、安装php的fastcgi版

mkdir /usr/local/modules

#jpeg目录
mkdir /usr/local/modules/jpeg6
mkdir /usr/local/modules/jpeg6/bin
mkdir /usr/local/modules/jpeg6/lib
mkdir /usr/local/modules/jpeg6/include
mkdir /usr/local/modules/jpeg6/man
mkdir /usr/local/modules/jpeg6/man/man1

A1、安装zlib

tar xzvf zlib-1.2.1.tar.gz
cd zlib-1.2.1
#不要用--prefix自定义安装目录,影响gd的安装
./configure
make
make install

A2、安装freetype

tar xzvf freetype-2.1.5.tar.gz
cd freetype-2.1.5
./configure --prefix=/usr/local/modules/freetype
make
make install

A3、安装libpng

tar xzvf libpng-1.2.5.tar.gz
#不要用--prefix自定义安装目录,影响gd的安装
cd libpng-1.2.5
cp scripts/makefile.std makefile
make test
make install

A3、安装jpeg

tar xzvf jpegsrc.v6b.tar.gz
cd jpeg-6b
./configure --prefix=/usr/local/modules/jpeg6 --enable-shared --enable-static
make
make install

A4、安装GD

tar xzvf gd-2.0.28.tar.gz
./configure --prefix=/usr/local/modules/gd --with-jpeg=/usr/local/modules/jpeg6 --with-png --with-zlib --with-freetype=/usr/local/modules/freetype
make
make install

然后编译安装php,注意加上--enable-fastcgi参数和--enable-force-cgi-redirect参数

./configure --prefix=/usr/local/php --with-gd=/usr/local/modules/gd --with-jpeg-dir=/usr/local/modules/jpeg6 --with-zlib --with-png --with-freetype-dir=/usr/local/modules/freetype --enable-magic-quotes --enable-fastcgi --with-mysql=/usr/local/mysql --enable-track-vars --enable-ftp --with-config-file-path=/usr/local/php/etc --with-zip --enable-force-cgi-redirect
make -j10
make install

如果过程中发现有错误:

mysql的错误在ubuntu 12.04 x64上解决方法:
sudo ln -s /usr/lib/x86_64-linux-gnu/libmysqlclient.so.18 /usr/lib64/
sudo ln -s /usr/lib/x86_64-linux-gnu/libmysqlclient.so /usr/lib64/
2、使用spawn-fcgi启动php的fastcgi引擎

编译完成后在/usr/local/php/bin/下面就会有php-cgi这个可执行程序,使用spawn-fcgi启动php的fastcgi引擎:

/data/nginx/sbin/spawn-fcgi -a 127.0.0.1 -p 9000 -u nobody -f /usr/bin/php-cgi -C 20

意思是fastcgi使用本机ip和端口9000提供服务,权限nobody,启动20个进程。其中主要留意-C这个参数,一般20个进程足够用了,觉得不够亦可开大,在我的机器上每个php-cgi进程会占用7-8兆内存,开100个就是700-800兆。

spawn-fcgi这个程序在nginx里没有提供,可以在

http://www.sudone.com/download/spawn-fcgi

下载到,一般放在nginx的sbin目录下,然后要给它加上可执行权限:

chmod +x /data/nginx/sbin/spawn-fcgi

3、配置nginx连接php的fastcgi引擎

首先弄一份fastcgi-params配置,在nginx的conf目录下建一份文本文件,内容是:

#fastcgi-params
fastcgi_param  QUERY_STRING       $query_string;
fastcgi_param  REQUEST_METHOD     $request_method;
fastcgi_param  CONTENT_TYPE       $content_type;
fastcgi_param  CONTENT_LENGTH     $content_length;

fastcgi_param  SCRIPT_NAME        $fastcgi_script_name;
fastcgi_param  REQUEST_URI        $request_uri;
fastcgi_param  DOCUMENT_URI       $document_uri;
fastcgi_param  DOCUMENT_ROOT      $document_root;
fastcgi_param  SERVER_PROTOCOL    $server_protocol;

fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;
fastcgi_param  SERVER_SOFTWARE    nginx;

fastcgi_param  REMOTE_ADDR        $remote_addr;
fastcgi_param  REMOTE_PORT        $remote_port;
fastcgi_param  SERVER_ADDR        $server_addr;
fastcgi_param  SERVER_PORT        $server_port;
fastcgi_param  SERVER_NAME        $server_name;

# PHP only, required if PHP was built with --enable-force-cgi-redirect
fastcgi_param  REDIRECT_STATUS    200;
#end

这个是最原始的fastcgi-params,在网上也可能有更优化的版本,可以相应取用。

然后配置nginx.conf,比如www.sudone.com,这样配置就可以用了:

server {
include port.conf;
server_name www.sudone.com sudone.com;

location / {
index index.html index.php;
root /data/sudone/php/;
}

location ~ .php$ {
fastcgi_pass   127.0.0.1:9000;
fastcgi_index  index.php;
fastcgi_param  SCRIPT_FILENAME  /data/sudone/php$fastcgi_script_name;
include        fastcgi_params;
}
}

拿下来之后,有几个需要改的地方:

1、server_name
2、location /里面的root
3、location ~ .php$里面的fastcgi_param  SCRIPT_FILENAME

其中fastcgi_param  SCRIPT_FILENAME的参数中,$fastcgi_script_name前面是php文件的路径一般和root一样的,最后不用写/,貌似会有点问题,不要画蛇添足。

注意事项:

可能会有的管理员启动nginx后总是忘记启动spawn-fcgi,所以最好是写一份脚本来启动,然后要养成测试服务可用性的习惯。

7Aug/11

用monit监控系统关键进程

Posted by Nick Xu

monit是一款功能强大的系统状态、进程、文件、目录和设备的监控软件,用于*nix平台, 它可以自动重启那些已经挂掉的程序,非常适合监控系统关键的进程和资源,如:nginx、apache、mysql和cpu占有率等。而监控管理Python进程,常用的是supervisor,后续会另外撰文介绍。

下面分别介绍monit的安装、配置和启动。

安装

在debian或ubuntu上安装monit非常方便,通过下面的命令

sudo apt-get install monit

即可,其它*nix上也很简单,下载源码走一遍安装三步就OK了。

./configure
make
make install

安装后,默认的配置文件为/etc/monit/monitrc。

配置

添加需要监控的进程等信息至monit的配置文件,monit的配置详见下面的示例文件,为了便于理解,关键的配置我都给出了中文的注释。

##
## 飞龙日志 示例monit配置文件,说明:
## 1. 域名以example.com为例。
## 2. 后面带xxx的均是举例用的名字,需要根据自己的需要修改。
##
###############################################################################
## Monit control file
###############################################################################
#
# 检查周期,默认为2分钟,对于网站来说有点长,可以根据需要自行调节,这改成30秒。
set daemon  30

# 日志文件
set logfile /var/log/monit.log

#
# 邮件通知服务器
#
#set mailserver mail.example.com
set mailserver localhost           

#
# 通知邮件的格式设置,下面是默认格式供参考
#
## Monit by default uses the following alert mail format:
##
## --8<--
## From: monit@$HOST                         # sender
## Subject: monit alert --  $EVENT $SERVICE  # subject
##
## $EVENT Service $SERVICE                   #
##                                           #
## 	Date:        $DATE                   #
## 	Action:      $ACTION                 #
## 	Host:        $HOST                   # body
## 	Description: $DESCRIPTION            #
##                                           #
## Your faithful employee,                   #
## monit                                     #
## --8<--
##
## You can override the alert message format or its parts such as subject
## or sender using the MAIL-FORMAT statement. Macros such as $DATE, etc.
## are expanded on runtime. For example to override the sender:
#
# 简单的,这只改了一下发送人,有需要可以自己修改其它内容。
set mail-format { from: webmaster@example.com }

# 设置邮件通知接收者。建议发到gmail,方便邮件过滤。
set alert userxxx@gmail.com

set httpd port 2812 and            # 设置http监控页面的端口
     use address www.example.com   # http监控页面的IP或域名
     allow localhost               # 允许本地访问
     allow 58.68.78.0/24           # 允许此IP段访问
     ##allow 0.0.0.0/0.0.0.0       # 允许任何IP段,不建议这样干
     allow userxxx:passwordxxx     # 访问用户名密码

###############################################################################
## Services
###############################################################################
#
# 系统整体运行状况监控,默认的就可以,可以自己去微调
#
# 系统名称,可以是IP或域名
check system www.example.com
    if loadavg (1min) > 4 then alert
    if loadavg (5min) > 2 then alert
    if memory usage > 75% then alert
    if cpu usage (user) > 70% then alert
    if cpu usage (system) > 30% then alert
    if cpu usage (wait) > 20% then alert

#
# 监控nginx
#
# 需要提供进程pid文件信息
check process nginx with pidfile /var/run/nginx.pid
    # 进程启动命令行,注:必须是命令全路径
    start program = "/etc/init.d/nginx start"
    # 进程关闭命令行
    stop program  = "/etc/init.d/nginx stop"
    # nginx进程状态测试,监测到nginx连不上了,则自动重启
    if failed host www.example.com port 80 protocol http then restart
    # 多次重启失败将不再尝试重启,这种就是系统出现严重错误的情况
    if 3 restarts within 5 cycles then timeout
    # 可选,设置分组信息
    group server

#   可选的ssl端口的监控,如果有的话
#    if failed port 443 type tcpssl protocol http
#       with timeout 15 seconds
#       then restart

#
# 监控apache
#
check process apache with pidfile /var/run/apache2.pid
    start program = "/etc/init.d/apache2 start"
    stop program  = "/etc/init.d/apache2 stop"
    # apache吃cpu和内存比较厉害,额外添加一些关于这方面的监控设置
    if cpu > 50% for 2 cycles then alert
    if cpu > 70% for 5 cycles then restart
    if totalmem > 1500 MB for 10 cycles then restart
    if children > 250 then restart
    if loadavg(5min) greater than 10 for 20 cycles then stop
    if failed host www.example.com port 8080 protocol http then restart
    if 3 restarts within 5 cycles then timeout
    group server
    # 可选,依赖于nginx
    depends on nginx

#
# 监控spawn-fcgi进程(其实就是fast-cgi进程)
#
check process spawn-fcgi with pidfile /var/run/spawn-fcgi.pid
    # spawn-fcgi一定要带-P参数才会生成pid文件,默认是没有的
    start program = "/usr/bin/spawn-fcgi -a 127.0.0.1 -p 8081 -C 10 -u userxxx -g groupxxx -P /var/run/spawn-fcgi.pid -f /usr/bin/php-cgi"
    stop program = "/usr/bin/killall /usr/bin/php-cgi"
    # fast-cgi走的不是http协议,monit的protocol参数也没有cgi对应的设置,这里去掉protocol http即可。
    if failed host 127.0.0.1 port 8081 then restart
    if 3 restarts within 5 cycles then timeout
    group server
    depends on nginx

虽然在注释里有详细说明,但是我还是要再强调说明几点:

  1. start和stop的program参数里的命令必须是全路径,否则monit不能正常启动,比如killall应该是/usr/bin/killall。
  2. 对于spawn-fcgi,很多人会用它来管理PHP的fast-cgi进程,但spawn-fcgi本身也是有可能挂掉的,所以还是需要用 monit来监控spawn-fcgi。spawn-fcgi必须带-P参数才会有pid文件,而且fast-cgi走的不是http协议,monit的 protocol参数也没有cgi对应的设置,一定要去掉protocol http这项设置才管用。
  3. 进程多次重启失败monit将不再尝试重启,收到这样的通知邮件表明系统出现了严重的问题,要引起足够的重视,需要赶紧人工处理。

当然monit除了管理进程之外,还可以监控文件、目录、设备等,本文不做讨论,具体配置方式可以去参考monit的官方文档

启动、停止、重启

标准的start、stop、restart

sudo /etc/init.d/monit start
sudo /etc/init.d/monit stop
sudo /etc/init.d/monit restart

看到正确的提示信息即可,若遇到问题可以去查看配置里指定的日志文件,如/var/log/monit.log。

从我的服务器这几年的运行情况(monit发了的通知邮件)来看,nginx挂掉的事几乎没有,但apache或fast-cgi出问题的情况还是比较多见,赶快用上monit来管理你的服务器以提高服务器稳定性,跟502 Bad Gateway之类错误说拜拜吧。

附件:monit示例配置文件 (注:下载后请去掉.txt文件后缀)

Tagged as: , No Comments
6Aug/11

linux下安装ZendOptimizer支持

Posted by Nick Xu

wget http://nick.txtcc.com/nickfiles/ZendOptimizer-3.3.9-linux-glibc23-i386.tar.gz

解压后复制到/usr/lib/php5/ZendOptimizer.so

修改php.ini 加入下面的内容

zend_extension=/usr/lib/php5/ZendOptimizer.so

 

 

 

 

 

 

wget http://pecl.php.net/get/vld

wget http://www.php.net/get/php-5.2.17.tar.gz/from/cn.php.net/mirror

mv mirror php.tar.gz

 

sudo apt-get install autoconf

wget http://nick.txtcc.com/nickfiles/libxml2-2.7.2.tar.gz
tar -xzvf libxml2-2.7.2.tar.gz
cd libxml2-2.7.2
sudo ./configure
sudo make install

sudo apt-get install libmysqlclient-dev

 

 

#tar -xzf vld-0.8.0.tgz //解压
#mv vld-0.8.0 vld //重命名
#cd -R vld ../php-4.3.8/ext //拷贝vld目录到php的解压目录下的ext中
#cd php-4.3.8
#rm configure //删除configure,因为下面的buildconf会重新生成新的configure
#./buildconf //如果出现错误,就按提示加上相应的参数.
#./configure –with-mysql –with-apxs2=/usr/www/bin/apxs –enable-vld 重新检查php
#make 编译
#make install 安装

服务器必须先安装ZendOptimizer
运行Zend后的文件,查看源代码就可以看到了.

site
site