LAMP网站建设 之性能优化篇(上)

开源的LAMP (linux/Apache/Mysql/PHP) 平台是流行的web application platform,不少网站,包括海归网都是建立在此平台上.

在帮助海归网正式转移到LAMP平台之前, 笔者虽然长期做网站设计和开发方面的工作,但主要是在J2EE 或者 ASP.NET /ASP方面的应用, 具体是在application 层面, 架构设计主要考虑功能/可扩充性和scalability, 而网站反应速度/性能方面一般不是问题–或者流量不大,或者硬件架构足够强(hardware load balancer, cluster, dedicated web/middle tier/DB tier/team等). 在海归网, 让我有机会在LAMP环境下接触和学习到许多以前做应用或自己玩操作系统时难以接触到的问题– 除了系统和网络管理外, 有许多是关于性能优化和scalability方面的.

在这篇里分享一点积攒的LAMP环境下PHP网站的性能优化经验. (谢谢老狼和海归网提供的给我一个发挥点业余爱好的机会); 以后有时间谈谈scalability/availability等.

有许多中小网站都和海归网一样只有一台服务器(海归网有一台dedictaed的dell, 更多更差的网站shared hosting的则是几十几百个网站公用一台server), 而这台服务器需要身兼web server, application server,database server, firewall等等所有一切功能…在网站建设的初期只能在有限的硬件条件下最大限度地进行优化充分利用所有的资源保证基本的功能/性能和稳定性.

1. 编译php/apache/mysql 时的优化选项

一般来说, 用不着自己编译这些东西,直接下载binary packages就可以了–无论是debian 的apt-get 还是redhat的rpm /yum. 但是这些现成的安装包编译时一般并未根据你的服务器硬件配置做优化, 而通过选择合适的C编译器 flags 和其他选项,自己编译往往能使总体性能提高几个到几十个百分点.

推荐在编译之前, 设置 CFLAGS 环境变量:

export CFLAGS="-march=pentium4 -O2 -pipe -msse2 -mfpmath=sse,387 -mmmx -fomit-frame-pointer"

-march , -msse2, -mfpmath, -mmmx 等都是根据自己的服务器CPU类型做的设置; 海归网服务器是个xeon CPU所以用上述标记; 老一些的GCC 编译器还可以加上 -prefer-nopix

一般linux用户都知道, 下载源代码后标准的编译安装过程是:

./configure [options]
make
make install

在运行./configure 时注意尽量避免编译自己不需要的模块或功能以免编译出来的东西过于臃肿.

./configure 时最好不要enable pix, 而是用 –disable-pix选项;


2. 软件版本

linux 核心版本最好在2.6以上, 因为在虚存/线程管理等关键功能上比2.4有了很大的改善,对系统性能影响较大.

有些版本的php/apache/mysql有比较严重的bug,导致系统严重不稳定. 比如 mysql 5.1.11会导致数据库表/索引频繁崩溃;最新的php5.2.5和php5.2.6 development snapshot 似乎有memory leak, 导致系统内存很快被用光服务器奇慢无比甚至死机等等.We learned it the hard way :(

3. 使用google的tcmalloc 内存分配函数代替libc里的标准malloc.

google的开源性能优化工具包 perftool 被证明对提高应用程序性能确有帮助. tcmalloc是其中一个, 与标准的malloc相比, 在内存的分配上效率很高; 编译mysql时建议使用tcmalloc库–
简单来说, 只要在./configure 后生成的Makefile里改一下, 在连接库的那行最后面加上 -ltcmalloc即可.

如果已经使用的是已编译的binary,或者只想简单测试一下tcmalloc的效果, 可以用LD_PRELOAD环境变量制定运行时使用tcmalloc库; 例如在mysqld_safe里加入

export LD_PRELOAD=/usr/local/lib/libtcmalloc.so

确定程序是否使用tcmalloc库可以用lsof命令:

lsof -n| grep tcmalloc

我的经验是使用tcmalloc后mysql的性能确实得到了提高,但在php和apache上没什么效果.

4. PHP config

一个是打开 zlib_compression开关,这样网页内容被传输到浏览器之前会先被压缩,从而减少网站流量并且加快page load速度.

当然也可以不在php里压缩.而是在apache里用mod_deflate.

5. Apache config

MPM: apache标准MPM是prefork, 起一大堆进程每个进程处理一个请求. 如果可行, 尽量使用apache worker MPM, 多线程模式可以减少apache内存使用提高性能. 最新的event mpm在worker mpm的基础上进一步提高了性能,但是目前(截至apache 2.2.8)尚处于实验阶段不推荐在production使用.

使用worker mpm要求编译apache时使用worker mpm选项, 并且php需要编译成thread-safe的,链接到mysql的thread-safe client library.

httpd.conf里一些影响性能的设置(不一一解释了, apache在线文档里都有):
— mpm的设置
— keep alive: 大部分设成 on 比较好; 个别网站设成off更好;这个需要自己测试
— keep alive time out: 1-2 秒.
— maxkeepaliveRequest: 设成比较大的数目, 比如 1000或2000.
— extended server status: disable
— allow override: 设成不允许 (也就是说尽量避免每个目录下的.htaccess文件)
— HostnameLookups Off
–LogLevel: 在production box上设成 error或crit

尽量少用mod_rewrite

除了用apache worker MPM + mod_php, 另一种常见的apache配置是用apache+ mod_fastCGI + php-fcgi; 使用fast CGI 的apache进程可以重用,另外还有安全上的一些特点.

顺便提一句, 虽然apache在web server里最有名, 但性能方面并不怎么样, 相比一些其他open source产品来说体积庞大臃肿占内存速度又慢. lighttpd是一个日渐流行的http server, 速度较apache快效率更高. 许多其他的基于scripting language的web app 例如ruby/python/perl都以lighttpd+fast cgi的模式运行.


6. mysql tunning

–mysql storage engine的选择: 最流行的是MyISAM 和INNODB. 前者是mysql初期的主要engine, 至今仍大量使用,优点是查询速度很快,并且具有全文检索等别的engine没有的功能. 但是不支持事务处理(transaction), 写操作效率也不高. innodb支持transaction和其他一些现代关系数据库的功能. 这个完全根据你的网站应用的需要了…如果涉及到ecommerce之类最好使用innodb.

–mysql 的一些系统参数的优化:

query_cache_size: 这个很重要; 太小了每个sql都得到硬盘数据库里找一次, 太大了占用内存过多影响系统其他部分. 另外query cache里相关的记录若被修改则所有cache的查询结果都会被清除.

此外, myisam 的 key_buffer, table_open_cache, sort_buffer_size, thread_cache_size, thread_concurrency, tmp_table_size,max_heap_table_size,join_buffer_size, max_connections等都影响performance. 此外.对于IINNODB, 还有一个很重要的参数是innodb_buffer_pool_size.

有一个简单的perl script可以帮助你调节上述参数: ( http://rackerhacker.com/mysqltuner/ ) .

对许多web 应用来说, 数据库往往是性能的瓶颈; 而数据库性能最常见的问题是索引问题–sql 查询/join字段不通过索引导致full table scan…可以在mysql的启动参数上加上 log-slow-queries 选项记录所有执行速度太慢的sql 语句. 甚至打开log-queries-not-using-indexes 记录所有没有使用索引的sql…然后根据情况解决: 或者给相关字段加上索引, 或者优化/改写应用程序里的sql语句.

一时写不完, 等下半篇再说说reverse proxy/ opcode cache/ data caching 等.