linux awk命令详解
http://www.chinaunix.net/old_jh/7/16985.html
linux 下使用 rsync 进行文件 同步
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 是最常用的参数了!
How To Mount a Remote Directory With SSHFS on a Linux
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
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
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
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,
- root@192.168.1.142 : Remote server with sshd
- fuse : File system type.
- idmap=user : Only translate UID of connecting user.
- allow_other : Allow access to other users.
- reconnect : Reconnect to server.
- _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).
- users : Allow every user to mount and unmount the filesystem.
- IdentityFile=/path/to/.ssh/keyfile – SSH key file.
NUMA架构的CPU — 你真的用好了么?
本文从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做什么
假设你是Linux教父Linus,对于NUMA架构你会做哪些优化?下面这点是显而易见的:
既然CPU只有在Local-Access时响应时间才能有保障,那么我们就尽量把该CPU所要的数据集中在他local的内存中就OK啦~
没错,事实上Linux识别到NUMA架构后,默认的内存分配方案就是:优先尝试在请求线程当前所处的CPU的Local内存上分配空间。如果local内存不足,优先淘汰local内存中无用的Page(Inactive,Unmapped)。
那么,问题来了。。。
NUMA的“七宗罪”
几乎所有的运维都会多多少少被NUMA坑害过,让我们看看究竟有多少种在NUMA上栽的方式:
- MySQL – The MySQL “swap insanity” problem and the effects of the NUMA architecture
- PostgreSQL – PostgreSQL, NUMA and zone reclaim mode on linux
- Oracle – Non-Uniform Memory Access (NUMA) architecture with Oracle database by examples
- Java – Optimizing Linux Memory Management for Low-latency / High-throughput Databases
究其原因几乎都和:“因为CPU亲和策略导致的内存分配不平均”及“NUMA Zone Claim内存回收”有关,而和数据库种类并没有直接联系。所以下文我们就拿MySQL为例,来看看重内存操作应用在NUMA架构下到底会出现什么问题。
MySQL在NUMA架构上会出现的问题
几乎所有NUMA + MySQL
关键字的搜索结果都会指向:Jeremy Cole大神的两篇文章
- The MySQL “swap insanity” problem and the effects of the NUMA architecture
- A brief update on NUMA and MySQL
大神解释的非常详尽,有兴趣的读者可以直接看原文。博主这里做一个简单的总结:
- CPU规模因摩尔定律指数级发展,而总线发展缓慢,导致多核CPU通过一条总线共享内存成为瓶颈
- 于是NUMA出现了,CPU平均划分为若干个Chip(不多于4个),每个Chip有自己的内存控制器及内存插槽
- CPU访问自己Chip上所插的内存时速度快,而访问其他CPU所关联的内存(下文称Remote Access)的速度相较慢三倍左右
- 于是Linux内核默认使用CPU亲和的内存分配策略,使内存页尽可能的和调用线程处在同一个Core/Chip中
- 由于内存页没有动态调整策略,使得大部分内存页都集中在
CPU 0
上 - 又因为
Reclaim
默认策略优先淘汰/Swap本Chip上的内存,使得大量有用内存被换出 - 当被换出页被访问时问题就以数据库响应时间飙高甚至阻塞的形式出现了
解决方案
Jeremy Cole大神推荐的三个方案如下,如果想详细了解可以阅读 原文
numactl --interleave=all
- 在MySQL进程启动前,使用
sysctl -q -w vm.drop_caches=3
清空文件缓存所占用的空间 - Innodb在启动时,就完成整个
Innodb_buffer_pool_size
的内存分配
这三个方案也被业界普遍认可可行,同时在 Twitter 的5.5patch 和 Percona 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上的做法,显然普遍适用性要强很多。
也就是说,像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核数不再是一个梦想。
- Percona NUMA aware Configuration
- Numa system performance issues – more than just swapping to consider
- MySQL Server and NUMA architectures
- Checking /proc/pid/numa_maps can be dangerous for mysql client connections
- on swapping and kernels
- Optimizing Linux Memory Management for Low-latency / High-throughput Databases
- Memory System Performance in a NUMA Multicore Multiprocessor
- A Case for NUMA-aware Contention Management on Multicore Systems
linux升级openssl和php_openssl模块
一、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的版本看看。
在linux下编译安装nginx+php(fastcgi)
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,所以最好是写一份脚本来启动,然后要养成测试服务可用性的习惯。
用monit监控系统关键进程
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
虽然在注释里有详细说明,但是我还是要再强调说明几点:
- start和stop的program参数里的命令必须是全路径,否则monit不能正常启动,比如killall应该是/usr/bin/killall。
- 对于spawn-fcgi,很多人会用它来管理PHP的fast-cgi进程,但spawn-fcgi本身也是有可能挂掉的,所以还是需要用 monit来监控spawn-fcgi。spawn-fcgi必须带-P参数才会有pid文件,而且fast-cgi走的不是http协议,monit的 protocol参数也没有cgi对应的设置,一定要去掉protocol http这项设置才管用。
- 进程多次重启失败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文件后缀)
linux下安装ZendOptimizer支持
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后的文件,查看源代码就可以看到了.