优化基于Kohana的网站的速度和可扩展性

80

我使用Kohana框架构建的网站昨天遭遇了大量的访问流量,导致我不得不回头评估一些设计。我想知道有哪些标准技术可用于优化基于Kohana的应用程序?

我对基准测试也很感兴趣。我是否需要为每个控制器方法设置 Benchmark::start()Benchmark::stop() 以便查看所有页面的执行时间,或者我可以全局和快速地应用基准测试?

我将在以后更多地使用Cache库,但是我对其他建议也持开放态度,因为我相信目前还有很多我不知道的东西。


你尝试过使用Kohana Profiler来构建应用程序并获取一些信息吗?它非常好。 - Yasen Zhelev
6个回答

211

我将在这个答案中说的内容不仅适用于Kohana,也可以适用于许多PHP项目。

以下是我谈到性能、可扩展性、PHP等方面时想到的一些要点...
我在几个项目中使用了许多这些想法——它们起到了帮助作用;所以它们可能在这里也有所帮助。


首先,当涉及到性能时,有许多方面/问题需要考虑

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


使用反向代理

第一件非常有用的事情是使用反向代理,像varnish这样,在您的Web服务器前面: 让它尽可能缓存许多东西,因此只有真正需要PHP / MySQL计算(当然,还有其他请求,当它们不在代理的缓存中时)才会到达Apache / PHP / MySQL。

首先,你的CSS/Javascript/Images -- 以及所有静态内容 -- 可能不需要总是由Apache提供服务,所以你可以让反向代理缓存所有这些内容。对于Apache来说,提供这些静态文件并不是什么大问题,但是它需要处理的越少,就越能够处理PHP。请记住:Apache一次只能提供有限数量的请求。
然后,尽可能让反向代理从缓存中提供尽可能多的PHP页面:可能有一些页面不经常更改,可以从缓存中提供服务。与其使用基于PHP的缓存,为什么不让另一个更轻量级的服务器提供服务呢?(而且从时间上来看,让它们时刻保持最新状态)
例如,如果您有一些RSS订阅(我们通常在优化性能时会忘记这些),它们被频繁请求,将它们缓存在几分钟内可以节省数百/数千个Apache+PHP+MySQL的请求!
对于您网站上访问量最高的页面,如果它们至少在几分钟内没有更改(例如主页),那么无需浪费CPU每次用户请求时都重新生成它们。
也许匿名用户服务的页面(所有匿名用户相同的页面)和为已识别用户服务的页面(例如“您好X先生,您有新消息”)之间存在差异?
如果是这样,您可能可以配置反向代理缓存为匿名用户提供服务的页面(基于cookie,例如会话cookie)。这意味着Apache+PHP需要处理的内容更少:仅识别用户 -- 这可能只是您用户中的一小部分。
关于在PHP应用中使用反向代理作为缓存,你可以查看基准测试结果显示APC和Squid Cache可以提高服务器性能400%-700%。 (是的,他们正在使用Squid,而我在谈论Varnish - 这只是另一种可能性^^ Varnish更加新颖,但更专注于缓存)
如果你做得足够好,并且成功地停止了反复生成太多页面,也许你甚至不需要优化任何代码;-) 至少,在任何紧急情况下都不需要...在没有太大压力的情况下执行优化总是更好的...
顺便说一句:你在OP中说: “我建立的一个Kohana网站昨天被大量流量淹没”, 这是一种突发情况,反向代理可以在这种情况下拯救一天,如果你的网站可以处理不实时更新的情况。
  • 安装它,配置它,让它始终运行:
    • 将其配置为不缓存PHP页面;或者只缓存短时间;这样,您总是可以显示最新的数据
  • 当您遇到Slashdot或Digg效应时:
    • 将反向代理配置为缓存PHP页面;或者缓存更长时间;也许您的页面不会每秒更新,但它将使您的网站幸存于Digg效应!

关于此,我如何检测和幸存于“Slashdot”?可能是一篇有趣的阅读。


在PHP方面:

首先:您是否使用了最新版本的PHP?新版本通常会有速度上的改进;-)
例如,看看PHP分支3.0到5.3-CVS的基准测试

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

您是否使用任何opcode缓存?

  • 我正在考虑使用APC - Alternative PHP Cache,例如(pecl, manual),这是我见过使用最多的解决方案,并且在我工作的所有服务器上都使用它。
  • 参见:Slides APC Facebook,或者Benchmark Results Show 400%-700% Increase In Server Capabilities with APC and Squid Cache
  • 它可以显著降低服务器的CPU负载,在某些情况下,(我曾经看到一些服务器的CPU负载从80%降至40%,只需安装APC并激活其opcode-cache功能!)
  • 基本上,执行PHP脚本分为两个步骤:
    • 将PHP源代码编译为opcode (类似于JAVA的字节码)
    • 执行这些opcodes
    • APC将这些内容保存在内存中,因此每次执行PHP脚本/文件时需要做的工作就少了:仅从RAM获取opcodes并执行它们。
  • 顺便说一下,您可能需要查看APC的configuration options
    • 其中有相当多的选项,有些选项对您的速度/ CPU负载/易用性都会产生很大的影响
    • 例如,禁用[apc.stat](https://php.net/manual/en/apc.configuration.php#ini.apc.stat)对系统负载有好处;但这意味着除非刷新整个opcode-cache,否则不会考虑对PHP文件所做的修改;关于此问题,有关详细信息,请参见To stat() Or Not To stat()?


使用缓存来处理数据

尽可能地避免重复做同样的事情,这是最好的。

主要考虑到SQL查询:你的许多页面可能做相同的查询,其中一些结果几乎总是相同的...这意味着数据库需要花费时间一次又一次地提供相同的数据,造成了大量"无用"的查询。
当然,对于其他东西也是如此,比如Web服务调用、从其他网站获取信息、重计算等等...

你可能会发现以下内容非常有趣:

  • 哪些查询被频繁运行,总是返回相同的数据
  • 哪些其他(繁重的)计算被频繁执行,总是返回相同的结果

并将这些数据/结果存储在某种缓存中,以便更容易地获取——更快——而不必为"无用"的查询去访问SQL服务器。

出色的缓存机制包括:

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

我相信你的框架已经带有一些缓存相关的东西;你可能已经知道了,因为你在原文中说过"未来我会更多地使用缓存库";-)


性能分析

现在,一个好的做法是使用Xdebug扩展来对应用程序进行性能分析:如果有任何需要花费大量时间的函数,它通常可以轻松找到一些薄弱点。

正确配置后,它将生成可由某些图形工具分析的性能分析文件,例如:

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

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

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

(顺便说一句,如果我没记错的话,第二个截图所呈现的调用图通常是WinCacheGrind和Webgrind都不能做到的 ^ ^)


(感谢@Mikushi的评论) 另一个我没怎么用过的可能性是xhprof扩展程序:它也有助于分析,可以生成调用图 - 但比Xdebug更轻量级,这意味着你应该能够在生产服务器上安装它。

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


关于SQL方面的事情:

既然我们已经谈论了一些PHP的内容,需要注意的是,你的瓶颈可能不在PHP方面,而是在数据库方面...

这里至少有两三件事:

  • 你应该确定:
    • 你的应用程序最常查询什么
    • 是否已经优化 (主要是使用正确的索引?),如果你使用的是MySQL,则使用EXPLAIN指令
    • 你是否可以缓存其中一些查询结果 (参见我之前说的内容)
  • 你的MySQL配置是否良好? 我不太懂,但是有一些配置选项可能会产生一些影响。

尽管如此,最重要的两件事情是:

  • 如果没有必要,不要访问数据库:尽可能进行缓存
  • 当必须访问数据库时,请使用高效的查询:使用索引;并进行性能分析!


现在怎么办?

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

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

  • 切换到n层架构:
    • 将MySQL放在另一台服务器上(2层:一个用于PHP;另一个用于MySQL)
    • 使用多个PHP服务器(并在这些服务器之间平衡负载)
    • 使用另一台机器来存储静态文件,使用更轻的Web服务器,例如:
    • 为MySQL使用多个服务器,为PHP使用多个服务器,并在这些服务器前面使用多个反向代理
    • 当然:在任何有空闲内存的服务器上安装memcached守护程序,并尽可能/合理地使用它们进行缓存。
  • 使用比Apache更高效的东西?
    • 我越来越经常听到nginx,它在处理PHP和高流量网站方面应该非常出色;我自己从未使用过它,但您可能会在网络上找到一些有趣的文章;

好吧,也许在你的情况下有些想法有点过头了^^
但是,为什么不学习一下它们,以防万一呢?;-)


那么 Kohana 呢?

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

我说过:使用缓存;Kohana 似乎支持一些缓存相关的东西 (你自己谈到过,所以没有新内容...)
如果有什么可以快速完成的事情,请尝试;-)

我还说你不应该做任何不必要的事情;Kohana 中是否启用了你不需要的任何功能?
在浏览网络时,似乎至少有一些与 XSS 过滤有关的内容;你需要它吗?

此外,以下是几个可能有用的链接:


结论?

最后,一个简单的想法:

  • 公司支付你5天需要多少费用?--考虑这是一个合理的时间做一些优化
  • 公司购买第二个服务器及其维护需要多少费用?
  • 如果您需要扩展规模呢?
    • 花费10天需要多少费用?更多吗?优化应用程序的每一个可能位?
    • 再增加几个服务器需要多少费用?

我并不是说您不应该进行优化:您肯定应该!
但是首先要进行“快速”优化,这将为您带来巨大的回报:使用某些操作码缓存可以帮助您减少服务器的CPU负载10%至50%……设置只需几分钟;-) 另一方面,为2%花费3天......

哦,顺便说一句:在做任何事情之前:先放置一些监控工具,以便您知道已经取得了什么改进和效果!
没有监控,您将不知道您所做的效果...甚至不知道它是否是真正的优化!

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


无论如何,最后要说的是: 玩得开心!
(没错,优化也很有趣!)
(额,我没想到我会写这么多...希望至少有些部分对你有用...我应该记住这个答案:可能在其他时候也会有用...)


虽然添加新服务器可能比让开发人员工作5天更便宜,但不要忘记当从多个服务器运行软件时,您的软件可能无法正常工作(您可能必须以某种方式在服务器之间共享文件 - NFS可能会很麻烦,您是否正在使用会话?最好将它们移动到数据库中等),这本身也需要开发人员进行处理。 - NSSec
16
非常清晰易懂的讲解!你有博客可以订阅吗? :-) - Grey Panther
@dnh828:我写这个是希望能在其他场合重复使用它(实际上我已经这样做了);; @MathieuK:绝对正确(关于会话,不过,你也可以考虑使用memcache而不是DB);; @Cd-MaN:谢谢!我确实有一个博客,但它是用法语写的,而且我真的不经常写博客...不过,如果你感兴趣:http://blog.pascal-martin.fr/ - Pascal MARTIN
考虑查看XHProf(http://pecl.php.net/package/xhprof),我发现它比XDebug更适合对我的代码进行分析,特别是在生产服务器上。结合XHGui(https://github.com/preinheimer/xhprof),使用起来非常愉快。 - Mikushi
真遗憾,不是吗?;-) ;; 不过你可以使用https://dev59.com/bnM_5IYBdhLWcg3wt1k0链接分享这个问题--这样更多的人就可以阅读这个答案了(这也正是我写这么长的答案的原因:为了让它被阅读^^) - Pascal MARTIN

6

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(谷歌搜索)获取其他性能提示。


5

使用XDebug来编写简介代码。

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


1

严格与Kohana相关(您可能已经完成了这个,或者还没有):

在生产模式下:

  1. 启用内部缓存(这将仅缓存Kohana::find_file结果,但实际上可以帮助很多。
  2. 禁用分析器

只是我的两分钱 :)


0

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

XDebug将告诉您花费最多时间的地方,并识别代码中的“热点”。保留此分析信息,以便您可以基准测试和测量性能改进。

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接