1. 简介

上一章节,我们完成了 Laravel 项目的 Web 站点部署,由于 Laravel 中包含异步队列与定时任务,因此如果在项目中使用到了还需要做对应的部署操作。

2. 使用 Horizon 管理队列

Horizon 是 Laravel 官方推出的一个集成在 Laravel 项目中的 Redis 队列管理工具,包含了一个可视化面板和几个管理命令,可以让我们更加方便地管理异步任务。

我们可以通过 composer 直接安装:

composer require laravel/horizon

安装完成之后还需要把 Horizon 的配置文件和前端文件放到项目目录中:

php artisan vendor:publish --provider="Laravel\Horizon\HorizonServiceProvider"

现在我们访问 demo.ilaoniu.cn/horizon 看看 Horizon 的管理面板。

默认情况下这个页面只能在 APP_ENV=local 的环境可以看到,所以不用担心线上站点信息泄露。

我们需要在终端调用 Horizon 的命令来启动:

php artisan horizon

3. 服务器配置队列

接下来我们还需要在服务器上配置 Supervisor 来启动 Horizon。

Supervisor 是一款进程管理工具,通过配置可以实现自动监听进程状态,如果被监听的进程发生异常退出,Supervisor 会尝试再次启动该进程。

安装 Supervisor:

apt-get install supervisor
systemctl status supervisor
cp /usr/bin/supervisord /usr/local/bin/
cp /usr/bin/supervisorctl /usr/local/bin/

现在来创建一个 Supervisor 配置:

vim /etc/supervisor/conf.d/demo.ilaoniu.cn.conf

然后输入以下内容:

[program:demo-horizon]
process_name=%(program_name)s_%(process_num)02d
command=php /home/wwwroot/demo.ilaoniu.cn/current/artisan horizon
autostart=true
autorestart=true
user=deployer
numprocs=4
redirect_stderr=true
stdout_logfile=/home/wwwroot/demo.ilaoniu.cn/current/storage/logs/horizon.log

接下来我们需要让 Supervisor 重新加载配置:

supervisorctl update

现在通过以下命令检查是否正常运行:

supervisorctl status

状态是 RUNNING 说明运行正常。

4. 调整 Deployer 脚本

Horizon 是一个常驻进程,在启动时就加载好了代码,不会因为 current 被链接到新的代码目录而重新加载代码,因此我们需要在部署脚本中停止 Horizon 进程然后再重新启动,使其加载最新版本的代码。

Horizon 的开发者也考虑到这种情况,所以提供了 horizon:terminate 这个命令,它可以「优雅地」停止 Horizon 进程,这与我们之前介绍的 Nginx reload 机制类似,Horizon 进程会等待当前正在执行的任务执行完毕,然后再退出进程。

由于我们在 Supervisor 配置了 autorestart=true,当 Supervisor 发现 Horizon 进程退出,就会立刻再次启动 Horizon 进程,而这个时候的 current 已经指向了最新的代码目录,因此此时启动的 Horizon 进程使用的是最新代码。

现在在部署脚本 deploy.php 中添加一个执行 horizon:terminate 的任务:

.
.
.
desc('Restart Horizon');
task('horizon:terminate', function() {
    run('{{bin/php}} {{release_path}}/artisan horizon:terminate');
});

// 在 deploy:symlink 任务之后执行 horizon:terminate 任务
after('deploy:symlink', 'horizon:terminate');
.
.
.
  • {{bin/php}} 是 Deployer 内置的变量,是 PHP 程序的绝对路径;
  • deploy:symlink 任务是将 current 链接到最新的代码目录。

5. 配置定时任务

接下来我们还需要配置一下定时任务,需要用到 Linux 系统的 cron 功能,一般的 Linux 发行版都会内置这个软件。

登录到云服务器,然后使用如下命令打开定时任务编辑器:

crontab -e -u deployer

其中 -e 代表编辑,-u deployer 代表我们要编辑 deployer 用户的定时任务。

在最底下添加如下内容:

* * * * * php /home/wwwroot/demo.ilaoniu.cn/current/artisan schedule:run >> /home/wwwroot/demo.ilaoniu.cn/current/storage/logs/cron.log 2>&1

前面的 5 个 * 代表这个定时任务每分钟执行一次,后面的则是这个定时任务要执行的命令,同时我们使用 Linux 的管道 >> 将定时任务的输出追加到 cron.log 文件末尾,2 > &1 代表将错误输出也重定向到普通输出,即也输出到 cron.log 文件。

然后保存并退出。

现在来检查一下,输入以下命令:

crontab -l -u deployer

然后再执行:

ls /home/wwwroot/demo.ilaoniu.cn/current/storage/logs/

可以看到有 cron.log 文件,说明定时任务命令已经被触发过了。

如果没有看到 cron.log 文件,稍等一分钟后再试试。

再用 tail 命令看看这个日志文件:

tail -f /home/wwwroot/demo.ilaoniu.cn/current/storage/logs/cron.log

-f 选项可以让 tail 持续追踪日志文件,会实时输出日志文件末尾的内容。

6. 开启 OPcache

请注意,OPcache 缓存区命令行和 PHP-FPM 是分开的,要分别重置才可以。

使用 root 用户运行以下命令开启 OPcache:

cd /root/lnmp2.1/
./addons.sh

图片标题

输入 4 回车。

编辑 OPcache 配置:

vim /usr/local/php/conf.d/004-opcache.ini

修改如下:

[Zend Opcache]
zend_extension="opcache.so"
opcache.memory_consumption=128
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=10000
opcache.validate_timestamps=0
opcache.enable_cli=1

opcache.jit=1255
opcache.jit_buffer_size=64M

我们设置 opcache.validate_timestamps=0 关闭了通过检查时间戳的方式来更新缓存,因此需要在部署代码后手动更新。

安装 laravel-opcache 扩展包:

composer require appstract/laravel-opcache

在部署脚本 deploy.php 中添加任务:

task('artisan:opcache:clear', function () {
    run('cd {{release_path}} && {{bin/php}} artisan opcache:clear');
});

task('opcache_reset', function () {
    run('{{bin/php}} -r \'opcache_reset();\'');
});

// 重置 PHP 命令行 opcache
after('deploy:symlink', 'opcache_reset');

// 重置 FPM opcache
after('deploy:symlink', 'artisan:opcache:clear');

如果重置时提示 404,有可能是在添加重置路由前 OPcode 已经缓存了,更新后获取的路由依旧是之前的,这时手动重启 FPM 即可,后续因为已经有重置路由了不会再出现该问题。

lnmp php-fpm reload