80

我用 Kohana 建立的一个网站昨天被大量的流量猛烈抨击,让我退后一步并评估一些设计。我很好奇优化基于 Kohana 的应用程序的一些标准技术是什么?

我也对基准测试感兴趣。我是否需要为每个控制器方法设置Benchmark::start()Benchmark::stop()查看所有页面的执行时间,或者我是否能够在全球范围内快速应用基准测试?

我将在以后更多地使用缓存库,但我愿意接受更多建议,因为我确信我可以做很多我现在根本不知道的事情。

4

6 回答 6

211

我在这个答案中要说的并不是 Kohana 特有的,并且可能适用于许多 PHP 项目。

以下是我在谈到性能、可扩展性、PHP 时想到的一些要点……
我在从事多个项目时使用了许多这些想法——它们有所帮助;所以他们可能也可以在这里提供帮助。


首先,在表演方面,有很多方面/问题需要考虑

  • 服务器的配置(Apache、PHP、MySQL、其他可能的守护进程和系统);我想,您可能会在ServerFault上获得更多帮助,
  • PHP代码,
  • 数据库查询,
  • 使用或不使用您的网络服务器?
  • 你可以使用任何类型的缓存机制吗?或者您是否总是需要网站上的最新数据?


使用反向代理

可能真正有用的第一件事是在您的网络服务器前面使用反向代理,如varnish:让它缓存尽可能多的东西,因此只有真正需要 PHP/MySQL 计算的请求(当然还有其他一些请求,当它们不在代理的缓存中时)将其发送到 Apache/PHP/MySQL。

  • 首先,你的 CSS/Javascript/Images——好吧,一切都是静态的——可能不需要总是由 Apache 提供服务
    • 因此,您可以让反向代理缓存所有这些。
    • 为这些静态文件提供服务对 Apache 来说没什么大不了的,但它为这些文件工作的越少,它就越能用 PHP 做。
    • 请记住:Apache 一次只能处理有限数量的请求。
  • 然后,让反向代理从缓存中提供尽可能多的 PHP 页面:可能有些页面不会经常更改,并且可以从缓存中提供。与其使用一些基于 PHP 的缓存,为什么不让另一个更轻量级的服务器为它们提供服务(并且不时从 PHP 服务器获取它们,所以它们几乎总是最新的)
    • 例如,如果您有一些经常被请求的 RSS 提要(在尝试优化性能时,我们通常倾向于忘记这些提要) ,将它们缓存几分钟可以节省对 Apache+PHP 的数百/数千个请求+MySQL!
    • 对于您网站上访问量最大的页面也是如此,如果它们至少在几分钟内没有变化(例如:主页?),那么,每次用户请求它们时,无需浪费 CPU 重新生成它们。
  • 也许为匿名用户提供的页面(所有匿名用户的相同页面)和为已识别用户提供的页面(例如,“你好 X 先生,你有新消息”)之间存在差异?
    • 如果是这样,您可能可以配置反向代理以缓存为匿名用户提供的页面(通常基于 cookie,如会话 cookie)
    • 这将意味着 Apache+PHP 需要处理的事情更少:只有已识别的用户——这可能只是您用户的一小部分。

关于使用反向代理作为缓存,例如,对于 PHP 应用程序,您可以查看Benchmark Results Show 400%-700% increase In Server Capabilities with APC and Squid Cache
(是的,他们正在使用 Squid,我说的是清漆——这只是另一种可能性 ^^ 清漆更新,但更专注于缓存)

如果您做得足够好,并且设法一次又一次地停止重新生成太多页面,那么您甚至不必优化任何代码;-)
至少,也许不会急于求成...当您没有太大压力时,执行优化总是更好...


作为旁注:您在 OP 中说:

我用 Kohana 建立的一个网站昨天被大量的流量猛烈抨击,

这是一种突然的情况,如果您的网站可以处理不及时更新的情况,反向代理实际上可以节省一天的时间:

  • 安装它,配置它,让它总是——每天正常——运行:
    • 将其配置为不将 PHP 页面保留在缓存中;或仅在短时间内;这样,您始终可以显示最新数据
  • 而且,在您采用 slashdot 或 digg 效果的那一天:
    • 配置反向代理以将 PHP 页面保留在缓存中;或更长的时间;也许您的网页不会在第二秒之前更新,但它会让您的网站在挖掘效应中幸存下来!

关于那个,我怎样才能发现并在“Slashdotted”中幸存下来?可能是一个有趣的阅读。


在 PHP 方面:

首先:您使用的是最新版本的 PHP吗?随着新版本的推出,速度会定期得到改进;-)
例如,请查看PHP 分支 3.0 到 5.3-CVS 的基准测试

请注意,性能是使用 PHP 5.3 的一个很好的理由我已经做了一些基准测试(法语),结果很好) ......
当然,另一个很好的理由是 PHP 5.2 已经到了生命的尽头,并且不再维护!

您是否使用任何操作码缓存?

  • 我正在考虑APC - Alternative PHP Cache,例如peclmanual,这是我见过使用最多的解决方案 - 并且在我工作过的所有服务器上都使用过。
  • 在某些情况下,它确实可以大大降低服务器的 CPU 负载(我已经看到某些服务器上的 CPU 负载从 80% 下降到 40%,只需安装 APC 并激活它的操作码缓存功能!)
  • 基本上,PHP 脚本的执行分为两个步骤:
    • 将 PHP 源代码编译为操作码(相当于 JAVA 的字节码)
    • 执行这些操作码
    • APC 将它们保存在内存中,因此每次执行 PHP 脚本/文件时要做的工作更少:只需从 RAM 中获取操作码并执行它们。
  • 顺便说 一下,您可能需要查看APC 的配置选项
    • 其中有很多,有些会对您的速度/CPU负载/易用性产生很大影响
    • 例如,禁用[apc.stat](https://php.net/manual/en/apc.configuration.php#ini.apc.stat)可能有利于系统负载;但这意味着除非您刷新整个操作码缓存,否则不会考虑对 PHP 文件所做的修改;关于这一点,有关更多详细信息,请参阅例如To stat() Or Not To stat()?


对数据使用缓存

尽可能避免一遍又一遍地做同样的事情

我在想的主要事情当然是 SQL 查询:您的许多页面可能执行相同的查询,其中一些的结果可能几乎总是相同的......这意味着很多“无用”的查询数据库,它必须花时间一遍又一遍地提供相同的数据。
当然,对于其他事情也是如此,例如 Web 服务调用、从其他网站获取信息、繁重的计算……

您可能会很有趣地确定:

  • 哪些查询运行了很多次,总是返回相同的数据
  • 哪些其他(繁重)计算需要花费大量时间,总是返回相同的结果

并将这些数据/结果存储在某种缓存中,因此它们更容易获得——更快——而且您不必“无所事事”地访问您的 SQL 服务器。

伟大的缓存机制是,例如:

  • APC:除了我之前提到的 opcode-cache 之外,它还允许您将数据存储在内存中,
  • 和/或memcached 另请参阅) ,如果您确实有大量数据和/或使用多个服务器,这非常有用,因为它是分布式的。
  • 当然,你可以考虑文件;可能还有很多其他的想法。

我很确定您的框架带有一些与缓存相关的东西;您可能已经知道,正如您在 OP 中所说的“我将在未来更多时间使用缓存库”;-)


剖析

现在,一件好事是使用Xdebug扩展来分析您的应用程序:它通常可以很容易地找到几个弱点——至少,如果有任何功能需要花费大量时间的话。

配置得当,会生成profiling文件,可以用一些图形工具来分析,比如:

  • KCachegrind:我最喜欢的,但仅适用于 Linux/KDE
  • 用于 Windows 的Wincachegrind;不幸的是,它比 KCacheGrind 做的事情要少一些——它通常不显示调用图。
  • Webgrind在 PHP 网络服务器上运行,因此可以在任何地方工作——但可能功能较少。

例如,这里有几个 KCacheGrind 的截图:

KCacheGrind : 主屏幕
(来源:pascal-martin.fr(来源:pascal-martin.fr
KCacheGrind : 导出为图像的调用图

(顺便说一句,如果我没记错的话,第二个屏幕截图上显示的调用图通常是 WinCacheGrind 和 Webgrind 都不能做的事情^^)


(感谢@Mikushi 的评论)我没有使用太多的另一种可能性是xhprof扩展:它还有助于分析,可以生成调用图——但比 Xdebug 更轻,这意味着你应该能够将它安装在生产服务器。

您应该能够与 XHGui 一起使用它这将有助于数据的可视化。


在 SQL 方面:

既然我们已经谈到了 PHP,请注意,您的瓶颈很可能不是 PHP 方面的,而是数据库方面的......

这里至少有两三件事:

  • 您应该确定:
    • 您的应用程序执行的最常见查询是什么
    • 如果您使用的是 MySQL,是否 使用指令进行了优化(主要是使用正确的索引?)EXPLAIN
    • 是否可以缓存其中一些查询(请参阅我之前所说的)
  • 你的 MySQL 配置好了吗?我对此了解不多,但有一些配置选项可能会产生一些影响。

不过,最重要的两件事是:

  • 如果您不需要,请不要去数据库:尽可能多地缓存
  • 当你必须去数据库时,使用高效的查询:使用索引;和简介!


现在怎么办?

如果你还在阅读,还有什么可以优化的?

好吧,还有改进的空间......一些面向架构的想法可能是:

  • 切换到 n 层架构:
    • 将 MySQL 放在另一台服务器上(2 层:一层用于 PHP;另一层用于 MySQL)
    • 使用多个 PHP 服务器(并在这些服务器之间对用户进行负载平衡)
    • 将另一台机器用于静态文件,使用更轻的网络服务器,例如:
    • 为 MySQL 使用几台服务器,为 PHP 使用几台服务器,并在它们前面使用几个反向代理
    • 当然:在任何具有任意数量可用 RAM 的服务器上安装memcached守护程序,并尽可能多地使用它们来缓存/有意义。
  • 使用 Apache 的“更高效”的东西?
    • 我越来越多地听到关于nginx的消息,这对于 PHP 和大容量网站来说应该很棒;我自己从来没有用过,但你可能会在网上找到一些关于它的有趣文章;

好吧,也许其中一些想法在你的情况下有点矫枉过正^^
但是,仍然......为什么不研究一下,以防万一?;-)


那么小花呢?

您最初的问题是关于优化使用 Kohana 的应用程序...好吧,我已经发布了一些适用于任何 PHP 应用程序的想法...这意味着它们也适用于 Kohana
;-)(即使不是特定于它^^)

我说:使用缓存;Kohana 似乎支持一些缓存的东西 (你自己说过,所以这里没有什么新东西......)
如果有什么可以快速完成的,试试吧 ;-)

我还说你不应该做任何不必要的事情;Kohana 中是否有任何您不需要的默认启用的功能?
浏览网络,似乎至少有一些关于XSS过滤的东西;你需要那个吗?

不过,这里有几个可能有用的链接:


结论?

最后,一个简单的想法:

  • 贵公司支付您 5 天的费用将花费多少? -- 考虑到进行一些出色的优化是合理的时间
  • 贵公司购买(支付?)第二台服务器及其维护需要多少钱?
  • 如果你必须扩大规模怎么办?
    • 花10天要花多少钱?更多的?优化应用程序的每一个可能的部分?
    • 再多几台服务器多少钱?

我并不是说你不应该优化:你绝对应该!
但是,请进行“快速”优化,这将首先为您带来丰厚的回报:使用一些操作码缓存可能会帮助您减少 10% 到 50% 的服务器 CPU 负载……而且只需几分钟即可设置;- ) 另一方面,花 3 天时间获得 2%...

哦,顺便说一句:在做任何事情之前:把一些监控的东西放在适当的位置,这样你就知道做了哪些改进,以及如何改进!
如果没有监控,您将不知道您所做的事情的效果......即使它是否是真正的优化也不知道!

例如,您可以使用RRDtool + cacti之类的东西。
向你的老板展示一些 CPU 负载下降 40% 的漂亮图形总是很棒的 ;-)


无论如何,要真正得出结论:玩得开心!
(是的,优化很有趣!)
(呃,我不认为我会写那么多......希望至少其中的某些部分有用......我应该记住这个答案:可能在其他时候有用。 ..)

于 2009-08-16T00:26:44.793 回答
6

使用XDebugWinCacheGrindWebCacheGrind来分析和分析缓慢的代码执行。

WebCacheGrind
(来源:jokke.dk
WinCacheGrind

于 2009-08-11T13:00:46.253 回答
5

使用XDebug 分析代码。

使用大量缓存。如果您的页面是相对静态的,那么反向代理可能是最好的方法。

于 2009-08-11T12:55:32.197 回答
5

Kohana 开箱即用的速度非常快,除了使用数据库对象。引用 Zombor “您可以通过确保使用数据库结果对象而不是结果数组来减少内存使用量。” 这在被抨击的网站上产生了巨大的性能差异。它不仅会使用更多内存,还会减慢脚本的执行速度。

另外 - 您必须使用缓存。我更喜欢 memcache 并在我的模型中使用它,如下所示:

public function get($e_id)
{
    $event_data = $this->cache->get('event_get_'.$e_id.Kohana::config('config.site_domain'));

    if ($event_data === NULL)
    {
        $this->db_slave
            ->select('e_id,e_name')
            ->from('Events')
            ->where('e_id', $e_id);

        $result = $this->db_slave->get();
        $event_data = ($result->count() ==1)? $result->current() : FALSE;

        $this->cache->set('event_get_'.$e_id.Kohana::config('config.site_domain'), $event_data, NULL, 300); // 5 minutes
    }

    return $event_data;
}

这也将显着提高性能。上述两种技术将站点性能提高了 80%。

如果您提供更多关于您认为瓶颈在哪里的信息,我相信我们可以提供一些更好的想法。

另请查看 yslow (google it) 以了解其他一些性能提示。

于 2009-08-16T12:16:34.217 回答
1

与 Kohana 密切相关(您可能已经这样做了,或者没有这样做):

在生产模式下:

  1. 启用内部缓存(这只会缓存 Kohana::find_file 结果,但这实际上有很大帮助。
  2. 禁用分析器

只是我的 2 美分 :)

于 2012-12-31T00:04:14.427 回答
0

我完全同意 XDebug 和缓存的答案。在确定最大的速度和规模瓶颈之前,不要查看 Kohana 层进行优化。

XDebug 会告诉您您是否花费了大部分时间并识别代码中的“热点”。保留此分析信息,以便您可以基线和衡量性能改进。

示例问题和解决方案:如果您发现每次都从数据库中构建昂贵的对象,而这些对象并不经常更改,那么您可以考虑使用 memcached 或其他机制缓存它们。所有这些性能修复都需要时间并增加系统的复杂性,因此在开始修复它们之前请确保您的瓶颈。

于 2009-08-11T23:52:55.440 回答