关于 Laravel 应用性能优化的几点建议


提升 Laravel 网站性能

前言

很多人吐槽 Laravel 框架性能不行,在我看来,除了每次新请求应用启动阶段由于 Laravel 框架本身的设计,导致服务容器加载服务确实增加了一些耗时外(不过这是由于 PHP 作为动态语言不能常驻内存,进而导致每次新请求需要重新初始化服务容器导致的,换做是常驻内存的静态语言,这反而可以是优点),我们是可以通过一些常规的手段将 Laravel 应用的性能优化到一个合理的水平的。况且服务容器并不是什么致命的缺点,相反,它所带来的系统扩展性和可维护性完全可以抵消它所产生的负面作用。

负载测试

以学院君网站为例,前段时间我通过一些常规的手段对其进行了优化。这个应用目前是基于 Laravel 6 构建的,使用 Nginx + PHP-FPM(7.4 版本)作为 Web 服务器,硬件环境是一台配置为 2C4G 的阿里云 ECS,带宽是 4M,在这个乞丐版配置下,我把它的 RPS 优化到了 60 左右,即每秒处理 60 个并发请求,以下是基于 ab 压测工具模拟的并发测试结果(50 个用户发起 500 个请求):

学院君首页负载测试结果

目前来说,这个性能已经足够支撑网站当前的负载需求了。我们对比同等条件下百度首页的并发测试结果,RPS 是 140 左右:

百度首页负载测试结果

如果我把学院君网站扩展成一个拥有3~5台同样配置机器的集群,理论上就可以支撑起 100 多个并发请求,当然这里并不是要把学院君网站拔高到百度这么高的水平,在更高级别的并发请求上,肯定是以卵击石了,毕竟人家是数十万台机器构建的、服务于全国亿万用户的庞大集群。不过针对中小型应用,这样的并发负载支持已经足以应付了。

注:有人反馈说本地压远程结果不准确,由于网络时延和带宽因素,确实存在这样的问题,不过都是在国内,暂且抛开网络连接的时延,对于学院君网站而言,服务器带宽比本地还小,所以其实还好,之前也考虑过这个问题,所以特地远程也测试过,结果和本地也一样,对于百度而言,确实就不准确了,毕竟人家是服务器集群,最合理的压测方式是在其集群内部某台机器进行内网压测,不过这里仅做一个同等压测条件下的参考了,其他同类型的网站也不便拿来参考,存在同行相争的嫌疑,遂作罢。

优化方案

下面我简单分享下学院君网站的优化方案。

首先是对 PHP 项目通用的几个优化手段,包括 PHP 字节码缓存、使用 CDN 加速、数据库查询、缓存和队列系统引入等:

  • 服务器启用 PHP OPcache 扩展缓存 PHP 字节码;
  • 使用 CDN 访问静态资源(图片、JS、CSS 文件)减轻带宽负载;
  • 对于所有高频业务 SQL 查询,合理优化索引字段,提升数据库查询性能;
  • 合理使用缓存,减少与 MySQL 服务器的交互,降低磁盘 IO(Laravel 本身支持多种缓存驱动,可以非常方便地集成不同缓存系统,我这里使用的是 Redis 作为缓存驱动);
  • 上面对数据库查询的缓存是动态缓存,对于数据更新不频繁的页面,还可以使用页面静态化手段直接返回静态 HTML 提升页面加载速度,比如学院君网站就对非登录用户直接返回静态缓存响应;
  • PHP 本身不支持并发编程,但是可以引入队列系统异步处理耗时任务,比如邮件发送、涉及数据库操作的数据统计和更新、事件监听和处理等,通过多个队列进程实现并发处理效果(Laravel 本身支持多种队列驱动,可以非常方便地集成不同队列系统,并且提供了 Horizon 这一队列系统解决方案,我这里使用的是 Horizon + Redis + Supervisor 搭建小型队列系统);
  • 通过 composer install --optimize-autoloader --no-dev 初始化项目依赖,以便加速 Composer 定位指定类对应的加载文件,同时不安装开发环境使用的依赖。

其实是针对 Laravel 项目通用的优化手段(请在线上生产环境执行这些优化命令,不要在开发环境执行,因为开发环境文件变动频繁,缓存没有意义,反而增加了清除缓存的麻烦):

  • 路由缓存:通过 php artisan route:cache 命令可以缓存 Laravel 项目注册的所有路由,避免请求期间动态解析,如果应用包含很多路由,这个优化效果还是很不错的,对请求性能提升效果很显著;
  • 视图缓存:通过 php artisan view:cache 命令可以提前将所有 Blade 视图模板编译,避免在请求期间动态编译视图,从而提升系统性能;
  • 配置缓存:通过 php artisan config:cache 命令可以将项目配置文件缓存起来提升应用性能。

注:以上三个优化手段在 Laravel 部署文档中都有提及,从 Laravel 8 开始,路由缓存开始支持闭包路由,此前是不支持的,需要将所有路由处理重构为基于控制器动作方可,此外,运行 php artisan optimize 可以同时缓存路由、视图和配置,无需分别运行对应缓存命令。

小结

结合前端 Vue.js 框架和 Bootstrap CSS 框架,Laravel 向来在 Web 应用全栈开发方面所向披靡,从 Laravel 8 开始,更是引入对 Tailwind CSS(一个实用优先的工具集 CSS 框架)、Livewire(一个使用 PHP 代码即可编写前端组件的框架,极大降低了后端开发人员进行全栈开发的学习成本)的开箱支持,进一步降低了 PHP 全栈开发的门槛。未来的 PHP 生态,将会是一半 WordPress,一半 Laravel,国外已经有这种态势了,前者无需懂任何代码即可快速搭建网站,后者方便开发者快速进行迭代开发,再加上适当的性能优化使其足以胜任中小型网站应用的负载,那真是“Web 开发,舍我其谁”。

Laravel Web Development

最后,希望大家使用 Laravel 框架快速产出的同时,也不再受性能纷争的干扰,大几百上千的并发还不够支撑,咱还可以使用 Golang/Java 对应用进行服务化改造不是,而在当下,尽情享受 Laravel 框架带来的编程乐趣即可,人生苦短,我用 Laravel。

预告篇:接下来,学院君更新完全栈工程师系列基础篇第三幕 Vue.js 教程后,会全面演示 Laravel 框架如何从无到有基于 TDD 模式进行实战项目开发,包含后续性能优化、持续集成和应用部署等完整的应用开发周期,敬请关注学院君网站的动态,或者你还可以扫码关注学院君微信公众号跟进:

学院君微信公众号


点赞 取消点赞 收藏 取消收藏

<< 上一篇: 学院君网站前端 UI 重构 & 支持暗黑模式(含演示视频)

>> 下一篇: 学院君网站支持视频功能了!