当前位置:  开发笔记 > 编程语言 > 正文

在高负载站点中使用PHP的策略

如何解决《在高负载站点中使用PHP的策略》经验,为你挑选了11个好方法。

在回答这个问题之前,我从来没有开发出任何足以获得高服务器负载的东西.把我视为(感叹)一个刚刚降落在这个星球上的外星人,虽然他知道PHP和一些优化技术.


我正在开发一个PHP工具,可以获得相当多的用户,如果它正确的话.然而,虽然我完全有能力开发这个程序,但在制作可以处理巨大流量的东西方面,我几乎一无所知.所以这里有几个问题(随意将这个问题转化为资源线程).

数据库

目前我打算在PHP5中使用MySQLi功能.但是,我应该如何设置与用户和内容相关的数据库?我真的需要多个数据库吗?目前,所有内容都混杂在一个数据库中 - 尽管我一直在考虑将用户数据分散到一个数据库,将实际内容传播到另一个数据库,最后将核心网站内容(模板主人等)传播到另一个数据库.我的理由是,将查询发送到不同的数据库将减轻它们的负担,因为一个数据库= 3个负载源.如果它们都在同一台服务器上,它还会有效吗?

高速缓存

我有一个模板系统,用于构建页面和交换变量.主模板存储在数据库中,每次调用模板时,都会调用缓存副本(html文档).目前,我在这些模板中有两种类型的变量 - 静态变量和动态变量.静态变量通常是页面名称,站点名称 - 不经常更改的东西; 动态变量是每个页面加载时发生变化的事物.

我的问题是:

说我对不同的文章有评论.这是一个更好的解决方案:存储简单的评论模板,并呈现评论(从DB调用)每个页面加载时间或存储评论页面的缓存副本为HTML页面 - 每次添加注释时间/编辑/删除页面被记录下来.

最后

有没有人有任何关于在PHP上运行高负载站点的提示/指针.我很确定这是一种可行的语言 - Facebook和Yahoo! 给它优先考虑 - 但是有什么经验值得我注意吗?



1> Gary Richard..:

没有两个网站是相似的.你真的需要得到像jmeter和基准测试这样的工具来查看你的问题所在.您可以花费大量时间进行猜测和改进,但在衡量和比较更改之前,您不会看到实际结果.

例如,多年来,MySQL查询缓存是解决我们所有性能问题的方法.如果您的网站速度很慢,MySQL专家建议打开查询缓存.事实证明,如果你有很高的写入负载,缓存实际上是瘫痪的.如果你在没有测试的情况下打开它,你就永远不会知道.

不要忘记你从未完成过缩放.处理10req/s的站点将需要更改以支持1000req/s.如果你的运气足够需要支持10,000req/s,你的架构可能看起来也会完全不同.

数据库

不要使用MySQLi - PDO是"现代"的OO数据库访问层.要使用的最重要的功能是查询中的占位符.它足够聪明,可以为您使用服务器端准备和其他优化.

此时您可能不想破坏数据库.如果您确实发现某个数据库未切割,则可以使用多种技术进行扩展,具体取决于您的应用.如果您的读取数多于写入数,则复制到其他服务器通常可以正常工作.分片是一种在多台机器上分割数据的技术.

高速缓存

您可能不希望在数据库中缓存.数据库通常是您的瓶颈,因此添加更多IO通常是一件坏事.有几个PHP缓存可以完成像APC和Zend 这样的类似事情.

通过打开和关闭缓存来测量您的系统.我敢打赌你的缓存比直接提供页面更重.

如果从db构建注释和文章数据需要很长时间,请将memcache集成到系统中.您可以缓存查询结果并将它们存储在memcached实例中.重要的是要记住,从memcache中检索数据必须比从数据库中组装数据要快得多.

如果您的文章不是动态的,或者在生成之后您有简单的动态更改,请考虑将html或php写入磁盘.你可以有一个index.php页面在磁盘上查找文章,如果它在那里,它会将它流式传输到客户端.如果不是,则生成文章,将其写入磁盘并将其发送到客户端.从磁盘删除文件会导致重写页面.如果将注释添加到文章中,请删除缓存的副本 - 它将被重新生成.


@writing到磁盘.您甚至可以放弃index.php并让Apache为您完成工作,这样只有在路径不存在的情况下才会调用index.php.你可以使用mode_rewrite.
-1,PDO明显慢于MySQLi甚至MySQL扩展.
我无法相信这被接受为答案.它不是很好.
PDO比mysqli慢得多,并且不适合我的嵌套查询.Mysqli还支持服务器端准备和绑定参数,就像PDO一样.

2> thesmart..:

我是一个拥有超过1500万用户的网站的首席开发人员.我们的扩展问题非常少,因为我们已经为它做了很早的计划并且经过精心设计.以下是我可以根据自己的经验提出的一些策略.

SCHEMA 首先,对您的模式进行非规范化.这意味着您应该选择拥有一个大表,而不是拥有多个关系表.通常,连接是浪费宝贵的数据库资源,因为进行多次准备和整理会烧毁磁盘I/O. 尽可能避免使用它们.

这里的权衡是您将存储/提取冗余数据,但这是可以接受的,因为数据和笼内带宽非常便宜(更大的磁盘),而多个准备I/O的数量级更高(更多服务器) .

索引 确保您的查询至少使用一个索引.但请注意,如果您经常编写或更新,索引将花费您.有一些实验技巧可以避免这种情况.

您可以尝试添加未编制索引的其他列,这些列与索引的列并行运行.然后,您可以拥有一个脱机进程,将非索引列分批写入索引列.这样,当mySQL需要重新计算索引时,您可以更好地控制.

避免像瘟疫这样的计算查询.如果必须计算查询,请尝试在写入时执行一次.

CACHING 我强烈推荐Memcached.PHP堆栈(Facebook)上最大的玩家已经证明了这一点并且非常灵活.有两种方法可以做到这一点,一种是在数据库层中进行缓存,另一种是在业务逻辑层中进行缓存.

DB层选项需要缓存从DB检索的查询的结果.您可以使用md5()散列SQL查询,并在转到数据库之前将其用作查找键.这样做的好处是它很容易实现.缺点(取决于实现)是您失去了灵活性,因为您在缓存过期方面将所有缓存视为相同.

在我工作的商店中,我们使用业务层缓存,这意味着我们系统中的每个具体类都控制着自己的缓存模式和缓存超时.这对我们来说非常好用,但要注意从DB检索的项目可能与缓存中的项目不同,因此您必须一起更新缓存和DB.

数据保护 复制只能让你到目前为止.比你预期的要早,你的写作将成为瓶颈.要进行补偿,请确保尽早支持数据分片.如果你不这样做,你可能会想要自己拍摄.

实现起来非常简单.基本上,您希望将密钥授权与数据存储分开.使用全局DB存储主键和群集ID之间的映射.您查询此映射以获取群集,然后查询群集以获取数据.你可以缓存这个查找操作的地狱,这将使它成为一个可以忽略不计的操作.

这样做的缺点是可能很难将来自多个分片的数据拼凑在一起.但是,你也可以设计自己的方式.

离线处理 如果用户不必,请不要让用户等待你的后端.构建作业队列并移动可以脱机的任何处理,将其与用户的请求分开.


+1举手,这应该是接受的答案.有趣的是,我读过的关于构建数据库的所有内容总是说"尽可能地规范化所有数据",而没有提到连接的性能损失.我总是直觉地认为连接(特别是多个)增加了很多开销,但直到现在还没有听到任何明确的说法.我希望我能更好地理解你在控制MySQL计算索引时所说的内容,这听起来像是一个非常有趣的黑客.

3> Ryan Doherty..:

我曾经在一些网站上工作过,这些网站每月都有数百万/次点击支持PHP和MySQL.以下是一些基础知识:

    缓存,缓存,缓存.缓存是减少Web服务器和数据库负载的最简单,最有效的方法之一.缓存页面内容,查询,昂贵的计算,I/O绑定的任何内容.Memcache简单而有效.

    一旦最大化,请使用多个服务器.您可以拥有多个Web服务器和多个数据库服务器(具有复制功能).

    减少对Web服务器的整体请求数.这需要使用expires头缓存JS,CSS和图像.您还可以将静态内容移动到CDN,这将加快用户的体验.

    衡量和基准.在生产计算机上运行Nagios并在dev/qa服务器上加载测试.你需要知道什么时候你的服务器会着火,所以你可以防止它.

我建议阅读Building Scalable Websites,它是由Flickr工程师之一编写的,是一个很好的参考.

查看我关于可扩展性的博客文章,它有很多关于使用多种语言和平台进行扩展的演示文稿的链接:http: //www.ryandoherty.net/2008/07/13/unicorns-and-scalability/



4> DavidM..:

Re:PDO/MySQLi/MySQLND

@ gary

你不能只说"不要使用MySQLi",因为他们有不同的目标.PDO几乎就像一个抽象层(虽然它实际上并不是这样),旨在使多个数据库产品易于使用,而MySQLi则专门用于MySQL连接.说PDO是将它与MySQLi进行比较的上下文中的现代访问层是错误的,因为你的语句意味着进展是mysql - > mysqli - > PDO,但事实并非如此.

MySQLi和PDO之间的选择很简单 - 如果您需要支持多个数据库产品,那么您可以使用PDO.如果您只是使用MySQL,那么您可以在PDO和MySQLi之间进行选择.

那你为什么选择MySQLi而不是PDO呢?见下文...

@ross

你对MySQLnd这是最新的MySQL核心语言级库是正确的,但它不是MySQLi的替代品.MySQLi(与PDO一样)仍然是通过PHP代码与MySQL交互的方式.这两个都使用libmysql作为PHP代码背后的C客户端.问题是libmysql不在核心PHP引擎之外,而是mysqlnd的用武之地,即它是一个本机驱动程序,它利用核心PHP内部来最大限度地提高效率,特别是在内存使用方面.

MySQLnd由MySQL自己开发,最近已经进入了用于RC测试的PHP 5.3分支,准备在今年晚些时候发布.然后,您将能够将MySQLnd与MySQLi一起使用......但不能与PDO一起使用.这将使MySQLi 在许多领域(并非所有领域)都有性能提升,并且如果您不需要像PDO这样的抽象功能,它将使其成为MySQL交互的最佳选择.

也就是说,MySQLnd 现在可以在PHP 5.3中用于PDO,因此您可以获得从ND到PDO的性能增强的优势,但是,PDO仍然是一个通用的数据库层,因此不太可能从作为MySQLi的ND的增强功能可以.

虽然它们来自2006年,但可以在这里找到一些有用的基准测试.您还需要了解此选项之类的内容.

在MySQLi和PDO之间进行决策时需要考虑很多因素.事实上,直到你得到高得多的请求数字并不重要,在这种情况下,使用专门为MySQL设计的扩展而不是抽象的东西并且碰巧提供MySQL驱动程序更有意义.

这不是一个简单的问题,因为每个都有优点和缺点.您需要阅读我提供的链接并提出自己的决定,然后进行测试并找出答案.我在过去的项目中使用过PDO,它是一个很好的扩展,但我对纯性能的选择是MySQLi,编译了新的MySQLND选项(当PHP 5.3发布时).


我从PDO切换到mysqli,常规查询开始执行速度快2倍.
@serg:关心发布一些测试以确认这一点?,因为我严重怀疑只需从PDO切换到mysqli会给你这样的速度提升.

5> Paul Kroll..:

一般

在开始看到真实负载之前不要尝试优化.你可能猜对了,但如果你没有,你就浪费了你的时间.

使用jmeter,xdebug或其他工具对网站进行基准测试.

如果加载开始出现问题,则可能涉及对象或数据缓存,因此通常会读取缓存选项(memcached,MySQL缓存选项)

描述您的代码,以便您知道瓶颈在哪里,以及它是在代码还是数据库中

数据库

如果对其他数据库的可移植性不重要,则使用MYSQLi,否则使用PDO

如果基准测试显示数据库是问题,请在开始缓存之前检查查询.使用EXPLAIN查看查询速度减慢的位置.

在优化查询并以某种方式缓存数据库之后,您可能希望使用多个数据库.复制到多个服务器或分片(在多个数据库/服务器上分割数据)可能是合适的,具体取决于数据,查询和读/写行为的类型.

高速缓存

在缓存代码,对象和数据方面已经做了大量的写作.查阅有关APC,Zend Optimizer,memcached,QuickCache,JPCache的文章.在你真正需要之前做一些这样的事情,你将不那么关心从未优化开始.

APC和Zend Optimizer是操作码缓存,它们通过避免重新编译和重新编译代码来加速PHP代码.一般安装简单,值得早做.

Memcached是一个通用缓存,可用于缓存查询,PHP函数或对象或整个页面.代码必须专门编写才能使用它,如果没有中心点来处理缓存对象的创建,更新和删除,则可以使用它.

QuickCache和JPCache是​​文件缓存,否则类似于Memcached.基本概念很简单,但也需要代码,并且更容易使用创建,更新和删除的中心点.

考虑高负载的替代Web服务器.像lighthttp和nginx这样的服务器可以在比Apache更少的内存中处理大量流量,如果你可以牺牲Apache的功能和灵活性(或者如果你不需要那些东西,通常你不需要).

请记住,硬件现在非常便宜,所以一定要花费大量优化大量代码的工作而不是"让我们购买怪物服务器".

考虑在此问题中添加"MySQL"和"缩放"标记



6> tslocum..:

APC是绝对必须的.它不仅适用于一个出色的缓存系统,而且自动缓存的PHP文件的收益也是天赐之物.至于多数据库的想法,我认为你不会在同一台服务器上拥有不同的数据库.它可能会在查询时间内为您带来一些速度提升,但我怀疑为确保它们同步而部署和维护所有三个代码所需的工作量是值得的.

我还强烈建议运行Xdebug以找到程序中的瓶颈.它使我的优化变得轻而易举.



7> Eric Scrivne..:

首先,正如我认为Knuth所说,"过早优化是万恶之源".如果您现在不必处理这些问题,那么请不要专注于首先提供正常工作的东西.话虽如此,如果优化不能等待.

尝试分析您的数据库查询,找出什么是缓慢的,以及发生了什么,并从中提出优化策略.

我会调查Memcached,因为它是许多较高负载站点用于有效缓存所有类型的内容的东西,并且它的PHP对象接口非常好.

在服务器之间拆分数据库并使用某种负载平衡技术(例如,在1和#冗余数据库之间生成具有必要数据的随机数 - 并使用该数字来确定要连接到哪个数据库服务器)也是一种很好的增加方式效率.

对于一些相当高负荷的站点,这些在过去都很好.希望这有助于您入门:-)



8> Bob Somers..:

使用Xdebug(如推荐的tj9991)对您的应用进行概要分析肯定是必须的.盲目地优化事物并没有多大意义.Xdebug将帮助您找到代码中的真正瓶颈,这样您就可以明智地花费优化时间并修复实际导致缓慢下降的代码块.

如果您正在使用Apache,那么可以帮助测试的另一个实用程序是Siege.它可以帮助您预测服务器和应用程序如何通过真正实现其高速负载来应对高负载.

PHP的任何类型的操作码缓存(如APC或许多其他人之一)也会有很多帮助.



9> Vegard Larse..:

我运营的网站每月有7-8百万的页面浏览量.不是很多,但足以让我们的服务器感受到负载.我们选择的解决方案很简单:数据库级别的Memcache.如果数据库负载是您的主要问题,此解决方案很有效.

我们开始使用Memcache来缓存整个对象和最常用的数据库结果.它确实有效,但它也引入了错误(如果我们更加小心的话,我们可能已经避免了一些错误).

所以我们改变了方法.我们构建了一个数据库包装器(使用与旧数据库完全相同的方法,因此很容易切换),然后我们将其子类化以提供memcached数据库访问方法.

现在,您所要做的就是确定查询是否可以使用缓存(可能是过时的)结果.现在,用户运行的大多数查询都是直接从Memcache中获取的.例外是更新和插入,主网站只会因为日志记录而发生.这个相当简单的措施将我们的服务器负载减少了大约80%.



10> 小智..:

对于它的价值,即使没有像memcached这样的扩展/帮助程序包,缓存也是PHP中的DIRT SIMPLE.

您需要做的就是使用创建输出缓冲区ob_start().

创建全局缓存功能.调用ob_start,将函数作为回调传递.在该函数中,查找页面的缓存版本.如果存在,请服务并结束.

如果它不存在,脚本将继续处理.当它到达匹配的ob_end()时,它将调用您指定的函数.那时,您只需获取输出缓冲区的内容,将其放入文件中,保存文件,然后结束.

添加一些到期/垃圾回收.

许多人没有意识到你可以嵌套ob_start()/ ob_end()打电话.因此,如果您已经使用输出缓冲区来解析广告或进行语法突出显示等等,您可以嵌套另一个ob_start/ob_end调用.



11> ceejayoz..:

感谢您对PHP缓存扩展的建议 - 您能解释一个使用另一个的原因吗?我通过IRC听说过有关memcached的好消息,但从未听说过APC - 你对它们的看法是什么?我假设使用多个缓存系统非常有效.

实际上,很多人一起使用APC和memcached ......

推荐阅读
Chloemw
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有