【问题标题】:Why is Symfony2 app spending 70-90% of its time parsing YAML?为什么 Symfony2 应用程序花费 70-90% 的时间来解析 YAML?
【发布时间】:2014-09-04 17:41:54
【问题描述】:

如下面的 Webgrind 输出所示,我的应用程序的大部分处理时间都花在了 YAML 解析上。

注意:Webgrind 输出以“百分比”为单位。因此,将“总自身成本”加起来显示总时间的 83.63% 用于处理 YAML。

我看过这个相关的帖子:

Symfony2 Application Parses YML On Every Request

但是,我的实现使用的是 ApcClassLoader 类,如下所示:

$loader = new ApcClassLoader('odr_dev', $loader);
$loader->register(true);

此外,我已经使用 apc.php 检查了 APC 系统,我的类和页面在 APC 缓存中找到并且正在被命中。即使在填充缓存之后,这也会在任何请求的 PROD 或 DEV 上发生。

我的理论是我们有一个循环实体引用,系统无法成功解析 YAML 以缓存它。因此,它最终会尝试在每个请求上解析 YAML。

但是,我在日志中没有看到任何关于无法解析 YAML 或任何内容的错误,并且不确定如何确定是否会出现这种情况或下一步该去哪里查看。

【问题讨论】:

  • 你追溯Parser->parse()函数的具体调用者了吗?
  • 我一直在努力,希望能找到今晚调用它们的原因。当我发现发生了什么时,我会发布更新。
  • 注意 - 我正在运行 2.3.18 - 最新的长期支持版本。也许这在不同的版本上表现不同。我在下面发布了我的解决方案(接受的答案),它非常明确地适用于这个版本的代码。

标签: php symfony doctrine-orm yaml


【解决方案1】:

我认为您的问题可能是递归 YAML 资源(或类似资源)。您会看到 4000 多次 Yaml\Parser::parse 调用。在使用完全空缓存的页面加载测试我自己的应用程序(相当复杂)时,我只看到 166 次调用。并且使用热缓存的页面加载下降到 2 次调用。

正如您所发现的,我认为您使用类加载器缓存不会对 YAML 解析产生任何影响。我怀疑您链接到的票可能是错误的)

【讨论】:

  • 感谢您提供有关您的代码看到多少解析器调用的信息。我同意我的似乎太高了,并且倾向于表示循环引用或其他内容。我认为这一定是仅与缓存有关,或者解析器在完成之前以某种方式退出了。事实上,解析器确实完成并且元数据已成功存储。所以,解决方案是......(见我的回答)
【解决方案2】:

在单步执行此过程中涉及的每一行代码后,我发现 Doctrine 正在使用默认的“数组”缓存,该缓存仅对单个页面加载有效。

我认为我自己和许多其他人都认为,当我们打开 APC 时,Doctrine 也会使用它来缓存元数据。事实上,Doctrine 默认使用它的数组缓存,除非另有说明。

此页面列出了 Doctrine 配置选项:

http://symfony.com/doc/2.3/reference/configuration/doctrine.html

在我的/app/config/config.yml添加缓存驱动选项后如下图:

doctrine:
    dbal:
        driver:   %database_driver%
        host:     %database_host%
        port:     %database_port%
        dbname:   %database_name%
        user:     %database_user%
        password: %database_password%
        charset:  UTF8
    orm:
        auto_generate_proxy_classes: %kernel.debug%
        auto_mapping: true
        result_cache_driver:
            type: memcached
            host: 127.0.0.1
            port: 11211
            instance_class: Memcached
        metadata_cache_driver:
            type: memcached
            host: 127.0.0.1
            port: 11211
            instance_class: Memcached
        query_cache_driver:
            type: memcached
            host: 127.0.0.1
            port: 11211
            instance_class: Memcached

修复后,同一页面显示没有 YAML 解析器交互并在 302 毫秒与 5851 毫秒内加载,总加速为 19 倍。此外,cachegrind 文件从 121MB 变为 3.4MB,这些结果在多次试验中基本一致。

这是显示差异的同一个 Webgrind:

所以,基本上,这是一个配置问题。从我在 StackOverflow 问题和其他论坛中看到的情况来看,这里似乎对缓存的工作方式存在脱节。本质上,您需要为 Doctrine 缓存显式打开它,如上所述,否则它使用基本无用的默认值。

Symfony2 有时可能过于“可配置”,这是我从未想过它可以单独配置的一个实例。在这方面,它是一个强大的功能(能够为事物使用单独的缓存),但在你弄清楚这一点之前,就速度而言,系统完全受到影响。

【讨论】:

  • 注意:我选择使用 Memcached 进行元数据缓存,因为新的 PHP 操作码缓存不推荐使用 APC,并且 APC 在较新的 PHP 安装中不可用。从本质上讲,只要 PHP 支持 Memcached,这将在一段时间内证明该解决方案的未来。
  • 我不确定这是不是问题所在。我们只在生产中使用跨请求缓存(并不总是在那里)。使用 Doctrine 数组不应该扼杀你的表现。我认为您打开的缓存可能只是隐藏了您的 YAML 的一个更大问题。除非你有大量的 Doctrine 元数据文件?
  • 根据 symfony 的开发界面,我所有的学说文件都显示为 100% ok。此外,很明显,这是查看代码所需的设置。如果你在没有它的情况下运行,我几乎 100% 肯定,如果你缓存这些东西,你会跑得更快。
  • 谢谢。我将加载时间从 1.4 秒减少到 0.3
猜你喜欢
  • 2013-08-26
  • 2021-01-07
  • 1970-01-01
  • 1970-01-01
  • 2013-08-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多