一直以来都是在写hadoop,很少写nginx和php相关的东西了。网上绝大多数文章是优化linux系统参数,优化nginx,php的配置参数等等,尝试写个不同视角的,跟具体技术点关系太大的,主要是思路。
从编译安装nginx和php开始捋一下。
编译nginx和php一个最基本的原则是,尽可能编译更少的附加模块,nginx和php或者更早的apache,为了完成某项特定的功能,会将该功能已动态连接库的形式包含在软件里面,在linux下面是.so后缀的文件。一般来说,用户在configure阶段,可以自己选择--with-xxx或者--without-xxx来决定是否使用它提供的模块。为了方便,我们当然可以这样做,比如我们要在php里面使用curl的函数,就指定--with-curl=/usr/local/curl这种方式去configure。但是,除非这个模块是你必须使用的,否则就不要指定编译它。
原则一:如果不需要这个模块,就不要编译它。
原因是这样,当你启动nginx或者php进程的时候,这些进程都会打开所有你所编译的这些动态连接库,每个动态链接库都会占用linux系统的FD资源,这个用lsof是可以很清楚的看到的。同样,你的log文件也是会占用FD资源。
- [root@collect-crash5-197 Hload]# lsof | grep nginx
- nginx 14214 nobody cwd DIR 8,9 4096 31623598 /opt/modules/tengine/sbin
- nginx 14214 nobody rtd DIR 8,2 4096 2 /
- nginx 14214 nobody txt REG 8,9 3114093 31623599 /opt/modules/tengine/sbin/nginx
- nginx 14214 nobody mem REG 8,2 143600 65301 /lib64/ld-2.5.so
- nginx 14214 nobody mem REG 8,2 1722304 65305 /lib64/libc-2.5.so
- nginx 14214 nobody mem REG 8,2 129984 65356 /lib64/libpcre.so.0.0.1
- nginx 14214 nobody mem REG 8,2 145824 65350 /lib64/libpthread-2.5.so
- nginx 14214 nobody mem REG 8,2 18152 65349 /lib64/libutil-2.5.so
- nginx 14214 nobody mem REG 8,2 615136 65315 /lib64/libm-2.5.so
- nginx 14214 nobody mem REG 8,2 85544 65591 /lib64/libz.so.1.2.3
- nginx 14214 nobody mem REG 8,2 48600 65346 /lib64/libcrypt-2.5.so
- nginx 14214 nobody mem REG 8,2 92736 65327 /lib64/libresolv-2.5.so
- nginx 14214 nobody mem REG 8,3 1262416 4146256 /usr/lib64/perl5/5.8.8/x86_64-linux-thread-multi/CORE/libperl.so
- nginx 14214 nobody mem REG 8,2 114352 65623 /lib64/libnsl-2.5.so
- nginx 14214 nobody mem REG 8,2 23360 65329 /lib64/libdl-2.5.so
- nginx 14214 nobody mem REG 8,3 120945 4245561 /usr/lib64/perl5/site_perl/5.8.8/x86_64-linux-thread-multi/auto/nginx/nginx.so
- nginx 14214 nobody DEL REG 0,9 1301143625 /dev/zero
- nginx 14214 nobody mem REG 8,2 53880 65306 /lib64/libnss_files-2.5.so
- nginx 14214 nobody 0u CHR 1,3 1670 /dev/null
- nginx 14214 nobody 1u CHR 1,3 1670 /dev/null
- nginx 14214 nobody 2w REG 8,9 19614456983 31719533 /opt/modules/tengine/logs/error.log
- nginx 14214 nobody 3w REG 8,17 0 73587637 /data/logs/error5/access.log
- nginx 14214 nobody 5u unix 0xffff81010f64ec40 1596291379 socket
- nginx 14214 nobody 7u unix 0xffff810186199480 1596291382 socket
- nginx 14214 nobody 9u unix 0xffff81010886eec0 1596291384 socket
- nginx 14214 nobody 10u IPv4 1301143624 TCP *:http (LISTEN)
- nginx 14214 nobody 11w REG 8,17 0 90475700 /data/logs/errorv/access.log
- nginx 14214 nobody 12w REG 8,17 0 1507590 /data/logs/errorcode/access.log
- nginx 14214 nobody 13w REG 8,17 0 73662516 /data/logs/mobile/access.log
- nginx 14214 nobody 14w REG 8,9 8612894912 31719506 /opt/modules/tengine/logs/access.log
- nginx 14214 nobody 15w REG 8,9 19614456983 31719533 /opt/modules/tengine/logs/error.log
- nginx 14214 nobody 16u unix 0xffff81010886fc80 1596291389 socket
- nginx 14214 nobody 17u unix 0xffff8101185cda00 1596291378 socket
- nginx 14214 nobody 18r 0000 0,11 0 1596291381 eventpoll
- nginx 14214 nobody 19u 0000 0,7 0 356 anon_inode
- nginx 14214 nobody 20u unix 0xffff81010886f440 1596291391 socket
- nginx 14214 nobody 21u unix 0xffff81011b1d3a00 1596291393 socket
- nginx 14214 nobody 23u unix 0xffff81013d2c5d00 1596291396 socket
- nginx 14214 nobody 25u unix 0xffff81013d2c5780 1596291398 socket
- nginx 14214 nobody 27u unix 0xffff81013d2c5200 1596291402 socket
- nginx 14214 nobody 29u unix 0xffff81013d2c4c80 1596291404 socket
- nginx 14214 nobody 31u unix 0xffff81013d2c4700 1596291406 socket
- nginx 14214 nobody 33u unix 0xffff81013d2c4180 1596291408 socket
- nginx 14214 nobody 35u unix 0xffff8102020a3940 1596291410 socket
- nginx 14214 nobody 37u unix 0xffff8102020a33c0 1596291412 socket
- nginx 14214 nobody 39u unix 0xffff8102020a2e40 1596291415 socket
- nginx 14215 nobody cwd DIR 8,9 4096 31623598 /opt/modules/tengine/sbin
- nginx 14215 nobody rtd DIR 8,2 4096 2 /
- nginx 14215 nobody txt REG 8,9 3114093 31623599 /opt/modules/tengine/sbin/nginx
- nginx 14215 nobody mem REG 8,2 143600 65301 /lib64/ld-2.5.so
- nginx 14215 nobody mem REG 8,2 1722304 65305 /lib64/libc-2.5.so
- nginx 14215 nobody mem REG 8,2 129984 65356 /lib64/libpcre.so.0.0.1
- nginx 14215 nobody mem REG 8,2 145824 65350 /lib64/libpthread-2.5.so
- nginx 14215 nobody mem REG 8,2 18152 65349 /lib64/libutil-2.5.so
- nginx 14215 nobody mem REG 8,2 615136 65315 /lib64/libm-2.5.so
- nginx 14215 nobody mem REG 8,2 85544 65591 /lib64/libz.so.1.2.3
- nginx 14215 nobody mem REG 8,2 48600 65346 /lib64/libcrypt-2.5.so
- nginx 14215 nobody mem REG 8,2 92736 65327 /lib64/libresolv-2.5.so
- nginx 14215 nobody mem REG 8,3 1262416 4146256 /usr/lib64/perl5/5.8.8/x86_64-linux-thread-multi/CORE/libperl.so
- nginx 14215 nobody mem REG 8,2 114352 65623 /lib64/libnsl-2.5.so
- nginx 14215 nobody mem REG 8,2 23360 65329 /lib64/libdl-2.5.so
- nginx 14215 nobody mem REG 8,3 120945 4245561 /usr/lib64/perl5/site_perl/5.8.8/x86_64-linux-thread-multi/auto/nginx/nginx.so
- nginx 14215 nobody DEL REG 0,9 1301143625 /dev/zero
- nginx 14215 nobody mem REG 8,2 53880 65306 /lib64/libnss_files-2.5.so
- nginx 14215 nobody 0u CHR 1,3 1670 /dev/null
- nginx 14215 nobody 1u CHR 1,3 1670 /dev/null
- nginx 14215 nobody 2w REG 8,9 19614456983 31719533 /opt/modules/tengine/logs/error.log
- nginx 14215 nobody 3w REG 8,17 0 73587637 /data/logs/error5/access.log
- nginx 14215 nobody 5u unix 0xffff810186199480 1596291382 socket
- nginx 14215 nobody 7u unix 0xffff81010886eec0 1596291384 socket
- nginx 14215 nobody 9u unix 0xffff81010886fc80 1596291389 socket
- nginx 14215 nobody 10u IPv4 1301143624 TCP *:http (LISTEN)
- nginx 14215 nobody 11w REG 8,17 0 90475700 /data/logs/errorv/access.log
- nginx 14215 nobody 12w REG 8,17 0 1507590 /data/logs/errorcode/access.log
- nginx 14215 nobody 13w REG 8,17 0 73662516 /data/logs/mobile/access.log
- nginx 14215 nobody 14w REG 8,9 8612894912 31719506 /opt/modules/tengine/logs/access.log
- nginx 14215 nobody 15w REG 8,9 19614456983 31719533 /opt/modules/tengine/logs/error.log
- nginx 14215 nobody 16u unix 0xffff8101185cdcc0 1596291377 socket
- nginx 14215 nobody 17u unix 0xffff81010886f440 1596291391 socket
- nginx 14215 nobody 18u unix 0xffff81011b1d3a00 1596291393 socket
- nginx 14215 nobody 19u unix 0xffff81010886ec00 1596291380 socket
- nginx 14215 nobody 20r 0000 0,11 0 1596291386 eventpoll
- nginx 14215 nobody 21u 0000 0,7 0 356 anon_inode
- nginx 14215 nobody 23u unix 0xffff81013d2c5d00 1596291396 socket
- nginx 14215 nobody 25u unix 0xffff81013d2c5780 1596291398 socket
- nginx 14215 nobody 27u unix 0xffff81013d2c5200 1596291402 socket
- nginx 14215 nobody 29u unix 0xffff81013d2c4c80 1596291404 socket
- nginx 14215 nobody 31u unix 0xffff81013d2c4700 1596291406 socket
- nginx 14215 nobody 33u unix 0xffff81013d2c4180 1596291408 socket
- nginx 14215 nobody 35u unix 0xffff8102020a3940 1596291410 socket
- nginx 14215 nobody 37u unix 0xffff8102020a33c0 1596291412 socket
- nginx 14215 nobody 39u unix 0xffff8102020a2e40 1596291415 socket
第二列是进程PID,我这里列了nginx的两个进程,你加载的动态链接库越多,他占用的FD和内存就会越多,而TCP/IP本身每个连接我记得是会占用1.5k左右的内存。所以,尽可能少的加载动态连接库,可以将更多的内存和cpu资源让给tcp/ip连接。
所以,除了必须要用的,尽可能少的指定configure参数是可以提高一些性能的。例如nginx的gzip参数,如果你不是遇到特别大的带宽瓶颈无法逾越,就尽量不要指定使用gzip,他可以减小带宽占用,但同时在高并发情况下会增大CPU的占用,gzip算法挺费CPU时间的。同理,不需要rewrite,就不要加pcre参数,不需要mhash,就不要给php指定mhash参数,以此类推。
原则二:尽可能使用缓存系统
无论是nginx的缓存,还是php的缓存,或者memcached或者redis,除非你遇到客户端刷新问题,否则不要拒绝缓存机制,这在性能优化里是非常有用的,这有点类似于代码重用。代码重用会减少程序员的工作量,而缓存会减少服务器的工作量,关于这方面任何人都没有异议吧。在我的实际工作中,由于不涉及前端工作,所以不怎么去关心memcached和redis。但是我也会尽可能的使用缓存,特别是php的缓存,我主要使用的就是eaccelerator。做一个对比,在不使用eaccelerator的情况下,php开256进程,并发量达到1000多的时候,CPU就已经跑满了,nginx会报出大量的errorlog。而使用了eaccelerator,php并发量达到2000或者更高,cpu也只跑到了一半多一些,nginx还没有报出errorlog。而且有很多优秀的缓存,除了eaccelerator之外,还有xcache等。
原则三:尽可能使用面向过程,而不是面向对象。
其实我这么说可能有点老土了,但是面向过程的确要比面向对象的方式要执行效率高。当然我不否认面向对象在代码重用和构建大型系统上的优势。面向对象的方式要比面向过程在php解释器里面多了好几步流程,而用虚拟机就更慢了。尽管这种区别可能只有几十个cpu微秒时间,但是累计误差是很可怕的一件事。
原则四:好的算法和坏的算法。
对于不是要求特严格的网站来说,其实算法无分好坏,只要能解决问题就行,但是就像原则三里面说到的累积误差。一个不好的算法带来的往往是整体效率的低能。单独跑一个几百几千个数的冒泡和快排的效率差别,可能相差也不过是几个毫秒,十几个毫秒。但是几万个呢,几十万个呢?早期去选择好的算法和书写风格,会让后面的工作轻松很多,代码重构的工作真的又耗精力又耗时间。
原则五:学会用监控。
监控的目的不仅仅是看服务器是不是还活着,这个活着包括服务器活着,也包括上面的服务还活着,这个根本就不是监控的最终目的。服务器和服务是不是还活着,不需要你去监控。群众的眼睛是雪亮的,服务用不了的话,电话早就被打爆了。监控的最终目的是分析出性能的瓶颈所在,然后想办法去调优。无论是图形化的cacti,ganglia,zabbix还是linux下面命令行的iftop,iostat,vmstat,lsof等等,将每台服务器的硬件资源利用率最大化,才是真正的目标所在。咱们毕竟不是国企央企政府机关,可以征收上来的苛捐杂税买一堆oracle,emc在那摆着观赏把玩,剩下的回扣甩给二奶三奶。
当然,这个监控也不仅仅是监控访问量和负载的关系,很多都可以监控,也可以通过前后端的技术来实现,比如在nginx配置里面加上一个参数,可以监控到页面的请求响应时间,或者通过cookie和javascript,可以监控到客户端的实际加载时间等等。不过这些就需要自己写代码实现了。
没事瞎写的,很久不搞web相关的东西了,写起来感觉挺怪的。恩,我开始挂臭袜子了。