bnomei/kirby3-boost

通过缓存文件/页面/用户的内容,并基于uuid进行快速查找,来提升Kirby的速度。

5.0.2 2024-08-03 07:24 UTC

README

Release Downloads Build Status Maintainability Twitter

通过缓存文件/页面/用户的内容,并基于uuid进行快速查找,来提升Kirby的速度。

商业使用


支持开源!

此插件免费,但如果您将其用于商业项目,请考虑赞助我或捐款。
如果我的工作帮助您赚了一些钱,那么我觉得我可能也应该得到一点回报,对吧?

善良一点。分享一点。谢谢。

—— Bruno
 

安装

  • master.zip 解压到 site/plugins/kirby3-boost 文件夹中,或者
  • 使用以下命令将git子模块添加到 site/plugins/kirby3-boost
  • composer require bnomei/kirby3-boost

使用场景

如果您必须在单个请求中处理大量页面对象(1000+),或者如果您有许多页面对象之间的关系需要解决,请考虑使用此插件。如果您处理的页面对象较少,可能不足以证明开销。

此插件是如何工作的?

  • 它缓存所有内容文件,并在您添加或修改内容时保持缓存更新。当构造页面对象时,将使用此缓存,这将使涉及页面对象的所有操作更快(甚至包括面板)。
  • 它提供基准测试,以帮助您决定使用哪个cachedriver。
  • 它将使用Kirby的uuid(唯一标识符)为页面对象创建关系,即使页面对象的slug或目录发生变化,这些关系也不会中断。
  • 它提供了通过id、diruri或uuid进行非常快速查找页面对象的方法。

设置

对于您希望缓存的每个模板,您需要使用一个模型,通过特质添加内容缓存逻辑。

site/models/default.php

class DefaultPage extends \Kirby\Cms\Page
{
    use \Bnomei\ModelHasBoost;
}

由于您大多数情况下将使用Kirby的自加载功能来处理 页面模型,因此您的类名必须以 Page 结尾。例如 site/models/article.phpArticlePagesite/models/blogpost.phpBlogpostPage

最后一步是在模板或控制器中调用以下命令来填充boost缓存。您只需这样做一次(而不是每次请求都这样做)。

// fill cache
$count = site()->boost();
echo $count . ' Pages have been boosted.';

恭喜!现在您的项目已经提升了。

用户模型

从版本1.9开始,您还可以通过在自定义模型中使用相应的特质/扩展,通过自定义插件来缓存用户模型的内容文件。

class AdminUser extends \Kirby\Cms\User
{
    use \Bnomei\ModelHasBoost;
}

Kirby::plugin('myplugin/user', [
    'userModels' => [
        'admin' => AdminUser::class, // admin is default role
    ],
]);

文件模型

从版本2.0开始,该插件可以对核心 Files 类进行monkey patch,以支持内容缓存。您只能一次为所有文件打开或关闭此功能,因为Kirby不允许自定义File模型。它需要首先读取内容文件,这将违反内容缓存的目的。

site/config/config.php

<?php

return [
    // other options
    'bnomei.boost.patch.files' => true, // default: true

目录库存缓存(实验性)

从版本5.0开始,插件将缓存目录的库存。为了实现这一点,它将修补Kirby\Filesystem\Dir类。如果您在面板中编辑页面,它将自动刷新缓存,就像核心的页面缓存一样。默认情况下它是启用的,但您可以根据需要禁用它,如下所示。

index.php

// after bootstrap and before kirby runs
\Bnomei\BoostDirInventory::singleton(['enabled' => false]);

您也可以手动刷新缓存。

\Bnomei\BoostDirInventory::singleton()->flush();

页面字段替代方案

此插件提供了一种基于多选字段并针对性能优化的页面字段替代方案。

site/blueprints/pages/default.yml

preset: page

fields:
  one_relation:
    extends: fields/boostidkv

  many_related:
    extends: fields/boostidkvs

您可以根据此插件提供的字段集合创建自己的相关页面字段。

更轻松地加载自定义模型、蓝图等

当您使用boost项目时,您可能会在插件中有一两个自定义模型。您可以使用我的自动加载助手来使注册这些类变得更容易。它还可以加载蓝图、类、集合、控制器、blockModels、pageModels、路由、api/routes、userModels、片段、模板和翻译文件。如果您通过composer安装了Boost插件,自动加载助手作为依赖项安装,您可以直接开始使用它。

用法

从PageId获取页面

$page = page($somePageId); // slower
$page = boost($somePageId); // faster

从DirUri获取页面

$page = boost($somePageDirUri); // fastest

从uuid获取页面

$page = page($uuid); // slower
$page = boost($uuid); // will use fastest internally

从uuids获取页面

$pages = pages([$uuid1, $uuid2, ...]); // slower
$pages = boost([$uuid1, $uuid2, ...]); // will use fastest internally

从uuid获取文件

$file = site()->file($uuid); // slower
$file = boost($uuid1); // will use fastest internally

解析关系

字段定义在上述示例蓝图上。

// one
$pageOrNull = $page->one_relation()->toPage(); // slower
$pageOrNull = $page->one_relation()->toPageBoosted(); // faster

// many
$pagesCollectionOrNull = $page->many_related()->toPages(); // slower
$pagesCollectionOrNull = $page->many_related()->toPagesBoosted(); // faster

从缓存获取修改时间戳

这将尝试从缓存中获取修改时间戳。如果页面对象内容可以缓存但当前未缓存,它将强制写入内容缓存。它将返回页面对象的修改时间戳,如果不存在则返回null

$pageModifiedTimestampOrNull = modified($someUuidOrPageId); // faster

从缓存中搜索模板

它将返回页面对象集合,您可以期望这比调用site()->index()->template('myTemplateName')要快得多。

 // in full site index
$allPagesWithTemplatePost = site()->searchForTemplate('post');

 // starting with blog as parent
$pagesWithTemplatePostInBlog = page('blog')->searchForTemplate('post');

缓存和缓存驱动程序

缓存驱动程序是一段代码,定义了缓存键/值存储的get/set命令的指向。Kirby支持内置的File、Apcu、Memcached和Memory。我为MySQLRedisSQLitePHP创建了额外的缓存驱动程序。

在Kirby中,缓存可以用于

  • Kirby自己的页面缓存以缓存完全渲染的HTML代码
  • 每个独立插件的插件缓存
  • 此插件提供的内容缓存
  • 部分缓存,如我名为Lapse的助手插件
  • 配置缓存尚不支持(尚不支持)

为了优化性能,最好对所有缓存使用相同的缓存驱动程序,但页面缓存除外。页面缓存最好使用文件缓存。

TL;DR

如果您有APCu缓存可用且您的内容适合定义的内存限制,请使用apcu缓存驱动程序。

调试 = 从内容文件读取(而不是从缓存)

如果您将Kirby的全局调试选项设置为true,插件将不会读取内容缓存,而是从磁盘上的内容文件中读取。但它会写入内容缓存,以便在处理过程中出现任何错误时,您可以获取调试信息。

强制内容缓存更新

您可以手动强制将过时的值写入缓存,但这样做通常是不必要的。

// write content cache of a single page
$cachedYesOrNoAsBoolean = $page->boost();

// write content cache of all pages in a Pages collection
$durationOfThisCacheIO = $page->children()->boost();

// write content cache of all pages in site index
$durationOfThisCacheIO = site()->boost();

限制

您在性能方面能获得多少提升,以及是否能获得提升,取决于硬件。所有内容文件都必须在内存限制范围内。如果遇到错误,请考虑增加服务器设置或选择不同的缓存驱动程序。

基准测试

包含的基准测试可以帮助您判断哪个缓存驱动程序更快。确保的唯一方法是测量生产环境中的情况。请注意,这将创建和删除1000个缓存项。基准测试将尝试在给定时间内(默认为每缓存1秒)执行尽可能多的获取操作。结果越高越好。

// use helpers to generate caches to compare
// rough performance level is based on my tests
$caches = [
    // better
    // \Bnomei\BoostCache::null(),
    // \Bnomei\BoostCache::memory(),
    \Bnomei\BoostCache::php(),       // 142
    \Bnomei\BoostCache::apcu(),      // 118
    \Bnomei\BoostCache::sqlite(),    //  60
    \Bnomei\BoostCache::redis(),     //  57
    // \Bnomei\BoostCache::file(),   //  44
    \Bnomei\BoostCache::memcached(), //  11
    // \Bnomei\BoostCache::mysql(),  //  ??
    // worse
];

// run the cachediver benchmark
var_dump(\Bnomei\CacheBenchmark::run($caches, 1, 1000)); // a rough guess
var_dump(\Bnomei\CacheBenchmark::run($caches, 1, site()->index()->count())); // more realistic
  • 内存缓存驱动程序和空缓存驱动程序将表现得最好,但它们要么仅缓存当前请求的内存,要么根本不缓存,这对本插件来说并不真正有用。
  • PHP缓存驱动程序将是可能的解决方案之一,但您可能会耗尽PHP应用程序内存。如果您需要最佳性能,完全控制服务器php.ini配置,并且缓存数据的大小适合您的应用程序内存,请使用此驱动程序。但此驱动程序不适合来自多个请求且处理时间重叠的并发写入。
  • APCu缓存可能非常快,但必须确保所有内容都适合内存限制。您还可以使用我的apcu缓存驱动程序带有垃圾回收
  • SQLite缓存驱动程序将表现得非常好,因为所有内容都在一个文件中,我已通过pragmaWAL日志模式优化了读写。内容将通过事务写入。
  • 我的Redis缓存驱动程序使用快速的Redis管道进行智能预加载,并将更改使用事务写入。
  • MySQL缓存驱动程序比Redis稍慢,也使用事务。
  • 文件缓存驱动程序的性能会随着页面对象的增加而下降。您可能最好不使用缓存。这是唯一具有这种缺陷的驱动程序。对该驱动程序的基准测试还会创建大量文件,这可能会使脚本超出PHP执行时间。

但不要只听我的话。下载插件,设置合理的基准测试选项,并在您的生产服务器上运行基准测试。

配置

一旦您知道要使用哪个驱动程序,您就可以设置插件缓存选项。

site/config/config.php

<?php

return [
    // other options
    // like Pages or UUID Cache
    // cache type for each plugin you use like the Laspe plugin

    // default is file cache driver because it will always work
    // but performance is not great so set to something else please
    'bnomei.boost.cache' => [
        'type'     => 'file',
    ],

    // example php
    'bnomei.boost.cache' => [
        'type'     => 'php',
    ],
    'cache' => [
        'uuid' => [
            'type' => 'php',
        ],
    ],

    // example apcu
    'bnomei.boost.cache' => [
        'type'     => 'apcu',
    ],
    'cache' => [
        'uuid' => [
            'type' => 'apcu',
        ],
    ],
    
    // example apcu with garbage collection
    'bnomei.boost.cache' => [
        'type'     => 'apcugc',
    ],
    'cache' => [
        'uuid' => [
            'type' => 'apcugc',
        ],
    ],

    // example sqlite
    // https://github.com/bnomei/kirby3-sqlite-cachedriver
    'bnomei.boost.cache' => [
        'type'     => 'sqlite',
    ],
    'cache' => [
        'uuid' => [
            'type' => 'sqlite',
        ],
    ],

    // example redis
    // https://github.com/bnomei/kirby3-redis-cachedriver
    'bnomei.boost.cache' => [
        'type'     => 'redis',
        'host'     => function() { return env('REDIS_HOST'); },
        'port'     => function() { return env('REDIS_PORT'); },
        'database' => function() { return env('REDIS_DATABASE'); },
        'password' => function() { return env('REDIS_PASSWORD'); },
    ],
    'cache' => [
        'uuid' => [
            // do same as boost
        ],
    ],

    // example memcached
    'bnomei.boost.cache' => [
        'type'     => 'memcached',
        'host'     => '127.0.0.1',
        'port'     => 11211,
    ],
    'cache' => [
        'uuid' => [
            // do same as boost
        ],
    ],
];

使用Boostmark验证

首先确保所有加速的页面在缓存中都是最新的。在模板或控制器中运行一次即可。这还会为尚未具有唯一ID的加速页面添加一个唯一ID(重新索引)。

// this can be skipped on next benchmark
site()->boost();

然后取消注释强制缓存更新,并运行跟踪内容加载次数和速度的基准测试。

// site()->boost();
var_dump(site()->boostmark());

如果您对某个页面集合的加载速度感兴趣,您也可以这样做。

// site()->boost();
var_dump(page('blog/2021')->children()->listed()->boostmark());

内存占用较低的网站索引

在Kirby中使用site()->index()会将所有页面同时加载到内存中。本插件提供了一种方法,可以在一次只加载一个页面的情况下迭代索引。

$boostedCount = 0;
$indexCount = \Bnomei\Bolt::index(function ($page) use (&$boostedCount) {
    // do something with that $page like...
    $boostedCount += $page->boost() ? 1 : 0;
});
// or just
$boostedCount = site()->boost();

设置

外部对内容文件的更改

如果您的其他方法(而不是Kirby的页面对象方法)写入内容文件,则需要启用bnomei.boost.fileModifiedCheck选项或基于模型重写checkModifiedTimestampForContentBoost(): bool方法。这将降低性能约1/3,但仍然比不使用缓存要快。

免责声明

本插件提供“原样”使用,不提供任何保证。请在自己的风险下使用,并在将其用于生产环境之前自行测试。如果您发现任何问题,请创建一个新的问题

许可协议

MIT

不建议在任何宣扬种族主义、性别歧视、恐同、动物虐待、暴力或其他任何形式仇恨言论的项目中使用此插件。