深度优化LNMP

优化前准备工做

Centos准备及配置

准备安装包及软件:
http://pan.baidu.com/s/1chHQF  下载解压到U盘便可安装
http://pan.baidu.com/s/15TUWf  其它版本的centos 在这里 
http://pan.baidu.com/s/1Dv3me  SecureCRT,远程linux管理软件
 
1  安装完centos
2  启动SecureCRT  远程链接linux服务器
若连不上,请检查一下几项:网络防火墙  sshd
3  若sshd未启动,则启动sshd   # /usr/sbin/sshd
若启动时出现以下错误:
         Could not load host key: /etc/ssh/ssh_host_rsa_key
         Could not load host key: /etc/ssh/ssh_host_dsa_key
         其缘由是在 SSH 链接协议中须要有 RSA 或 DSA 密钥的鉴权。所以,咱们能够在服务器端使用 ssh-keygen 程序来生成一对公钥
/私钥对
执行  # ssh-keygen -t rsa -b 1024 -f /etc/ssh/ssh_host_rsa_key   一路回车
命令执行成功后,在 /etc/ssh 下会看到有两个文件生成:ssh_host_rsa_key 和 ssh_host_rsa_key.pub ,前者是私钥,后者是公钥。
 
此时,启用SecureCRT远程链接linux服务器,通常会成功!
 
4 配置yum更新源
 
         配置国内更新源:参考个人这篇文章
         http://www.cnblogs.com/buffer/p/3426908.html
         而后执行命令,更新缓存:
         # yum clean metadata
         # yum clean dbcache
         # yum makecache
 
5 安装lrzsz工具
         用于windows和linux间传输文件
         # yum -y install lrzsz
 
6 配置固定ip
 
         修改或者增长 /etc/sysconfig/network-scripts/ifcfg-eth0
                   DEVICE=eth0
                   IPADDR=192.168.1.104
                   NETMASK=255.255.255.0
                   GATEWAY=192.168.1.1
                   ONBOOT=yes
                   USERCTL=no        //是否容许非root用户控制该设备
                   BOOTPROTO=static
        
         修改DNS配置文件: vi /etc/resolv.conf  增长
         nameserver 192.168.1.1             #主DNS
         nameserver 8.8.8.8                 #次DNS
         search localdomain
        
         关闭NetworkManager,由于在命令行模式下,NetworkManager 和network两个服务冲突。重启:# service network restart
 
7 配置vi
配置vi 做为后面的编程IDE,基本配置步骤请参考个人这篇文章:
http://www.cnblogs.com/buffer/p/3429221.html
 
8 安装必要的编译工具及必需的库文件
         yum -y install make apr* autoconf automake curl-devel gcc gcc-c++ zlib-devel openssl openssl-devel pcre-devel gd kernel keyutils patch perl kernel-headers compat* mpfr cpp glibc libgomp libstdc++-devel ppl cloog-ppl keyutils-libs-devel libcom_err-devel libsepol-devel libselinux-devel krb5-devel zlib-devel libXpm* freetype libjpeg* libpng* php-common php-gd ncurses* libtool* libxml2 libxml2-devel patch cmake
         总共148M左右,具体每一项的做用,你们感兴趣的能够查一查
 
9配置防火墙(服务器安全优化)
         安全规划:开启 80 22 端口并打开回路(回环地址 127.0.0.1)
         # iptables –P INPUT ACCEPT
         # iptables –P OUTPUT ACCEPT
         # iptables –P FORWARD ACCEPT
         以上几步操做是为了在清除全部规则以前,经过全部请求,若是远程操做的话,防止远程连接断开。
接下来清除服务器内置规则和用户自定义规则:
         # iptables –F
         # iptables -X
        
         打开ssh端口,用于远程连接用:
         # iptables –A INPUT –p tcp –-dport 22 –j ACCEPT
         # iptables -A OUTPUT -p tcp --sport 22 -m state --state ESTABLISHED,RELATED -j ACCEPT容许已创建的连接经过22端口向外发送数据包
         而后关闭INPUT 和FORWARD请求:
         # iptables –P INPUT DROP
         # iptables –P FORWARD DROP
        
         接下来设置环路,使得ping 127.0.0.1这样的包额能够经过。后面php会使用这个规则,
         Nginx中设置php-fpm访问地址:http://127.0.0.1:9000即用到这个规则
         # iptables –A INPUT –i lo –j ACCEPT
 
         接下来设置容许其余机器ping 本机,也能够不容许,不容许会更加安全。
         # iptables –A INPUT –p icmp –j ACCEPT
        
         接下来开放web服务端口 80
         # iptables –A INPUT –p tcp –dport 80 –j ACCEPT
         # iptables -A OUTPUT -p tcp --sport 80 -m state --state ESTABLISHED,RELATED -j ACCEPT容许已创建的连接经过80端口向外发送数据包
        
         接下来开放 53端口用于DNS解析
         # iptables -A INPUT -p udp --dport 53 -j ACCEPT
         # iptables -A OUTPUT -p udp --sport 53 -m state --state ESTABLISHED,RELATED -j ACCEPT
 
         最后保存设置:
         # service iptables save
         # service iptables restart
 
         至此已经完成关闭除22 80以外的全部对外端口,服务器能够经过任意端口向外发请求,可是外面的请求只能经过 80和22端口进入到内部。
         也能够直接下载这个脚本执行便可完成基本防火墙设置:
         http://pan.baidu.com/s/17qiUG
         附件:
         linux端口号大全请参考我这篇文章
         http://www.cnblogs.com/buffer/p/3386132.html
         iptables 详解,请参考我这篇文章:
         http://www.cnblogs.com/buffer/archive/2012/09/24/2700609.html
 
10 修改启动模式,默认命令行启动
         # vi /etc/inittab
         将id:5:initdefault:改成id:3:initdefault:保存便可
         从说明里能够看出,5 是启动桌面x-window    3是启动命令行文本模式
 
以上为配置linux基础工做环境
 php

准备nginx 基础工做环境

1 安装nginx
         下载源码包nginx-1.4.2.tar.gz:http://pan.baidu.com/s/1chQ76
 
         建立nginx运行的用户组及用户:www  www
         #groupadd www
         # useradd -g www www -s /bin/false 建立nginx运行帐户www并加入到www组,不容许www用户直接登陆系统
 
         编译安装:
         # ./configure --prefix=/usr/local/webserver/nginx --user=www --group=www --with-http_ssl_module --with-http_gzip_static_module
--with-pcre=/usr/local/webserver/softs/libs/pcre-8.32
--with-openssl=/usr/local/webserver/softs/libs/openssl-1.0.0d
         # make & make install
         查看编译安装参数命令:# ./configure –help
         这里须要两个源码包pcre和openssl:
         pcre-8.32.tar.gz下载:http://pan.baidu.com/s/1pFcIw
         openssl-1.0.0d.tar.gz下载:http://pan.baidu.com/s/1fYYv
        
         设置nginx开机启动:
         具体设置步骤请参考我这篇文章:
                   http://www.cnblogs.com/buffer/archive/2011/08/15/2138762.html
         配置完以后,能够经过命令启动nginx服务:# service nginx start
        
         配置nginx虚拟主机。
至此nginx服务搭建完毕。
 
2 编译安装mysql
         下载源码包mysql-5.5.15.tar.gz:http://pan.baidu.com/s/1chRcF
        
         建立mysql服务运行的用户 mysql 并加入组www
         # useradd –g www mysql –s /bin/false
         建立mysql数据库数据存放目录:
         # mkdir -p /usr/local/webserver/mysql/data
         设置MySQL数据库目录权限
         #chown –R  mysql:www  /usr/local/webserver/mysql/data
        
         下面开始编译安装mysql:
         # cmake . -DCMAKE_INSTALL_PREFIX=/usr/local/webserver/mysql
-DMYSQL_DATADIR=/usr/local/webserver/mysql/data
-DSYSCONFDIR=/etc/
# make && make install
 
配置mysql:
# cp ./support-files/my-huge.cnf /etc/my.cnf
 
编辑配置文件,在 [mysqld] 部分增长下面一行,添加MySQL数据库数据路径
datadir = /usr/local/webserver/mysql/data/mysql
 
接下来,生成mysql系统数据库:
# ./scripts/mysql_install_db --user=mysql
        
         接下来,将mysql加入系统服务开机启动:
         # cp ./support-files/mysql.server /etc/rc.d/init.d/mysqld
增长执行权限:
         # chmod 755 /etc/init.d/mysqld
         加入开机启动:
# chkconfig mysqld on
         编辑启动文件修改mysql路径及mysql数据文件目录:
# vi /etc/rc.d/init.d/mysqld
basedir = /usr/local/webserver/mysql
datadir = /usr/local/webserver/mysql /data/mysql
 
接下来能够启动mysql服务了
Service mysqld start
 
mysql后续配置
设置mysql密码:
#./bin/mysql_secure_installation
根据提示输入密码,删除anonymous用户,禁止以root身份远程登陆,删除test数据库等
接下来,把myslq的库文件连接到系统默认的位置,这样在编译PHP等软件时能够不用指定mysql的库文件地址:
# ln -s /usr/local/webserver/mysql/lib/mysql /usr/lib/mysql
# ln -s /usr/local/webserver/mysql/include/mysql /usr/include/mysql
最后,把mysql服务加入系统环境变量,方便调用mysql客户端登陆mysql
# vi /etc/profile增长下面一行
export PATH=$PATH:/usr/local/webserver/mysql/bin
        
至此,mysql编译安装及配置已经所有完成。最好重启一下系统,使修改生效。

html

编译安装php

         下载源码包php-5.5.5.tar.gz:http://pan.baidu.com/s/1zi33B
        
         安装php以前须要编译安装libmcrypt,到这里下载:http://pan.baidu.com/s/1uyM1L
         编译安装libmcrypt:
         # ./configure
# make && install
 
接下来编译安装php:
# ./configure --prefix=/usr/local/webserver/php --with-mysql=mysqlnd
--with-mysqli=mysqlnd --with-pdo-mysql=mysqlnd --with-zlib --with-libxml-dir
--with-gd  --with-jpeg-dir   --with-png-dir=/usr/lib --with-ttf --with-iconv
--with-openssl  --with-mcrypt --enable-static --enable-maintainer-zts
--enable-zend-multibyte --enable-inline-optimization --enable-sockets
--enable-wddx --enable-zip --enable-calendar --enable-bcmath--enable-soap 
--enable-mbstring --without-sqlite --disable-ipv6--with-mhash
--with-mcrypt --enable-fpm
# make && make install
with-mcrypt:扩展加密算法,若是只用md5的话,则不须要此选项
接下来配置php:
#  cp php.ini-production /usr/local/webserver/php/etc/php.ini从源文件目录下复制php配置文件到安装目录
#  rm -rf /etc/php.ini删除系统自带配置文件
#  ln -s /usr/local/webserver/php/etc/php.ini /etc/php.ini添加软连接
 
#  vi /usr/local/webserver/php/etc/php.ini
禁用不安全函数:
找到:disable_functions =修改成:
disable_functions  =
passthru,exec,system,chroot,scandir,chgrp,chown,shell_exec,proc_open,proc_get_status,
ini_alter,ini_alter,ini_restore,dl,openlog,syslog,readlink,symlink,popepassthru,
stream_socket_server,escapeshellcmd,dll,popen,disk_free_space,checkdnsrr,checkdnsrr,
getservbyname,getservbyport,disk_total_space,posix_ctermid,posix_get_last_error,
posix_getcwd, posix_getegid,posix_geteuid,posix_getgid, posix_getgrgid,posix_getgrnam,
posix_getgroups,posix_getlogin,posix_getpgid,posix_getpgrp,posix_getpid,posix_getppid,
posix_getpwnam,posix_getpwuid, posix_getrlimit, posix_getsid,posix_getuid,
posix_isatty,posix_kill,posix_mkfifo,posix_setegid,posix_seteuid,posix_setgid, posix_setpgid,
posix_setsid,posix_setuid,posix_strerror,posix_times,posix_ttyname,posix_uname
列出PHP能够禁用的函数,若是某些程序须要用到这个函数,能够删除,取消禁用。
找到:;date.timezone =修改成:date.timezone = PRC #设置时区
找到:expose_php = On修改成:expose_php = OFF #禁止显示php版本的信息
 
                   接下来配置php-fpm.conf
# cp php/etc/php-fpm.conf.default php/etc/php-fpm.conf
拷贝模板文件为php-fpm配置文件
# vi php/etc/php-fpm.conf
user = www 设置php-fpm运行帐号为www
group = www 设置php-fpm运行组为www
pid = run/php-fpm.pid 取消前面的分号
                  
                   将php-fpm加入系统服务病设置开机启动:
                   # cp php-5.5.5/sapi/fpm/init.d.php-fpm /etc/rc.d/init.d/php-fpm
拷贝php-fpm到启动目录
# chmod +x /etc/rc.d/init.d/php-fpm 添加执行权限
# chkconfig php-fpm on 设置开机启动
 
启动php-fpm:  #  service php-fpm start
至此,php已经编译安装完成。
 
Lnmp已经所有初步编译安装及配置完毕,下一步,分别对lnmp 进行优化。

mysql

LNMP优化

本文LNMP优化从系统安全,系统资源占用率,及web服务并发负载这三个方面体现,而且主要体如今web服务并发负载这一方面。
本文中使用的服务器配置:centos 6.4  2G内存
本文用到主要从Linux优化、nginx优化、mysql优化、php优化这四个方面依次着手,而且用到的优化效果测试工具备如下几项:
1 服务并发测试工具——apache bench(即ab.exe)
这里下载:http://pan.baidu.com/s/1y2BlC除此以外,注明的web并发测试工具还有http_load 、webbench 、Loadrunner等
2 网络负载监控工具——nload
这里下载:http://pan.baidu.com/s/126vnm
3  linux系统内存、IO、CPU、网络状态监测命令等。更直观的能够安装nmon工具及
 nmon  analyser ,前者是系统各项指标检测工具,后者是将检测结果数据图表化的工具。
   这里下载:
32位 nmon 下载: http://pan.baidu.com/s/1sxkmI
64位 nmon下载: http://pan.baidu.com/s/1rbr6C
nmon analyser 工具下载:http://pan.baidu.com/s/1Caaa8   这是一个windows上的用excel宏作的excel图表工具
这两款工具具体使用方法见个人这篇文章:
http://blog.csdn.net/neubuffer/article/details/16881167
 
为了体现优化效果,本文将优化以前和优化以后的效果保存以做对比。而且每作一步优化都会进行测试比较。
安装完linux,并安装了基本web服务软件nginx、mysql、php以后,
优化以前的系统内存资源占用状况及进程明细,以下图1所示:
内存占用了274M

图1
 
优化以前的系统资源CPU利用率及平均负载状况,以下图2所示:
 

图2
load average: 0.51, 0.30, 0.12指的是 系统负载,即任务队列的平均长度,三个数值分别为 1分钟、5分钟、15分钟前到如今的平均值。
Cpu(s): 0.1% us 用户空间占用CPU百分比
0.2% sy 内核空间占用CPU百分比
0.0% ni 用户进程空间内改变过优先级的进程占用CPU百分比
99.3.0% id 空闲CPU百分比
0.4% wa 等待输入输出的CPU时间百分比
Mem 和 Swap 中的buffers和cached分别指用做内核缓存的内存量及缓冲的交换区总量
优化以前的web并发负载状况,以下图3所示:模拟1000个客户端发送200000个请求,每分钟并发 5280.34,而且出现大量TIME_WAIT


图3

20万并发资源消耗状况以下图4 所示:

系统资源使用状况CPU 和 IO

CPU
 

磁盘

网络
图4
此时看一下nginx错误日志,出现大量failed (24: Too many open files) ,而且 /var/log/message 中也出现   possible SYN flooding on port 80. Sending cookies. 
下面开始一步一步优化,将上面日志中的警告或错误解决掉,而且提升服务器并发负载能力轻松达到1万以上并发,让有限的资源发挥最大性能
好的,让咱们开始吧!linux

首先进行linux优化加固

Linux优化加固最好的办法就是提高硬件配置,好比提升CPU运算能力,增大内存容量,提升硬盘吞吐率等。
本文谈的Linux优化加固是在不提高硬件配置的状况下,经过优化内核配置,从而提升linux服务效率,从三个方面进行:安全加固、内核调优、优化网络,本文主要讲解内核调优及网络优化。nginx

1优化linux 启动项

使用ntsysv工具将不须要的服务关闭
优化启动服务以前的内存使用状况:使用了 275M

图5
   进行优化,默认启动服务能够只保留如下六项必要服务:
iptables sshd crond syslog network messagebus
同时也要保留 nginx、mysql、php默认启动
系统服务解释请参考个人这篇文章:http://www.cnblogs.com/buffer/p/3386346.html
优化以后内存使用状况,使用了224M,节省了近50m内存,不要小看这50M内存,关键时候能够起很大做用

图6
 c++

2 安全加固

Linux安全加固主要针对iptables进行,控制全部INPUT数据包,除了必要的端口打开以外,其他的端口一概关闭。禁用用户ping服务器等会更加安全。详情见LNMP优化准备工做—9配置防火墙(服务器安全优化)。
    删除没必要要的用户:
    # cp /etc/passwd /etc/passwd.sav
# cp /etc/group /etc/group.sav
# for a in adm lp sync news uucp operator games gopher mailnull nscd rpc;
do /usr/sbin/userdel $a -f; done
# for a in lp news uucp games gopher users floopy nscd rpc rpcuser nfsnobody;
do /usr/sbin/groupdel $a ; doneweb

3网络优化

通常状况下,Nginx经过TCP socket来链接客户端与上游应用,默认安装的系统对TCP有许多门限值与限制,经过内核参数来设定。这些参数的默认值每每是为通常的用途而定的,并不能知足web服务器所需的高流量、短生命的要求。
对于网络参数调优能够修改 /etc/sysctl.conf 这个文件。修改完以后使用 #sysctl –p 让内核配置生效。
3.1 内核调优——调整TIMEWAIT,解决出现大量TIMEWAIT问题
在调整TIMEWAIT参数以前,先解释一下tcp连接请求和tcp关闭请求中的报文响应流程。如图7所示为一个完整的数据报格式。
E:\baiduyundownload\传智播客\lnmp优化\配置文件\200711211195609944859.jpg
图7
Tcp的连接及断开过程当中间是通过一系列状态变换的。有这些状态:
创建连接状态:LISTEN,SYN-SENT,SYN-RECEIVED,ESTABLISHED
关闭连接状态:FIN-WAIT-1,FIN-WAIT-2,CLOSE-WAIT,CLOSING,LAST-ACK,TIME-WAIT 和 CLOSED。
各状态参数解释请参考我这篇文章:
http://blog.csdn.net/neubuffer/article/details/16853747
 
    创建连接时,须要通过三次握手协议,创建连接时的握手协议以下图8所示。

redis

收到客户端发来的ack
进入ESTABLISHED
收到服务器发来的ack
进入ESTABLISHED
由LISTEN状态进入SYN-RECEIVED
进入SYN-SENT状态


图8
 
Tcp连接创建过程在服务器端不会产生TIME_WAIT状态,所以本文不做为重要知识点讲解。
 
    断开连接时,须要通过四次握手协议,断开连接时的握手协议以下图9所示。
 
 

算法

发送FIN表示没有数据发送给客户端了,接着进入
FIN-WAIT-1
CLOSED
TIME-WAIT
LAST-ACK WWAITWAIT
FIN-WAIT-2
CLOSE-WAIT WWAITWAIT



       
 
服务器端
   
客户端
 

 
 
 

图9
    Linux系统下,TCP链接主动断开后,会以TIME_WAIT状态保留必定的时间,而后才会释放端口。当并发请求过多的时候,就会产生大量的TIME_WAIT状态的链接,没法及时断开的话,会占用大量的端口资源和服务器资源。这个时候咱们能够优化TCP的内核参数,来及时将TIME_WAIT状态的端口清理掉。
    经过 ab.exe 模拟1000个客户端发起200000个并发请求,而后统计linux tcp等待个数,结果以下图10:

图10
从图7中能够看出,有24986个连接等待。
 
接下来咱们优化一下TIMEWAIT,而后再统计。
# vi /etc/sysctl.conf
在文件中加入下面几行内容:
net.ipv4.tcp_syncookies = 1    开启SYN Cookies,当出现SYN等待队列溢出时,启用cookies来处理,可防范少许SYN攻击,默认为0,表示关闭;
net.ipv4.tcp_tw_reuse = 1    开启重用。容许将TIME-WAIT sockets从新用于新的TCP链接,默认为0,表示关闭;
net.ipv4.tcp_tw_recycle = 1   开启TCP链接中TIME-WAIT sockets的快速回收,默认为0,表示关闭;
net.ipv4.tcp_fin_timeout = 30    修改系統默认的 TIMEOUT 时间,
查看系统默认timeout时间: # cat /proc/sys/net/ipv4/tcp_fin_timeout  默认为60秒。

接下来,优化tcp  keepalive时间,在sysctl.conf中增长如下几行:
net.ipv4.tcp_keepalive_time = 1200 #TCP发送keepalive消息的频度。默认为2小时,改小。tcp连接在空闲 1200秒以后,内核发起关闭连接probe
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 3 #若是probe 3次(每次30秒)不成功,内核才完全放弃
接下来优化其它一些参数:
net.ipv4.ip_local_port_range = 1024 65000
#向外链接的端口范围。默认为32768到61000,范围改大
net.ipv4.tcp_max_syn_backlog = 2148
#SYN队列的长度。默认为1024,改大
net.ipv4.tcp_max_tw_buckets = 5000
#系统同时保持TIME_WAIT套接字的最大数量,超过这个数字,TIME_WAIT套接字将马上被清除并打印警告信息。默认为180000
net.core.netdev_max_backlog = 1000
#进入包的最大设备队列,默认300,改大
net.core.somaxconn = 511  # socket的监听队列backlog的上限,默认值为128,二nginx的默认为511 限制了nginx发挥,NGX_LISTEN_BACKLOG 511
修改完以后,执行# /sbin/sysctl –p  让设置生效
关于网络参数详解及优化,请参考我这篇文章:
http://blog.csdn.net/neubuffer/article/details/16859829
也能够直接下载优化过的文件放到/etc 目录下:http://pan.baidu.com/s/1uyZ7s
 
从新经过 ab.exe 模拟1000个客户端发起200000个并发请求,而后统计linux tcp等待TIMEWAIT个数 netstat -tnp | awk '{print $6}' | sort | uniq -c ,结果以下图11:

图11
从图11中能够看出,连接等待数大量下降,节省了资源。
可是此时并发量,仍是在6000多,没什么提高,这是为何呢?
这时候看一下nginx的错误日志,# tail nginx/logs/error.log 结果如图12所示:
E:\baiduyundownload\传智播客\lnmp优化\搜狗截图20131121021437.png
图12
从错误日志结果中能够看出,打开的文件太多,出现这个错误的缘由主要是因为linux的打开文件描述符的数目太小形成的。
须要修改文件描述符限制。接下来优化内核文件描述符参数。
 
3.2 内核调优——调整文件描述符限制
    查看用户文件描述符限制:
    # ulimit –Hn   查看硬限制
    # ulimit –Sn   查看软限制

 
增大文件描述符限制:
查看系统file-max参数,系统全部进程一共能够打开的文件句柄描述符数量
# cat /proc/sys/fs/file-max  结果为183972   在这里够用了不须要修改。
此值通常默认为系统内存的10%(系统内存以kb计算),通常够用,根据状况能够调大该值。经过编辑/etc/sysctl.conf 添加内容:fs.file-max=102400   来调整。
 
    因而可知本实验中出现的问题因为用户软硬文件句柄数太小致使的,那么咱们增长当前用户软硬文件句柄数:
    # vi /etc/security/limits.conf  添加如下内容,表示限制全部用户打开文件句柄数的软硬限制到102400个。你也能够根据系统须要,限制某个用户。
* hard nofile 102400
* soft nofile 102400
保存,重启linux让刚才的修改生效。
 
File-max 和 ulimit 的区别是前者指的系统全部文件描述符限制,针对整个系统;然后者指的是用户的文件描述符限制,针对的是用户。
 
从新经过 ab.exe 模拟1000个客户端发起200000个并发请求,而后统计linux tcp等待个数 netstat -tnp | awk '{print $6}' | sort | uniq -c ,结果以下图13:


图13
看一下系统各项性能指标,如图14所示:

系统总体CPU 及 IO

CPU

磁盘

网络
图14
    从结果中能够看出,与优化前相比没有太大提高。
   
这时候再看一下nginx的错误日志,# tail nginx/logs/error.log  仍是有打开文件过多错误。可是,这时候看一下 /var/log/message  里面已经没有警告了。
继续找缘由,猜测是否是nginx的限制呢?
 sql

进行nginx优化

前面修改了linux的文件描述符限制及linux内核参数,接下来优化nginx:
修改 # vi nginx/conf/nginx.conf
1 增长nginx工做进程数并绑定到不一样的CPU上,本文所用的硬件有4个CPU,顾开辟4个进程,以下:
worker_processes  4;
worker_cpu_affinity 0001 0010 0100 1000;  #绑定进程和CPU对应
 
    2 增长每一个进程打开文件句柄数,理论值应该是最多打开文件数(ulimit -n)与nginx进程数相除,可是nginx分配请求并非那么均匀,因此最好与ulimit -n的值保持至关。
        worker_rlimit_nofile 50000; 
   
3 采用epoll 模式,并增大每一个进程链接数限制:
    events {
    use epoll;   //异步非阻塞I/O模型
    worker_connections  204800;
}
   
    4 设置客户端请求头部缓冲区大小为系统分页大小的整数倍,能够用命令查看系统分页大小:# getconf PAGESIZE 若是常常出现 400错误,则和值有关,调大便可。
    http{
client_header_buffer_size    4k; 
        large_client_header_buffers  4 4k;
}
 
 
5 打开请求文件缓存
    http{
    open_file_cache max=102400 inactive=60s;
    说明:打开文件指定缓存,默认是没有启用的,max 指定缓存数量,建议和打开文件数一致,inactive 是指通过60s时间文件没被请求后删除缓存。
    open_file_cache_valid 80s;
说明:80s 检查一次缓存的有效信息。
open_file_cache_min_uses 1;
说明:文件使用次数,判断有效与否。inactive 时间内一次没被使用,它将被移除。
}
 
    重启nginx:# service nginx restart
 
    再次经过 ab 模拟1000个客户端发起200000个并发请求,而后统计linux tcp等待个数 netstat -tnp | awk '{print $6}' | sort | uniq -c ,结果以下图15:


图15
看一下系统资源利用状况,以下图16所示:
系统总体CPU及IO

 
CPU

磁盘

网络

图16
由以上结果可见,优化以后并发达到1.1万多。而且TIMEWAIT数量大大减小,性能有明显提高。
实际上此时并发能够达到将近2w,因为ab并发性能成为瓶颈。咱们能够开3个ab,每一个ab分别并发1000发送20万个请求。实验结果以下图17所示:


图17 每一个并发达到0.62万 总共并发大于1.8万
 
    系统资源利用状况以下图18所示:

系统总体CPU及IO
 

CPU

磁盘

网络

内存空闲率
图18
    由结果可知,优化以后,只用了不到200M内存,并发请求达到近2W,系统并发有了很大提高。其中,三个AB程序占了200M内存中的近50%。

进行mysql优化

提高mysql性能须要从三个方面着手,首先是硬件,提高硬件配置效果最明显;其次是mysql参数配置优化;还有数据读写架构优化。本文主要讲mysql参数配置优化,顺便解释一下硬件配置和程序中使用mysql架构优化问题。
对于硬件配置这不用说,任何服务都是基于硬件之上的,提高硬件配置,原则上会提高服务效率,好比使用更大内存,使用磁盘高级raid,数据分区使用固态IO卡,使用xfs文件系统等。
对于mysql架构设计优化,这个很是重要,sql语句优化,表存储引擎(MyISAM,
InnoDB)选择,使用索引,增长redis或者memcached缓存层等。将传统web服务的2层架构(webserver+db)变成三层架构(webserver+cache+db)甚至四层架构(webserver+logicserver+cache+db),由cache来承担分流大并发读写操做。
 
对于存储引擎选择有2个原则:第一个原则,大量读少许写 选用MyISAM,大量写少许读选用InnoDB。针对不一样的需求使用不一样的存储引擎。第二个原则,能不用InnoDB尽可能不用InnoDB。总之,若是你想追求99.9%的稳定性,方便的扩展性和高可用性仍是尽可能用MyISAM吧。
至于为何呢?
1         MyISAM的索引和数据是分开的,而且索引是有压缩的,内存使用率就对应提升了很多。能加载更多索引,而InnoDB是索引和数据是紧密捆绑的,没有使用压缩从而会形成InnoDB比MyISAM体积庞大很多。
2        InnoDB的行级锁是相对的,那个只有where主键时是有效,非主键的都会锁全表的。若是在执行一个SQL语句时MySQL不能肯定要扫描的范围,InnoDB表一样会锁全表,例如update table set num=1 where name like “%aaa%”
3        MyISAM相对简单因此在效率上要优于InnoDB。小型应用使用MyISAM是不错的选择。另外,MyISAM表是保存成文件的形式,在跨平台的数据转移很方便。
总之,尽可能不使用InnoDB,InnoDB主要用于须要外键,事务等企业级支持,代价是速度比MyISAM有倍数的降低。
   
下面主要讲mysql参数配置优化:
准备一个工具:http://pan.baidu.com/s/1M8Ectuning-primer.sh  mysql性能报告工具。
    在开始优化以前先测试一下当前mysql并发状况及系统资源消耗状况。用mysql自带的并发测试工具,测试myisam及innodb引擎,开启100个并发分别写入20000条数据而且查询20000次。统计消耗时间及系统资源使用状况。
    下图19结果展现了分别读写myisam和innodb效率:


图19
下图20是对应的资源消耗状况:

系统总体CPU及IO

CPU

磁盘


内存
图20
经过结果能够看出mysql占用内存过高。写入2万次myisam引擎平均须要2秒钟,innodb平均须要70秒钟,写入时瓶颈出如今IO。读取2万次 两种引擎须要时间至关,4.3秒左右,读取瓶颈出如今CPU。
 
接下来经过运行tuning-primer.sh工具,获取初步配置建议:
# chmod +x tuning-primer.sh
# sh tuning-primer.sh    根据提示继续
结果中红色部分是当前配置不恰当的地方,根据实际状况进行优化。
 
接下来咱们开始一步一步优化 /etc/my.cnf   
本文重点以优化MyISAM 引擎为例。在[mysqld]部分增长如下内容:
1关闭innodb引擎
    default-storage-engine=MYISAM
innodb=OFF
2 开启慢查询日志记录,便于抓出查询速度较慢的语句进行优化查询。
    long_query_time=2 #当某个查询时间超过2s时记录下来
log-slow-queries= /usr/local/webserver/mysql/logs/slowquery.log
 
3 调整max_connections
    容许的同时连接的客户端数量,默认数值是100。若是常常看到 Too many connections 错误,则增大该值。小型服务器通常默认100就够了,本文这里设置为200
 
3 优化myisam 写入效率。
    分别并发100,200,写入10万次,统计系统资源使用状况,如图21所示:
bin/mysqlslap --concurrency=100 --iterations=1 --number-int-cols=4 --number-char-cols=35 --auto-generate-sql --auto-generate-sql-add-autoincrement --auto-generate-sql-load-type=write --engine=myisam --number-of-queries=100000 --debug-info --verbose -uroot -predis123



并发100系统总体CPU及IO            并发100空闲内存
 

并发200系统总体CPU及IO            并发200空闲内存
 
图21
由上图资源使用状况可见,myisam写入的主要瓶颈在系统CPU和IO,因此经过配置参数来作写入优化提高空间有限,这时候就得考虑作数据库集群了。
 
优化myisam 读取效率
    分别并发100,200,读取10万次,统计系统资源使用状况,如图22所示:
bin/mysqlslap --concurrency=100 --iterations=1 --number-int-cols=4 --number-char-cols=35 --auto-generate-sql --auto-generate-sql-add-autoincrement --auto-generate-sql-load-type=read --engine=myisam --number-of-queries=100000 --debug-info --verbose -uroot -predis123


并发100系统总体CPU及IO            并发100空闲内存
 


并发200系统总体CPU及IO            并发200空闲内存
图23
由上图资源使用状况,myisam并发读主要瓶颈在CPU,且内存空闲率也比较多。下面经过优化myisam参数,提高并发读效率。修改 /etc/my.cnf  mysql配置文件。
    4.1 增长  key_buffer_size
       用于索引块的缓冲区大小,增长它可更好处理索引,若是只是使用MyISAM表,能够把它设置为可用内存的 30-40%。具体根据mysql当前负载状况设置,要看Key_reads和 Key_read_requests比例,若是Key_reads 从硬盘读取键的数据块的次数。若是Key_reads较大,则Key_buffer_size值可能过小。能够用Key_reads/Key_read_requests计算缓存损失率。
    
    本文将key_buffer_size设置为 256M
       4.2 增长read_buffer_size大小
       顺序读取数据时的缓冲区大小,该参数分配的内存也是以每链接为单位的。read_buffer_size 是用来当须要顺序读取数据的时候,没法使用索引的状况下的全表扫描,全索引扫描等状况下,会按照数据的存储顺序依次读取数据块,每次读取的数据快首先会暂存在 read_buffer_size 中,当 buffer 空间被写满或者所有数据读取结束后,再将 buffer 中的数据返回给上层调用者,以提升效率。
    本文将read_buffer_size 设置为 2M。
    4.3 增长 query_cache_size 大小
        该参数对应 缓存sql语句及其结果的功能。在下次接收到一样的查询请求时,再也不执行实际查询处理而直接返 回结果,有这样的查询缓存能提升查询的速度,使查询性能获得优化,前提条件是你有大量的相同或类似的查询,而不多改变表里的数据,不然没有必要使用此功 能。注意:若是你查询的表更新比较频繁,并且不多有 相同的查询,最好不要使用查询缓存。设置完以后最好是跟踪一段时间,查看是否运行良好。在必定的负载压力下,若是缓存命中率过低了,就启用它。
    本文将query_cache_size设置为32M
    4.4另外还有其它参数,根据系统状况调整。
thread_cache — 线程的建立和销毁的开销可能很大,由于每一个线程的链接/断开都须要。我一般至少设置为 16。
table_cache — 缓存打开的表。一般要加大缓存数量,使得足以最大限度地缓存打开的表。若是你有200多个表的话,那么设置为 1024 也许比较合适(每一个线程都须要打开表),若是链接数比较大那么就加大它的值。
关于INNODB的参数本文暂不做讲解。
 
保存以上修改,重启mysql,一样分别并发100,200 读取10万次,统计消耗时间,及系统资源使用状况,以下图24所示。


并发100系统总体CPU及IO            并发100空闲内存
 
 
 
 


并发200系统总体CPU及IO            并发200空闲内存
图24
因而可知,优化以后与优化以前对比,myisam总体读取性能有了很大提高。
 
 

进行php优化

 
对于一个web服务来讲,除去mysql瓶颈,最影响性能的瓶颈是php等动态语言。而数据库瓶颈,能够经过第三方解决方案缓解,好比采用分布式数据库,采用内存数据库加速等。解决了数据库瓶颈,接下来就要解决动态语言php瓶颈了。好的解决办法无非这几种:
1 页面静态化,尽可能避免请求动态解析。
2 采用第三方php加速器,经过缓存PHP代码编译后的结果来提升PHP脚本的性能,优化PHP代码执行速度,下降服务器负载,能够提升PHP应用执行速度最高达几倍,甚至十几倍。比较有名的加速器有,Zend Opcache,xcache,eAccelerator。
在php 5.5 及以上的版本中已经内置了Zend Opcache,而本文用的php 5.5.5,所以不须要作这步优化了。
    3 经过配置php参数,充分利用系统硬件资源,从而提升服务效率。本文主要讲解这一部分。
    在优化以前仍是作个测试,并统计系统资源使用状况。
    首先编写一个php页面,使用ab工具,启动1000个并发,发起1万个请求。
测试结果以下图25所示。


系统总体CPU及IO状况内存
图25
每秒系统处理请求 166.34个并发,很是低。而且经过资源消耗状况看,在请求开始的前10s CPU使用率很是高,接下来接着CPU使用率突降,IO一直波动。另外,内存使用一直较低。
接下来查看一下系统日志及nginx错误日志:
# tail /var/log/message

系统提示相似洪水攻击。

Nginx错误日志中则出现大量连接php错误

另外,TIME_WAIT数也相对太高
    由此推断,php链接数配置太低?
    下面开始优化php配置,vi php/etc/php-fpm.conf
    1 增大php-fpm对打开文件描述符的限制
        rlimit_files = 65536
    2设置容许访问Fastcgi进程解析器的IP地址,更加安全
        listen.allowed_clients = 127.0.0.1
    3 增大请求缓冲队列大小
        listen.backlog = 2048      默认为128,有点小,增大这个参数,能够解决系统日志中攻击提示问题以及nginx错误日志中的连接错误。
    4  pm.max_requests = 1024由 500改成1024
    此时再作测试,结果以下图26所示:
      


    并发提高了,达到882.28个每秒,比优化前的166.34 提高了5倍之多,而且TIME_WAIT数量也大大减小,降到合理范围内。

系统总体CPU及IO使用状况

内存使用状况
图26
 
    继续优化,达到并发5000以上,才告一段落:
在nginx配置中使用fast_cgi缓存,在http段加入如下内容:
fastcgi_temp_path /dev/shm/fastcgi_temp;
    #cache设置
    fastcgi_cache_path /dev/shm/fastcgi_cache levels=1:2
keys_zone=cfcache:10m inactive=50m max_size=256;
//为FastCGI缓存指定一个路径,目录结构等级,关键字区域存储时间和非活动删除时间。以及最大占用空间。
    fastcgi_cache_key "$request_method://$host$request_uri";
    fastcgi_cache_methods GET HEAD;
    fastcgi_cache   cfcache;  //开启FastCGI缓存而且为其制定一个名称。
fastcgi_cache_valid 200 302 301 1h;
    fastcgi_cache_valid   any 5m;   //为指定应答代码指定缓存时间,这里指定200 302 301应答缓存1小时,其他任何应答缓存5分钟
    fastcgi_cache_min_uses  1;  //缓存在fastcgi_cache_path内文件在inactive参数值时间内的最少使用次数,如上例,这里在50分钟内某文件1次也没有被使用,那么这个文件将被移除。
    fastcgi_cache_use_stale error  timeout invalid_header http_500;//对于error timeout invalid_header http_500等类型的应答内容不缓存
    fastcgi_ignore_client_abort on;//忽略客户端终止请求
 
 
    重启nginx ,并发1000发送10万个请求,统计执行效率及系统资源消耗状况。以下图27所示。
    

图27
由测试结果可知,优化以后并发达到 6004.95个。系统CPU及IO利用率也比较合理,内存占用较小,总体比较理想。

优化总结

本文采用的测试机是普通的2G内存笔记本,再作优化没有多大意义,实际生产环境中在运行着大并发请求的真实服务器上进行优化比较准确。本文Lnmp优化到此告一段落吧。
经过合理架构,合理代码逻辑,通过优化以后服务轻松能够达到并发1-2w。

 

http://php.itcast.cn/news/20140211/10284488889.shtml

相关文章
相关标签/搜索