博客上线一周,访问量慢慢上来了。但我发现页面加载越来越慢,尤其是文章列表页,有时候要等两秒才能打开。用Chrome开发者工具看了一下,TTFB(首字节时间)居然有1.8秒,这显然不正常。
两秒的响应时间,对于一个只有几十篇文章的个人博客来说,简直是灾难。我决定好好优化一下,目标是把TTFB降到两百毫秒以内。
第一步:排查慢查询
性能问题,十有八九出在数据库。我先在MySQL里开启了慢查询日志,把阈值设为0.1秒,跑了一天,果然抓到了几条慢SQL。
最慢的一条是文章列表页的查询:
SELECT p.*, c.name as category_name
FROM blog_posts p
LEFT JOIN blog_categories c ON p.category_id = c.id
WHERE p.status = 1
ORDER BY p.created_at DESC
LIMIT 0, 10;这条SQL看起来没问题,但EXPLAIN一下发现,blog_posts表的status字段没有索引,导致全表扫描。虽然现在只有几十篇文章感觉不到,但数据量大了就会很慢。
解决方法很简单,给status和created_at加联合索引:
ALTER TABLE blog_posts ADD INDEX idx_status_created (status, created_at);加完索引再EXPLAIN,type从ALL变成了range,rows从全表变成了10,查询时间从0.3秒降到了0.001秒。
还有一个问题是文章详情页,每次都查一次数据库。我加了个简单的文件缓存,把文章内容序列化存到文件里,有效期一小时,命中率能到百分之九十以上。
第二步:开启OPcache
PHP是解释型语言,每次请求都要重新解析编译脚本,这部分开销其实不小。PHP 5.5以后内置了Zend OPcache,可以把编译后的字节码缓存到内存里,下次请求直接用,省去解析编译的时间。
我的服务器上PHP 5.6默认没开OPcache,在php.ini里加了几行配置:
zend_extension=opcache.so
opcache.enable=1
opcache.memory_consumption=128
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=10000
opcache.revalidate_freq=60
opcache.fast_shutdown=1重启PHP-FPM后,用phpinfo()看了一下,OPcache已经生效。缓存命中率百分之九十八以上,页面响应时间又降了一截。
有个要注意的点:opcache.revalidate_freq设为60,意味着代码修改后最多六十秒才会生效。开发环境可以设为0,生产环境设大一点没问题。
第三步:Nginx优化
PHP层面优化完了,再看看Web服务器。Nginx的优化主要有三个方向:静态文件缓存、Gzip压缩、连接复用。
静态文件缓存:给图片、CSS、JS设置Expires头,让浏览器缓存七天,减少重复请求。
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
expires 7d;
add_header Cache-Control "public, no-transform";
}Gzip压缩:开启gzip,压缩文本类文件,能把HTML从20KB压到5KB,传输更快。
gzip on;
gzip_min_length 1k;
gzip_comp_level 5;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml;连接复用:开启keepalive,减少TCP握手开销。
优化结果
一通操作下来,文章列表页的TTFB从1.8秒降到了150毫秒,整页加载时间从2.5秒降到了400毫秒。对于一个1核1G的小服务器来说,这个成绩我很满意了。
性能优化是个持续的过程,没有最好只有更好。但核心思路就那几条:先找瓶颈(慢查询日志、Xdebug profiling),再针对性优化,最后加缓存。不要上来就盲目优化,要先测量再动手。
评论(0)
暂无评论,快来抢沙发~
评论功能仅对会员开放,请先登录
登录