【问题标题】:Is there any compatible memory cache for PHP 7?PHP 7 是否有兼容的内存缓存?
【发布时间】:2016-09-03 16:32:08
【问题描述】:

我想使用 PHP 7。但是似乎没有 键值内存缓存 选项。

APC is discontinued.

XCache will not be available for PHP 7 for some time

PHP 7 是否有可用的替代方案?

或者有没有办法使用PHP7的Opcache来实现key-value内存缓存?

【问题讨论】:

  • 用 memcached 试过了吗?
  • 我问的不是这个。我知道差异会随着对缓存的请求数量而增加。这是简单的数学。 ;-) 但我仍然从未听说这在任何规模的项目中都是一个问题。我仍然不确定这是否是真的。在键/值存储的情况下,APC 和 Redis 或 memcached 的工作方式几乎相同。因此,基准或它是一个谎言。 ;-)
  • 这是一个微优化,不值得。如前所述,Redis 和 memcached 是正常的方式。我最好重构那些经常提出这么多请求询问“数百个值”的代码。
  • @Frodik 如果每个请求有数百次,您是否可以批量处理它们? Memcached 具有 setMulti/getMulti 功能,因此您只需一个网络请求的开销,而不是数百个。
  • 您可以为 Memcached(或 Redis)做的另一项优化是通过套接字连接,如果在本地主机上,则不是 TCP/IP。您提到您使用基于网络的 memcached,理论上它应该比基于套接字的连接慢,因为您必须添加网络协议处理。

标签: php apc opcache xcache


【解决方案1】:

APCU 字面意思是没有代码缓存的 APC(他们获取了 APC 代码,删除了字节码缓存并将其作为 APCU 发布)。这是一个插入式的替代品。就像 APC 的用户缓存一样,它将数据保存在与 PHP 运行时相同的进程中,因此使用该值就像检索普通变量一样,因此速度很快。

【讨论】:

  • 嗯,是的,但是 PHP 5.3 或更高版本上的 APC 一切都不是稳定的 :-( 所以即使它可能与 PHP 7 一起运行,我也很担心它也会受到不稳定的影响。
  • 不要害怕,但试试吧。除了原生内置的 zend opcache 之外,您可能还需要 APCu,而且它非常稳定。
【解决方案2】:

如果您担心性能,我建议您使用Memcached尤其是

虽然您认为 APC(u) 比 Memcache 快很多是正确的,但您并没有考虑到 当您担心这些指标时,您将在多个服务器上运行 和 APC(u) 不能跨节点共享。

您可以使用单个 Memcache 实例或集群来服务任意数量的应用程序服务器。在现代应用程序开发中,可扩展性比“我可以从一台服务器中挤出多少性能?”更为关注。

话虽如此,您的替代方案是APCu,它具有您习惯于 APC 的所有功能。它在 PHP7 中被标记为稳定,但我不建议这样做,因为它具有单节点性质并且无法与 fastcgi 一起正常工作。

【讨论】:

  • 感谢您的回答。我们的应用程序非常专业,我们已经在使用 memcache 并且出于您提到的原因。但是,正如我所说,我们还需要在本地缓存数百个 key-value 数据,这些数据是 memcached 等不太适合的。但我同意你的看法,这个答案对运行“普通”网站的人很有用。
  • @Frodik 在这种情况下,APCu 可能是您将获得的最好的(至少在不了解您的具体用法的情况下)。值得一提的是,Memcache 有一堆 set multiget multi 函数,如果你同时设置这数百个函数,它们可能对你有用。这将为您节省多个请求的开销。
  • 如果您在 Windows 上怎么办? Windows 上似乎没有 Memcached 的 dll。这是否意味着任何使用 PHP 开发且需要内存缓存的人都必须在 unix 环境中开发,还是我缺少什么?
【解决方案3】:

另一种方法(我没有尝试过,但听起来很有趣)是利用 opcache 作为键值缓存。这篇 graphiq 帖子包含更多细节,但遗憾的是没有真正的代码(请注意来自 Kerry Schwab 的 cmets)。

它的要点是确保 opcache 已启用并为您需要缓存的数据分配足够的内存,然后按照以下内容进行操作(摘自文章,完整查看)。缓存过期(除了手动删除)也需要处理,但不会很难添加(例如,将您的数据包装在具有过期时间的包含对象中并在您的cache_get 中检查它,删除并忽略记录如果它已过期)。

function cache_set($key, $val) {
   $val = var_export($val, true);
   // HHVM fails at __set_state, so just use object cast for now
   $val = str_replace('stdClass::__set_state', '(object)', $val);
   // Write to temp file first to ensure atomicity
   $tmp = "/tmp/$key." . uniqid('', true) . '.tmp';
   file_put_contents($tmp, '<?php $val = ' . $val . ';', LOCK_EX);
   rename($tmp, "/tmp/$key");
}

function cache_get($key) {
    @include "/tmp/$key";
    return isset($val) ? $val : false;
}

由于 opcache 的作用是作为内存中的缓存,但它避免了序列化和反序列化的开销。我猜 cache_set 在写入时也应该调用opcache_invalidate(以及在他们的示例中不存在的cache_delete 函数中),但是对于不需要在服务器之间共享的缓存来说似乎是合理的。

编辑:缓存到期的示例实现(仅精确到一秒,如果需要更高的精确度,可以使用microtime(true))。实际上做了最少的测试,我放弃了 HHVM 特定的替换,所以 YMMV。欢迎提出改进建议。

class Cache {                                                                   
    private $root;                                                              
    private $compile;                                                           
    private $ttl;                                                               

    public function __construct($options = []) {                                
        $this->options = array_merge(                                           
            array(                                                              
                'root' => sys_get_temp_dir(),                                   
                'ttl'  => false,                                                
            ),                                                                  
            $options                                                            
        );                                                                      
        $this->root = $this->options['root'];                                   
        $this->ttl = $this->options['ttl'];                                     
    }                                                                           

    public function set($key, $val, $ttl = null) {                              
        $ttl = $ttl === null ? $this->ttl : $ttl;                               
        $file = md5($key);                                                      
        $val = var_export(array(                                                
            'expiry' => $ttl ? time() + $ttl : false,                           
            'data' => $val,                                                     
        ), true);                                                               

        // Write to temp file first to ensure atomicity                         
        $tmp = $this->root . '/' . $file . '.' . uniqid('', true) . '.tmp';     
        file_put_contents($tmp, '<?php $val = ' . $val . ';', LOCK_EX);         

        $dest = $this->root . '/' . $file;                                      
        rename($tmp, $dest);                                                    
        opcache_invalidate($dest);                                              
    }                                                                           

    public function get($key) {                                                 
        @include $this->root . '/' . md5($key);                                 

        // Not found                                                            
        if (!isset($val)) return null;                                          

        // Found and not expired                                                
        if (!$val['expiry'] || $val['expiry'] > time()) return $val['data'];    

        // Expired, clean up                                                    
        $this->remove($key);                                                    
    }                                                                           

    public function remove($key) {                                              
        $dest = $this->root . '/' . md5($key);                                  
        if (@unlink($dest)) {                                                   
            // Invalidate cache if successfully written                         
            opcache_invalidate($dest);                                          
        }                                                                       
    }                                                                           
}      

【讨论】:

  • 喜欢这段代码,将在项目中使用,谢谢分享!
【解决方案4】:

PHP 7 缓存/加速器列表

死/过时 PHP 加速器列表:XCache、APC、memoize、ZendOpcache、 chdb、hidef(它们不支持 PHP 7)

我们可以在PECL website 上找到 PHP 加速器列表,但正如我提到的,其中一些已停产或不是最新的。

目前开发的(支持 PHP 7.3)有:

您将在下载的 tgz/zip 文件中找到所有安装说明。

APCu WINDOWS 用户: 下载与您的系统规格 x64(64 位)或 x86(32 位窗口)匹配的 APCu 和 APCu_bc DLL 文件,选择 TS 或 UTS 版本,当然还有正确的 PHP 版本。将 .DLL 粘贴到您的 php/ext 目录中 您可以通过查看您的 php 目录 来确定线程模式。在 DLL 文件名处查找(例如:php7ts.dll)。注意文件名中的 TS 或 UTS。

php -v 将显示您当前的 PHP CLI 安装版本。 只需确保您的 PHP 版本与您在服务器中使用的版本相同。如果不更改,请更新 PHP 的 windows 环境路径。

如果您有困难,请阅读:How to install apcu in windows https://kapilpatel84.wordpress.com/2016/06/15/install-xdebug-apcu-on-windows-xampp-for-php7/

对于 XAMPP:

1) 使用以下链接下载兼容的 APCu http://pecl.php.net/package/apcu

2) APCu 需要与 APC 兼容的 backword,因此您必须使用以下链接下载它。 http://pecl.php.net/package/apcu_bc

3) 提取 DDL 文件并移动名为 php_apc.dll 和 php_apcu.dll 的 DDL 文件并将这些文件复制到您的 PHP ext 目录。即 C:\xampp\php\ext

4) 打开php.ini文件,复制文件底部如下代码

[apcu]
extension="C:\xampp\php\ext\php_apcu.dll"
apc.enabled=1
apc.shm_size=32M
apc.ttl=7200
apc.enable_cli=1
apc.serializer=php
extension="C:\xampp\php\ext\php_apc.dll"

当您解压缩文件时。将 DLL 文件复制到您的 PHP 扩展文件夹 np: .../php/ext. 并配置php.ini(con​​f指令包含在INSTALL文本文件中)。

Symfony 4

PS。如果您有任何机会使用 Symfony 框架,请不要忘记在 config>packages>cache.yaml 中启用 APCu

framework:
    cache:
        app: cache.adapter.apcu

使用内置服务器:

php bin/console server:run

【讨论】:

  • OPCache 并没有死,它是事实上的标准 PHP 加速器,自 PHP 5.6 以来的每个发行版都或多或少地作为 PHP 的组成部分提供。此外,它在性能方面是必须使用的扩展。
  • @DanilaVershinin 你是对的。感谢您指出了这一点。 “此扩展与 PHP 5.5.0 及更高版本捆绑在一起,并且 » 在 PECL 中可用于 PHP 5.2、5.3 和 5.4 版本。”我错过了“及以后”部分。
猜你喜欢
  • 1970-01-01
  • 2016-07-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-27
  • 1970-01-01
  • 2014-08-04
  • 2010-12-13
相关资源
最近更新 更多