laragear/preload

轻松为您的 Laravel 应用程序制作 Preload 脚本。

v2.0.0 2024-03-06 20:44 UTC

This package is auto-updated.

Last update: 2024-09-13 07:30:33 UTC


README

Latest Version on Packagist Latest stable test run Codecov coverage Maintainability Sonarcloud Status Laravel Octane Compatibility

动态预加载您的 Laravel 应用程序。

此包会自动从您的 Opcache 统计信息中生成一个 PHP 预加载 脚本。无需手动修改。

成为赞助商

您的支持使我能够保持此包免费、更新和可维护。或者,您也可以 传播这个消息!

要求

安装

使用 Composer 在项目中要求此包

composer require laragear/preload

注意

此包在安装过程中不需要 ext-zend-opcache 扩展。只需确保在您的部署服务器中 已启用

什么是预加载?它会让我的应用更快吗?

PHP 解释器需要读取和编译项目中每个请求的文件。当 Opcache 已启用时,它将在内存中保留已解释的文件,而不是再次从文件系统中读取,这要快得多。

Opcache 的预加载允许在 PHP 进程启动时,在正常执行之前,将给定文件列表存储在内存中。这使得应用程序在首次请求时 更快,因为这些要读取的文件已经在内存中。借助 JIT,这些文件还会被编译成字节码,从而节省了另一步。

此包会生成一个包含应用程序中最常访问的文件的预加载文件。完成之后,您可以将生成的列表指向您的 php.ini

opcache.preload_user = 'www-data'
opcache.preload = 'www/app/preload.php';

之后,下次 PHP 启动时,此文件列表将自动预加载。

注意

如果您位于共享服务器上,预加载可能无法为您的应用程序提供。通常,共享服务器也会共享相同的 PHP 进程,该进程的配置(php.ini)不可用于配置。如果您不确定是否应该安装 Laragear Preload,请检查您的服务器。

用法

默认情况下,此包会在每 10,000 次请求后推送一个队列作业数据,其中包含应用程序中最常访问的文件列表的有限列表。

首先,由于您将从一个未生成的脚本开始,请使用 preload:placeholder 命令创建一个空的预加载列表。

php artisan preload:placeholder

# Generating a preload placeholder at: /www/app/preload.php
#
# Empty preload stub generated
# Remember to edit your [php.ini] file:
# opcache.preload = '/www/app/preload.php';

重要

如果文件已存在,则命令不会替换文件。您可以使用 --force 强制执行操作。

在您的 php.ini 中添加预加载文件路径

opcache.preload = '/www/app/preload.php';

配置

有些人可能不满意“默认”行为。幸运的是,您可以配置自己的脚本生成方式。

首先发布配置文件

php artisan vendor:publish --provider="Laragear\Preload\PreloadServiceProvider"

让我们检查配置数组

<?php

return [
    'enabled' => env('PRELOAD_ENABLE'),
    'condition' => [
        'store' => null,
        'hits' => 10000,
        'key' => 'preload|request_count'
    ],
    'project_only' => true,
    'memory' => 32,
    'job' => [
        'connection' => env('PRELOAD_JOB_CONNECTION'),
        'queue' => env('PRELOAD_JOB_QUEUE'),
    ],
    'path' => base_path('preload.php'),
    'use_require' => false,
    'autoload' => base_path('vendor/autoload.php'),
    'ignore_not_found' => true,
];

启用

return [
    'enable' => env('PRELOAD_ENABLE'),
];

默认情况下,在生产环境中会自动注册一个全局中间件。您可以使用环境变量强制启用或禁用此中间件,分别设置为 truefalse

PRELOAD_ENABLE=true

条件

return [
    'condition' => [
        'store' => null,
        'hits' => 10000,
        'key' => 'preload|request_count'
    ],
];

本软件包包含一个简单的条件回调,当计数达到10,000次成功请求时返回true。此数组作为$options参数发送到回调,如果您想定义自己的条件,这将很有用

use Illuminate\Http\Request;
use Laragear\Preload\Facades\Preload;

Preload::condition(function (array $options) {
    return random_int(1, $options['max']) < 3;
});

项目范围

return [
    'project_only' => true,
];

某些PHP进程可能在多个项目之间共享。为了避免在当前项目外预加载文件,默认设置为true。禁用它将允许无论目录如何都预加载文件。

内存限制

return [
    'memory' => 64,
];

列表的内存限制(以兆字节为单位)。一旦达到此阈值,列表中将不再包含更多脚本。

对于大多数应用程序,32MB就足够了,但您可以针对特定项目进行微调。

注意

这不是Opcache内存限制,因为它单独处理。

作业配置

return [
    'job' => [
        'connection' => env('PRELOAD_JOB_CONNECTION'),
        'queue' => env('PRELOAD_JOB_QUEUE'),
    ],
];

当作业接收到要持久化的列表时,它将被分配到此处设置的连接和队列。如果为null,框架将使用默认值。您可以使用您的.env文件来设置它们

PRELOAD_JOB_CONNECTION=redis
PRELOAD_JOB_QUEUE=low

路径

return [
    'path' => base_path('preload.php'),
];

默认情况下,脚本保存在您的项目根路径中,但您可以根据需要更改文件名和路径来保存它,只要PHP有权限写入即可。无论您将其放置在哪里,都不要将其放在公开/可访问的目录中,如publicstorage/app/public

重要

请务必检查您的文件权限,以避免在生产中读取文件时出现失败。

方法

return [
    'use_require' => true,
    'autoload' => base_path('vendor/autoload.php'),
];

Opcache允许使用require_onceopcache_compile_file()预加载文件。

预加载使用opcache_compile_file()以更好地管理预加载的文件。一些未解决的链接在启动时可能会输出警告,但不会产生严重问题。

使用require_once执行所有文件。通过在编译之前解析所有链接(导入、父类、特质、接口等),它可能在不应执行的文件(如纯脚本)上输出大量错误。根据您的应用程序,您可能希望使用其中一个而不是另一个。

如果您计划使用require_once,请确保您已设置Composer自动加载的正确路径,因为它将被用于解析类等文件。

忽略未找到的文件

return [
    'ignore_not_found' => true,
];

一些文件由Laravel在运行时创建,并由Opcache积极缓存,但在部署时却不存在,如实时外观。忽略它们是安全的,默认情况下已启用。

您可以根据任何原因禁用此功能,这将抛出一个异常,如果任何文件丢失,但除非您知道自己在做什么,否则建议您不要更改它。

排除和附加文件

通过在App Service Provider中发出包含目录路径的数组,通过Preload外观,从目录中排除和附加文件。

您还可以使用接收Symfony Finder(包含在此包中)的函数,以获得更多的过滤选项。

use Symfony\Component\Finder\Finder;
use Illuminate\Support\ServiceProvider;
use Laragear\Preload\Facades\Preload;

class AppServiceProvider extends ServiceProvider
{
    // ...
    
    public function boot()
    {
        Preload::append(function (Finder $find) {
            $find->in(base_path('foo/'))
                ->contains('class ')
                ->name('*.php');
        });
        
        Preload::exclude(
            base_path('/bar/'),
            base_path('/baz/Http/'),
        );
    }
}

自定义条件

此软件包包括一个简单的条件回调:每10,000次请求返回true。请求次数、要使用的缓存以及缓存的键可以在配置的condition部分设置。

在某些情况下,您可能想使用随机种子或定期生成列表。您可以通过在AppServiceProvider中设置回调来创建自己的条件。

use Laragear\Preload\Facades\Preload;
use Illuminate\Support\Facades\Cache;

public function register()
{
    Preload::condition(function () {
        if (Cache::has('preload generated yesterday')) {
            return false;
        }
        
        Cache::put('preload generated yesterday', true, now()->endOfDay());
        
        return true;
    });
    
    // ...
}

常见问题解答

  • 我可以手动禁用预加载器吗?

是的。这基本上是不注册全局中间件。

  • 我需要在生成列表后重新启动PHP吗?

不需要,生成的列表已经在Opcache内存中。

  • 当我使用它时,软件包返回了错误!

请检查您是否正在使用最新的PHP稳定版本,并且Opcache已启用。另外,请检查脚本路径是否可写。所有PHP错误都会被记录,所以请检查一下。

如果您确定这是由软件包引起的错误,请提交一个issue,并提供完整的细节和堆栈跟踪。

  • 为什么我不能使用php artisan preload:generate或者一个计划任务呢?

当使用PHP CLI时,Opcache不会被启用,如果启用了,它将收集CLI统计信息。您必须让此软件包从实时应用程序中收集真实统计信息。

  • 这会将软件包本身排除在列表之外吗?这有影响吗?

不,没有影响。只有全局中间件和条件可能被频繁请求,但大多数此软件包的文件都不会。

  • 我激活了这个Preload,但我的应用程序仍然感觉不。怎么回事?

在预加载脚本下,初始请求应该会更快。这不会以任何方式影响Opcache或整个应用程序的性能。

如果您仍然感觉应用程序很慢,请记住基准测试您的应用程序,缓存您的配置和视图,检查您的数据库查询和API调用,以及队列昂贵的逻辑等。您还可以使用Laravel Octane

  • 列表是如何创建的?

基本上:按访问次数最多的文件降序排列。每个文件都会消耗内存,因此当累计内存使用达到限制(默认为32MB)时,列表会被截断。

如果最后一个文件是一个带有列表外链接的类,PHP将发出一些警告,这是正常且预期的,但如果这些文件之前未被添加,它不会编译链接的文件。

  • 我能否只是将项目中所有的文件都放进去?

您不应该这样做。包含应用程序中所有文件可能的效果可能不如仅包含最常请求的文件,而且这会使预加载耗时更长。

您总是可以通过基准测试您的应用程序来自证这是错误的。

  • 我可以使用自定义条件吗?

是的。

  • 我可以禁用中间件吗?或者只检查XXX状态?

是的。如果您需要仅检查给定的响应状态代码,您可以创建一个自定义中间件。

  • 中间件在单元测试中工作吗?

不,在单元测试环境下运行的应用程序中,中间件不会被注册。

  • 我如何知道预加载脚本是否已成功生成?

在请求过程中生成列表时,将触发ListGeneratedScriptStored事件,分别通过排队作业保存脚本。

您可以添加监听器以发送电子邮件或Slack通知。

composer.json中排除或包含文件

您可以对要预加载的软件包以及要从列表中排除或包含的文件有更好的控制。

如果您的composer.json文件中,使用extra.preload.exclude键与软件包名称和文件路径。这些字符串将被传递给底层的Symfony Finder实例。

使用true将排除软件包名称下的所有文件。

{
    "extra": {
        "preload": {
            "exclude": {
                "laragear/meta": ["src/Cache/*", "resources/views"],
                "charlesdp/builder": true
            }
        }
    }
}

Laravel Octane 兼容性

  • 注册了一个Preloader类到应用程序和配置中。在启动时没有理由解析它。
  • 注册了一个Condition类到应用程序和配置中。出于安全目的,配置不应被更改。

除此之外,真实的条件回调总是使用服务容器在每个请求中执行,因此它可以(但不应该)解析一个新的配置存储库。

安全性

如果您发现任何与安全相关的问题,请通过电子邮件发送至 darkghosthunter@gmail.com,而不是使用问题跟踪器。

许可证

本特定软件包版本在发布时受 MIT 许可证 的约束。

LaravelTaylor Otwell 的商标。版权所有 © 2011-2023 Laravel LLC。