`
freespace
  • 浏览: 175406 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

Drupal优化

阅读更多

 

 

Drupal的内核架构非常简洁并且非常灵活。然而,这种灵活性是有代价的。当启用的模块增加时,处理一个请求的复杂度也会增加。这意味着将耗费更多的服务器资源,必须实现一些策略,在一个站点日渐流行同时,来保证Drupal特有的简明。通过适当的配置,Drupal可以很容易的满足用户的需求。在本章中,我们将讨论性能(performance)和可升级性(scalability)。性能指的是你的站点响应一个请求所用的时间。可升级性指的是你的系统可以同时处理多少个并发请求,通常用“请求数/秒”来度量。

找出瓶颈

如果你的网站运行性能达不到预期,第一步要做的就是分析问题所在。可能的原因包括web服务器,操作系统,数据库,和网络。

初步追踪

了解如何估算一个系统的性能和可升级性,即便是在出现大的问题时,它也能使你保持自信,从而快速的隔离并找到系统的瓶颈。你可以借助于一些简单的工具,通过询问一些问题,来发现瓶颈。这里给出了一种方式,用来分析一个存在严重性能问题的服务器。首先,我们需要知道性能是有哪些因素决定的,CPU,RAM,I/O,或者带宽都是影响性能的因素。那么你需要询问以下问题:

CPU占用率达到最大了吗?检查CPU 的使用情况,在Unix上你可以使用top,在Windows上可以使用任务管理器,如果CPU占用率达到了100%,那么你的任务就是找出是什么程序占用了CPU。查看进程列表,可以让你了解到,是不是web服务器或者数据库占用了处理器的大部分计算资源。这两者都是可以解决的。

服务器的RAM用完了没有?在Unix上你可以使用top,在Windows上可以使用任务管理器,,来方便的检查这一点。如果服务器还有大量的空闲内存,那么继续下一个问题。如果服务器用完了内存,你必须找出原因。

磁盘空间不足了吗?检查磁盘子系统,在Unix使用工具vmstat,在Windows 下使用性能监测器,如果可用磁盘不能满足需求,同时又有大量空闲内存剩余,那么这就是一个I/O问题。可能的原因包括,记录了大量的冗余日志,对数据库不恰当的配置使得在磁盘上创建了许多临时表,后台脚本的执行,对于一个需要大量写操作的系统使用了一个不恰当的RAID级别,等等。

网络带宽用完了吗?如果网络带宽用完了,那么只有两种解决方案。一个是增加带宽。另一个是对发送的信息进行恰当的压缩,从而发送更少的信息。

Web服务器用完了CPU

如果你的CPU占用率达到了100%,而根据进程列表显示,是web服务器消耗了大量的资源而不是数据库(后面介绍),那么你应该去减少web服务器处理一个请求所耗费的资源。通常PHP代码的执行就是罪魁祸首。

PHP最优化措施

PHP最优化措施

在Drupal中,由于PHP代码执行在处理一个请求中占了一大块,所以我们需要知道采取哪些措施才能加快这一进程,这一点非常重要。对编译后的PHP操作代码(opcodes)进行缓存,和剖析应用层来找出低效算法,能够带来重要的性能提升。

缓存操作代码

有两种方式可以减少执行PHP代码所耗费的资源。很明显,一种是减少代码总量,可以通过禁用不必要的Drupal模块和编写高效的代码来达到这一点。另一种方式就是使用一个opcode缓存。PHP对于每个请求,都会将所有代码解析并编译成一种中间形态,在这种形态里包含了一系列的操作代码。添加一个 opcode缓存可以让PHP能够重用前面编译过的代码,这样就会跳过解析和编译。常见的opcode缓存有Alternative PHP Cache (http://pecl.php.net/package/APC), eAccelerator (http://eaccelerator.net), XCache (http://trac.lighttpd.net/xcache/), 和 Zend Platform (http://zend.com)。Zend是一个商业产品,而其它几个则是免费的。

由于Drupal是一个需要大量数据库操作的程序,所以一个opcode缓存不能作为一个单独的解决方案,但它一个整体方案中的一部份。只需要最小的努力,他人仍然可以代码明显的性能提升。


图22-1 Alternative PHP Cache (APC)带有一个接口,它能够展示内存分配情况和当前缓存中的文件。

剖析应用

通常定制的代码和模块对于小规模的站点能够很好的工作,如果将它放到大一点的站点上那么就可能成为站点的瓶颈。耗费CPU的代码循环,占用内存的算法,还有大量的数据库读取,这些都可以通过剖析你的代码来判定PHP在哪里花费了大量时间,因此,找到的关键点也就是你需要花费功夫进行调试的地方。更多关于PHP调试器和profiler的信息,参看第21章。

有时候,即便是添加了opcode并且进行了代码优化以后,你的web服务器仍然不能处理这么大的负载,那么现在你就应该换一个更强大的服务器,比如带有更多CPU或者更快的CPU,或者更换应用架构,采用多个web服务器。

Web服务器用完了RAM

Web服务器进程处理一个请求时,用到RAM的地方包括,web服务器加载所有的模块(比如Apache的mime_module, rewrite_module,等等),还有PHP解释器使用的内存。启用的web服务器和Drupal模块越多,处理单个请求耗费的RAM就越多。

因为RAM是个有限的资源,你应该决定对于每个请求分配多少内存,还有你的web服务器能够同时处理多少个请求。为了知道平均为每个请求使用多少内存,可使用一个像Unix中top一样的程序来查看你的进程列表。在Apache中,可以使用指令MaxClients来设置能够处理的最大并发请求数。一个常见的错误认为,解决满负荷的web服务器的方案是增加MaxClients的值。这只会让问题变得更加复杂,因为你将同时收到太多的请求。这意味着RAM 将被耗尽,而你的服务器将开始进行磁盘交换并开始不能响应请求。让我们假定,你的web服务器拥有2GB的内存,而每个Apache请求大约使用 20MB(对于Unix,你可以使用top来检查实际值;对于windows,则可以使用任务管理器)。通过下面的公式,你可以为MaxClients计算出一个合适的值;你要记住你需要为你的操作系统和其它进程预留一定的内存:

2GB RAM / 20MB per process = 100 MaxClients

如果禁用了不需要的web服务器模块,并且优化了定制的模块或者代码以后,你的服务器仍然耗尽内存,那么接下来你要做的是,确保数据库和操作系统不是产生瓶颈的原因。如果是由它们引起的,那么就添加更多的内存。如果不是,那么问题就很简单了,你收到的请求比你能够处理的请求要多;解决方案就是添加更多的 web服务器。

提示 由于Apache进程用到的内存,随着它的子进程增多,有逐步增加的趋势,通过将MaxRequestsPerChild的值设得小一点比如300(实际的值依赖于你所处的环境)可以收回不少的内存。Apache将会更努力的工作来生成新的子进程,而新的子进程比替换掉的子进程所需的内存要少一些,这样你就可以使用较少的内存来处理更多的请求了。MaxRequestsPerChild的默认值为0,这意味着进程永不过期。

其它web服务器最优化

为了让你的web服务器更有效的运行,这里有一些其它的措施。

Apache最优化

Apache是Drupal最常用的web服务器,通过对它进行调整可以获得更高的性能。下面的部分将给出一些可以一试的方式,供大家参考。

mod_expires

这个Apache模块将让Drupal发出ExpiresHTTP头部,在用户的浏览器中对静态文件缓存两周,或者直到一个文件存在新的版本为止。这适用于所有的图片,CSS和JavaScript文件,和其它静态文件。最终的结果是减少了带宽,而服务器需要发送的信息将会更少一些。Drupal为了使用mod_expires,对其进行了预先配置,一旦mod_expires可用,Drupal就会使用它。mod_expires的设置可以在Drupal的.htaccess文件中找到。


1 # Requires mod_expires to be enabled.
2 <IfModule mod_expires.c>
3 # Enable expirations.
4 ExpiresActive On
5 # Cache all files for 2 weeks after access (A).
6 ExpiresDefault A555-5555
7 # Do not cache dynamically generated pages.
8 ExpiresByType text/html A1
9 </IfModule>

我们不能让mod_expires缓存HTML内容,这是由于Drupal生成的HTML内容不全静态的。这也是Drupal拥有自己的内部缓存系统的原因,内置缓存系统可对它的HTML输出进行缓存(比如,页面缓存)。

将.htaccess文件中的指令迁移到httpd.conf

Drupal带有两个.htaccess文件:一个位于Drupal根路径,而另一个将被自动创建,在你创建了用于存储上传文件的目录以后,访问Administer ➤ File system来设置目录的位置,此时系统将为你自动创建一个.htaccess文件。在处理每个请求时,所有的.htaccess文件都将被搜索,读取,和解析。相反,httpd.conf只在Apache启动时才被读取。Apache指令可以放在这两种文件中。如果你能够控制你自己的服务器,你应该将.htaccess文件中的内容转移到Apache主配置文件(httpd.conf)中,并通过将AllowOverride设置为None来禁用在你的web服务器根路径下查找.htaccess文件:


1 <Directory />
2 AllowOverride None
3 ...
4 </Directory>

对于每个请求,这将阻止Apache通过遍历目录树来查找要执行的.htaccess文件。这样对于每个请求,Apache要做的工作就会有所减少,这样它就能够处理更多请求了。

其它的Web服务器

还有另外一种选项,那就是使用其它服务器来代替Apache。Benchmarks已经说明了这一点,例如,一般情况下,LightTPD web服务器每秒能够为Drupal处理更多的请求。更多详细比较,参看http://buytaert.net/drupal-webserver-configurations-compared。

数据库瓶颈

Drupal需要进行大量的数据库操作,特别是对于登录的用户和定制的模块。数据库常常会成为产生瓶颈的原因。这里有一些基本的策略用于优化Drupal中数据库的使用。

启用MySQL的查询语句缓存
MySQL 是Drupal最常用的数据库。它具有在内存中缓存常用查询语句的能力,这样一个给定的查询语句再次被调用时,MySQL将立即从缓存中将其返回。然而,在大多数MySQL中,这一特性默认是被禁用的。为了启用它,向你的MySQL配置选项文件添加以下代码;该配置文件的名称为my.cnf,它用来声明变量和你的MySQL服务器的行为(参看http://dev.mysql.com/doc/refman/5.1/en/option- files.html)。在这里,我们将查询语句缓存设为64MB:


# The MySQL server
[mysqld]
query_cache_size=64M

当前查询语句缓存的大小,可以通过MySQL的SHOW VARIABLES命令来查看:


mysql>SHOW VARIABLES;
...
| query_cache_size |555-55554
| query_cache_type | ON
...

不断的试验查询语句缓存的大小通常是有用的。缓存太小就意味着缓存了的查询语句很快就会过期。缓存太大就意味着搜索一个缓存可能需要花费相对较长的时间;还有就是使用内存进行缓存比使用其它一些方式要好,就像有更多的web服务器处理,memcache或者操作系统的文件缓存一样。

提示 在Drupal中,访问“管理➤报告➤状态报告”,点击MySQL版本号,来快速的查看一些重要的MySQL变量值。你还可以在这一页面查看,查询语句缓存是否被启用了。

识别耗费资源的查询

如果你想了解在生成一个给定页面时都发生了什么,那么devel.module就会非常有用。它拥有一个选项,用来显示生成页面所用到的所有查询语句,以及每个查询所用的时间。关于如何使用devel.module,以及通过EXPLAIN语法来识别和优化数据库查询的更详细的讨论,参看第21章。

找出执行时间过长的查询的另一种方式是,在MySQL中启用缓慢查询日志。为了启用它,需要在MySQL的配置选项文件(my.cnf)中这样设置:


# The MySQL server
[mysqld]
log-slow-queries

这会将超过10秒的查询记录到MySQL数据目录中的日志文件example.com-slow.log中去。你可以修改秒数以及日志的位置,如下面的代码所示,这里我们将缓慢查询的最小值设为5秒:


# The MySQL server
[mysqld]
long_query_time = 5
log-slow-queries = /var/log/mysql/example-slow.log

识别耗费资源的页面

识别耗费资源的页面
为了找出哪些页面是最耗费资源的,需要启用Drupal自带的统计模块。尽管统计模块增加了你的服务器的负担(由于它将你的站点的访问统计记录到了数据库中),但它能够帮助我们找出哪些页面的访问量最大,对于这些页面我们要进行更多的优化。它也可以用来追踪一个时期内生成页面的总时间,你可以在“管理➤报告➤访问日志设置”中进行声明。这可以用于识别耗费系统资源不能控制的网络爬虫,通过访问“管理➤报告➤浏览者排行”并点击 “禁止”来禁止该网络爬虫的访问。你还需要小心一点----有时候会很容易的禁用掉一个好的网络爬虫,就是能够给你的站点带来访问量的爬虫。在禁止网络爬虫以前,你一定要先检查一下它的出处。

识别耗费资源的代码
看一下下面耗费资源的代码:


01 // Very expensive, silly way to get node titles. First we get the node IDs
02 // of all published nodes.
03 $sql = "SELECT n.nid FROM {node} n WHERE n.status = 1";
04
05 // We wrap our node query in db_rewrite_sql() so that node access is respected.
06 $result = db_rewrite_sql(db_query($sql));
07
08 // Now we do a node_load() on each individual node.
09 while ($data = db_fetch_object($result)) {
10 $node = node_load($data->nid);
11 // And save the titles.
12 $titles[$node->nid] = check_plain($node->title);
13 }

完全加载一个节点是一个耗费资源的操作:运行钩子函数,通过模块处理数据库查询来添加或者修改节点,使用内存来在node_load()内部中缓存节点。如果你不依赖于其它模块对节点的修改,直接对节点表进行你自己的查询,速度将会更快一些。当然这仅仅是一个例子,但是常常会遇到同样的情景,也就是,许多时候数据是通过多个查询来取回的,而实际上可以将多个查询合并成一个简单的查询,或者不需要加载整个节点,就可以完成所要的操作。

提示 Drupal拥有一个内部的缓存机制(使用了一个静态变量),当在一个请求中多次加载同一节点时就会使用这一机制。例如,如果调用了node_load(1)。节点1将被完全加载并被缓存。当在同一个web请求中再次调用node_load(1)时,Drupal将会返回前面使用相同节点ID加载节点的缓存结果。

优化表结构

优化表结构
另外,SQL的缓慢可能是由于,第3方模块中SQL表的不良实现引起的。例如,列没有索引的话就会引起查询缓慢。一个快速查看MySQL如何执行查询的方式是,从你的缓慢查询日志中取出一个查询,在其前面加上单词EXPLAIN,然后将这个查询发给MySQL。那么结果就是得到了一个显示使用了哪些索引的表。更多信息可参看MySQL的相关书籍。

手工缓存查询语句
如果你必须要进行一些非常昂贵的查询,那么你可以在你的模块中手工的将结果缓存起来。关于Drupal缓存API的更多详细信息,参看第15章。

将表类型从MyISAM改为InnoDB
MySQL有两种常见的存储引擎,通常也称为表类型,它们是MyISAM 和InnoDB。Drupal默认使用的是MyISAM。
MyISAM 使用表级别的锁机制,而InnoDB使用行级别的锁机制。锁对于数据库的完整性非常重要;它可以避免两个数据库进程同时对同一数据进行更新操作。在实际中,锁机制策略的不同意味着当你对MyISAM表进行写操作时,整个表将被锁住。因此,在一个繁忙的Drupal站点上,当正在添加多个评论时,在插入一个新评论的同时所有的评论都不能被读取。而在InnoDB上,这就不是一个问题,因为只有正被插入的那一行被锁住了,从而允许其它的服务器线程对其它各行继续进行操作。然而,在MyISAM中,表的读取更快,而数据维护和恢复工具更加完善。MySQL表的存储架构的更多信息,参看http://dev.mysql.com/tech-resources/articles/storage-engine/part_1.html或者http://dev.mysql.com/doc/refman/5.1/en/storage-engines.html。
为了测试表级锁是不是引起性能缓慢的原因,你可以通过在MySQL中检查状态变量Table_locks_immediate和Table_locks_waited的值来分析锁的竞争程度。

mysql> SHOW STATUS LIKE 'Table%';

+-----------------------+---------+
| Variable_name         | Value     |
+-----------------------+---------+
| Table_locks_immediate |555-5555  |
| Table_locks_waited    | 15324     |
+-----------------------+---------+

Table_locks_immediate 指的是能够立即获得表级锁的次数,而Table_locks_waited指的是不能立即获取表级锁而需要等待的次数。如果 Table_locks_waited的值比较大的话,并且你遇到了性能问题,你可能希望将大表切分成小表;例如,你可以为一个定制模块创建一个专有的缓存(cache)表,或者通过其它方式来减小表的大小,或者降低表级锁命令调用的频率。对于一些表,比如cache_*,Watchdog, 和 accesslog表,减少表的大小的一种方式是减少数据的生命周期。使用Drupal的后台管理接口可以设置数据的生命周期。还有,确保每小时能够运行一次cron,从而能够不断的清理这些表中的过期数据。

因为Drupal可以运行在不同的应用下,所以不可能一刀切的具体到某个表就应该使用某个表引擎。然而,一般情况下,适合转变为InnoDB的表有cache, watchdog, sessions, 和 accesslog 表。幸运的是,转变到InnoDB上非常简单:

ALTER TABLE accesslog TYPE='InnoDB';

当然,这一转变应该在站点下线并且已经为你的数据做好备份时进行,而且你也应该首先了解InnoDB表的不同特性。

注意 尽管数据库API提供了db_lock_table() 和db_unlock_tables()函数供第3方模块使用,但是Drupal6中,核心代码并没有使用LOCK TABLES命令。

关于MySQL的性能调优,参看http://www.day32.com/MySQL/的性能调优脚本,这里提供了调整MySQL服务器变量的建议。

Memcached(内存缓存)

当数据必须使用缓慢的设备比如一个硬盘进行交互时,系统通常会遇到一个性能问题。如果你能够为数据绕过这一操作,而且你能够承受得起数据的丢失(比如session数据),那会怎么样呢?此时我们可以使用memcached,这个系统将读写操作都放到内存中进行。与本章中介绍了其它解决方案相比,Memcached更加复杂,而且更难设定。,但是当你的系统需要在可升级性方面有所提高时还是值得考虑这一方案的。

Drupal 有一个内置的数据库缓存,用来缓存页面,菜单,和其它Drupal数据,而MySQL数据库也能够缓存常用查询,但是当你的数据库不堪重负时那会怎样?你可以再买一台数据库服务器,或者你也可以直接将数据存放在内存中而不是存在数据库中,从而完全减轻数据库的重负。Memcached库(see http://www.danga.com/memcached/)和PECL Memcache PHP 扩展 (seehttp://pecl.php.net/package/memcache)都是专门为你实现这一点的工具。

Memcached 系统将任意数据都保存在随机存取的内存中,而且能够迅速的从中读取数据。使用这种方式比任何使用磁盘的方式在性能上都要好一些。Memcached存储对象并使用唯一的键来引用对象。哪些对象应该被放到memcached中,这由程序员决定。对放到Memcached中的对象,Memcached不知对象的类型和本质;在它眼中,一切都是一堆等待取回的带有键的比特数据。

系统的简单性是它的优点。当为Drupal编写支持memcached的代码时,开发者可以决定对引起瓶颈的主要因素进行缓存。这可能是,频繁出现的数据库查询的查询结果,比如路径查找,或者是更复杂的构造比如完整加载的节点和分类词汇,这些都需要许多数据库查询和大量的PHP处理才能得到。

Drupal的memcache模块和使用PECL Memcache接口的Drupal专有API可在Drupal的Memcache项目中找到(参看http://drupal.org/project/memcache)。

特定于Drupal的最优化

大多数针对Drupal的最优化措施,都在软件堆栈的其它层次中进行,也有一些专门针对Drupal本身的最优化措施,这也能使性能得到极大提升。

页面缓存
有时,一些简单的事情会被忽略掉,这也是为什么需要再次提到它们的原因。Drupal 拥有各种内置的方式,它能够通过为匿名用户存储和发送压缩了的缓存页面,来减少数据库的负重。通过启用这一缓存,你可以使用一个单独的数据库查询来高效的读取页面,而不是使用许多查询来获取页面(在没有缓存可用时就使用这种方式)。Drupal的缓存默认是禁用的,它可以在“管理➤站点配置➤性能”中配置。更多信息参看第15章。

带宽最优化
这是“管理➤站点配置➤性能”页面中的另一个性能优化措施,它能够减少发送给服务器的请求次数。通过启用 “优化CSS 文件”特性,Drupal将处理由modules创建的CSS文件,压缩它们,并将它们合并成一个文件,放到你的“文件系统路径”下的css目录中。而 “优化JavaScript文件”特性可以将多个JavaScript文件合并成一个,放到你的“文件系统路径”下的js目录中。这将减少每个页面的 HTTP请求数量,以及下载页面的整体大小。
当将一个页面存储在页面缓存中时,Drupal将会检查是否启用了页面压缩。这个特性默认是启用的,你可以在“管理➤站点配置➤性能”将其禁用。如果启用了的话,在页面存储到缓存中以前,Drupal将会检查PHP的zlib扩展(如果存在的话),并使用 gzencode($data, 9, FORCE_GZIP)对页面进行压缩。当页面从数据库中取出时,Drupal判定当前浏览器是否支持gzip编码,如果支持的话,它就简单的将缓存数据返回。否则,缓存数据在返回以前,将会使用gzinflate()进行解压处理。详情请参看includes/bootstrap.inc中的 drupal_page_cache_header()。

调优Sessions表
Drupal 将用户会话保存到了它的数据库中,而不是文件中(参看第16章)。这意味着Drupal能够很容易的应用到多个服务器上,但是由于要管理每个用户的会话信息这也增加了数据库的负担。如果一个站点每天有成千上万的用户访问,那么很容得就会看到这个表将会极速膨胀。
你可以通过PHP来控制多长时间清除一次旧的会话记录。Drupal将这一配置放到了它的settings.php文件中:


ini_set('session.gc_maxlifetime', 200000); // 55 hours (in seconds)

垃圾收集系统运行周期,默认设置为两天多点时间。这意味着如果用户两天内没有登录,那么它的会话将被删除。如果你的sessions表不断疯长,那么你需要提高PHP的会话垃圾收集系统的运行频率。


ini_set('session.gc_maxlifetime', 86400); // 24 hours (in seconds)
ini_set('session.cache_expire', 1440); // 24 hours (in minutes)

当调整session.gc_maxlifetime时,最好也将session.cache_expire设为相同的值,session.cache_expire用来控制缓存中会话页面的存活周期。注意session.cache_expire值的单位为分钟。

管理已验证用户的访问

管理已验证用户的访问
由于Drupal可以为匿名用户提供缓存了的页面,而匿名用户一般也不需要与Drupal进行交互,你可能想要减少用户登录停留的时间,或者更疯狂一点,一旦用户关闭他们的浏览器就使他们退出。通过调整settings.php文件中的cookie生存周期来做到这一点。在下面这行代码中,我们将它的值改为24小时:

ini_set('session.cookie_lifetime', 86400); // 24 hours (in seconds)

而在这里一旦用户关闭浏览我们就将他们登出:

ini_set('session.cookie_lifetime', 0); // When they close the browser.

settings.php中的默认值(2,000,000秒)能够允许用户保持登录大约3周的时间(在此期间会话垃圾收集系统不会将他们的会话记录从sessions表中删除)。

清除错误报告日志
Drupal为模块开发者提供了watchdog()函数,使用它可以将信息写入到日志中。Drupal内置了两种方式,一种是记录到数据库中,另一种是记录到syslog中。

严重性级别
调用watchdog()时,PHP代码所使用的严重性级别符合RFC 3164,如表22-1所示。

表 22-1. Drupal看门狗系统的常量和严重性级别

Drupal 常量     整数     严重性级别
WATCHDOG_EMERG     0    紧急: 系统不可用
WATCHDOG_ALERT     1    警报: 需立即采取行动
WATCHDOG_CRITICAL  2    关键: 关键条件
WATCHDOG_ERROR     3    错误:错误条件
WATCHDOG_WARNING   4    警告: 警告条件
WATCHDOG_NOTICE    5    通知: 一般的,但是重要的消息
WATCHDOG_INFO      6    信息: 一般消息
WATCHDOG_DEBUG     7    调试: 调试级别消息

记录到数据库中
Drupal内置的数据库日志模块默认是启用的,可以在“管理➤报告➤最近的日志条目”查看日志条目。数据库中的watchdog表,用来存储日志信息,如果不对其进行定期地清理的话,那么它就会快速的膨胀。如果你发现watchdog表的大小导致了你的站点运行缓慢,你可以通过在“管理➤站点配置➤日志与报警 ➤数据库日志”里来调整相关配置以减小它的大小。注意,对该设置的修改将在cron下次运行时生效。不能定期的运行cron会使得watchdog表越来越大,从而为系统增加极大的负担。

记录到Syslog
Drupal核心自带的syslog模块,默认是禁用的,它使用PHP的syslog()函数将watchdog()的调用写入到操作系统中。这一方式就绕开了数据库日志模块所需要的数据库插入操作。

运行cron

运行cron

尽管设定cron是Drupal安装指令的第5步,但是它常被忽视,而这一忽视能够给站点带来不小的麻烦。如果在一Drupal 站点上没有运行cron,那么数据库就会充满日志信息、过期的缓存数据、以及其它的统计数据,这些都是应该从系统中定期清除的。我们应该把它作为正常安装流程中的一部份,及早的配置cron,这是一个很好的实践经验。关于设定cron的更多信息,参看Drupal的INSTALL.txt文件中的步骤5。

提示 如果你处于一个非常特殊的环境下,在一个访问量很大的站点上cron却永远没有运行过或者它没有被充分的运行,你可以手工的进行一些属于cron管理的操作。你可以随时清空缓存表(TRUNCATE TABLE 'cache', TRUNCATE TABLE 'cache_filter', and TRUNCATE TABLE 'cache_page'),而它将会重新构造自己。还有,在情急之时,你可以清空watchdog和sessions表来重新控制一个失控的Drupal站点。删除watchdog记录意味着你将丢失所有的错误消息,它们可能指示站点的问题所在。如果你想保存这些数据,那么在清空表watchdog以前,先对它进行备份。清空sessions表会使当前已登录的用户退出系统。

自动节流

Drupal在核心中包含了一个名为 throttle.module的模块。这一模块通过对当前在线用户数量进行采样来测量站点的负载,如果采样显示超过了管理员设置的极值,那么它将关闭一些功能。在你配置一个站点时,最好启用这一模块,这样当一个页面成为热门话题并带来极大的访问量时,它使你能够应付这种局面。然而,节流阀模块不是一个万能药。为了进行节流,该模块本身会带来不小的负担。你也应该考虑一下其它的解决方案,比如使用memcached。

启用节流阀模块

当你启用了节流阀模块,你将会注意到在模块管理页面多了一列复选框。也就是,除了选择是否启用一个模块以外,你还可以选择它能否被节流。被节流意味着当module_list()返回了一列启用的模块时,由于访问量过大,启用了节流阀的模块将不被包含在内;被节流的模块此时将被禁用。

很明显,你将需要小心的选择你想对哪些模块进行节流。一般选择功能不重要但是耗费CPU时间或者许多数据库查询的模块。核心模块不能被节流(因为它们是Drupal正常运行所必需的),但是它们能在站点处于节流时,够意识到节流并使用它们自己的措施用来降低处理时间。例如,区块模块不能被节流,但是独立的区块可以被节流,如图22-2所示。


图22-2 当站点处于大的负载时,它将不展示头部的搜索表单和右边栏中的“Who’s new” 和 “Who’s online”区块,但是左边栏的导航和用户登录区块以及页脚的“Powered by Drupal”区块总是被显示的。

配置节流阀模块

为了使节流机制能够起作用,你必须为其提供一个阀值和一个采样频率。当启用了节流阀模块时,阀值可以在“管理➤站点配置➤节流阀”中设置。

设置阀值

可以输入两个阀值:节流开始所需要的最小匿名用户数和节流开始所需要的最小登录用户数。由于匿名用户占用的资源比验证用户小,所以匿名用户的阀值应该更高一些。实际值则依赖于你的个人站点。用户数必须是在一个给定的时间内测量的。这个时间周期在“Who’s online”区块中设置,并作为Drupal变量user_block_seconds_online存储起来。如果它没有被设置,那它默认为900秒(15分钟),如图22-3所示。


图 22-3.用户最后一次访问以后仍被作为“在线”的时间周期,可以在“Who’s online”区块设置的User activity字段中进行设置。

设置采样频率

为了判定站点的负载量,以决定是打开还是关闭节流机制,节流阀模块必须查询数据库。这为数据库服务器增加了额外的负担。使用“Auto-throttle probability limiter”来设置检查的频率(实际中有可能检查发生在一个给定请求上)。例如,选择20%,那么对于每5个请求就会采样一次。

使得模块和主题懂得节流(Throttle-Aware)

节流机制可能开着,也可能关着。当你编写自己的模块和主题时,你可以对节流阀的状态进行判断,例如:


1 // Get throttle status.
2 // We use module_invoke() instead of calling throttle_status() directly
3 // so this will still work when throttle.module is disabled.
4 $throttle = module_invoke('throttle', 'status');
5
6 if (!$throttle) {
7 // Throttle is off.
8 // Do nonessential CPU-intensive task here.
9 }

提示 如果你拥有大量的多媒体文件,这些文件不重要,但又是主题的一部分,需要提供给用户,当你的网站不堪重负时,你可以对这些文件进行节流来减少带宽的总量。

架构

Drupal可用的架构就是那些其它的LAM堆栈软件,以及使得Drupal具有可升级性的技术。因此,我们将为你讲述不同的架构,并主要针对Drupal来讨论相关的技巧。

单个服务器

这是最简单的架构。Web服务器和数据库运行在同一个服务器上。服务器可能是一个共享主机或者一个专用主机。尽管大多数Drupal站点能够在共享主机上很好的运转,如果期望具有一定的升级性的话,就应该把它放到专有主机上。

在单主机架构下,配置非常简单,因为所有的东西都已设置好了。同样的,web服务器和数据库之间的通信非常快,这是由于不需要使用网络来传播数据,所以避免了由此带来的时间延迟。很明显,如果能够使用多核处理器那就更好了,这样web服务器和数据库之间就不需要争抢处理器了。

独立的数据库服务器

如果数据库是你的瓶颈,那么你可能就需要一个单独的强大的数据库服务器了。由于需要使用网络来发送请求,所以会影响性能,但是可升级性将会提高。

注意 无论什么时候你在使用多个服务器,你都需要确保使用一个快速的本地网络将它们连接起来。

独立的数据库服务器和web服务器集群

独立的数据库服务器和web服务器集群
多个web服务器具有更好的容错性,并能处理更多的访问。集群所需的最小计算机数量是2个web服务器。还有,你需要有一种方式能够用来在服务器之间切换流量。而当其中的一个机器不能工作时,集群中其余的机器能够处理整个负载。

负载均衡

负载均衡器能够将web请求分配到多个web服务器上。还有一些其它类型的负载均衡器用来分发其它的资源,比如硬盘和数据库,但在这里,我们仅仅讨论对HTTP请求的分发。在多个web服务器的情况下,当一个web服务器当机或者处于维护状态时,负载均衡器允许web服务继续运行。

负载均衡器可分为两大类。软件负载均衡器非常便宜甚至免费,但是它的维护和管理费用高于硬件负载均衡器。Linux Virtual Server (http://www.linuxvirtualserver.org/)是一个非常流行的Linux负载均衡器。硬件负载均衡器一般很昂贵,因为与基于软件的解决方案相比,它们包含了更高级的服务器切换算法并具有更好的可靠性。

除了负载均衡,多个服务器还带来了一些其它问题,主要包括文件上传和保持代码在服务器间的同步。

文件上传和同步

文件上传和同步
当Drupal运行在单个web服务器上时,上传的文件一般存储在Drupal的files(文件)目录中。它的位置可在“管理➤站点配置➤文件系统”里配置。对于多个web服务器,则需要避免下面的场景:

1. 一个用户在web服务器A上,上传了一个文件;数据库被更新以反映这一情况。
2. 一个用户在web服务器B上查看一个页面时,引用了这个新文件。文件未找到!

很明显,答案就是将文件也同步到web服务器B上。有多种方式。

使用rsync

Rsync程序是一个解决方案,它通过仅仅复制修改了的文件来保持两个目录间的同步。更多信息,参看http://samba.anu.edu.au/rsync/。这种方式的不足之处是,同步会带来延迟,还有所有上传了的文件都有多个副本(因此增加了存储成本)。

提示 如果你有很多文件并定期的调度rsyncs,通过检查表file和upload,当文件未被修改时,不同步;文件被修改时,同步。

使用一个共享的固定的文件系统

与其在多个服务器间同步文件系统,你不如部署一个共享的固定的文件系统,它将文件存放在文件服务器上的一个单独的位置中。接着,web 服务器可以使用一个协议比如网络文件系统(NFS)来安放文件。这种方式的优点有,能够很容易的添加廉价的web服务器,而资源将被集中存放在一个耐用的文件服务器上,它上面可以带有冗余存储系统比如RAID 5。这个系统的主要缺点是,仅有一个失败点;如果你的服务器或者文件系统出了问题,那么就会影响整个站点,除非你创建一个文件服务器集群。

如果需要提供大量的多媒体文件,最好将这些文件存放在一个单独的服务器上,可以使用一个轻量级的服务器比如Lighttpd,从而减轻你的web服务器的负担,使得Drupal能够处理更多的请求。做到这一点的一个简单的方式是,在你的web服务器上使用一个重写(rewrite)规则,将到来的针对特定文件类型的所有请求重定向到静态服务器上。下面是Apache的重写(rewrite)规则的一个例子,它重写了所有针对JPEG文件的请求:


RewriteCond %{REQUEST_URI} ^/(.*\.jpg)$ [NC]
RewriteRule .* http://static.example.com/%1 [R]

这种方式的不足是,web服务器仍然需要处理额外的工作——将请求重定向到文件服务器上。一个改进的方案是,在Drupal内部重写所有文件的URLs,这样web服务器就不再参与静态文件请求了。然而,现在,在Drupal内核里还没有一个简单的方式来进行修改。

超越单个文件系统

如果存储总量不断增长,以至于超过了单个文件系统能够承受的范围,你可以通过编写定制的代码来实现一个存储抽象层,从而满足需求。另一种选择是使用一个外部的存储系统比如Amazon的S3服务。

多个数据库服务器

多个数据库服务器带来了额外的复杂性,因为数据将被重复插入和更新,或者数据库被分割到多个服务器中。

数据库复制

MySQL中的数据库复制,一个单独的主数据库接收所有的写操作,然后这些写操作将被复制到一个或多个从数据库上。读操作可以在任何主数据库或者从数据库上进行。在一个多层架构中,从数据库也可以是主数据库。

当前,在一个能够复制的数据库环境下运行Drupal的一个难点是,Drupal不能区分读和写操作。然而,由于所有的数据库查询都要通过数据库层,通过扫描查询中的关键字ALTER, CREATE, DELETE, FLUSH, INSERT, LOCK, UPDATE,等等,也不难做到这一点,从而将查询分发给合适的数据库。通过在http://drupal.org搜索“replication”可以找到这种方式的一些例子,另外还有一篇博客也值得一读http://buytaert.net/database-replication-lag。

数据库分割

由于Drupal可以处理多个数据库链接,为了增加你的数据库架构的可升级性,另一种策略是将一些表放在一个机子上的一个数据库中,将另一些表放到另一个机子上的不同数据库中。例如,将所有的cache表分离到一个独立的机子上的独立的数据库中,对于所有使用这些表的查询,使用Drupal的表前缀机制来对查询应用别名,从而提高你站点的可升级性。

总结

在本章,你学到以下几点:

  • 如何发现性能瓶颈
  • 如何优化一个web服务器
  • 如何优化一个数据库
分享到:
评论

相关推荐

    php资料库4 防止foeach中变量不是数组

    Drupal专业开发指南 第22章 Drupal优化(1) - g089h515r806的专栏 - CSDNBlog.mht 由Table_locks_waited想到的mysql 表锁问题_含笑的波浪在逐浪.mht MySQL优化经验 key_buffer_size,query_cache_size,table_cache....

    docker4drupal:基于Docker的Drupal堆栈

    Docker4Drupal是针对Drupal优化的一组Docker映像。 使用docker-compose.yml文件在Linux,Mac OS X和Windows上启动本地环境。 阅读有关的文档 在提问 关注以获取将来的公告 叠放 Drupal堆栈由以下容器组成: 容器 ...

    Drupal v7.9 多国语言版.zip

    更加扩展:感谢对JavaScript和CSS的优化、更好的缓存机制以及其他很多改进,你的Drupal 7站点会很快很可靠,并且可以处理高流量的访问。 开源:我们为了软件而来,最终留在了社区里。成千上万的聪明而高效的朋友们...

    Drupal v7.52

    更加扩展:感谢对JavaScript和CSS的优化、更好的缓存机制以及其他很多改进,你的Drupal 7站点会很快很可靠,并且可以处理高流量的访问。开源:我们为了软件而来,最终留在了社区里。成千上万的聪明而高效的朋友们在...

    Drupal专业开发指南(中文版)99.9%完整

    补完的这几章还算比较重要的,例如表单API,搜索,安全,优化等等。有兴趣的同学可以看看目录,然后查找自己不了解的地方。 如果有bug,可以给我发邮件hezll@msn.com谢谢大家支持,请注意并没有获得原作者授权,仅...

    Drupal Search Engine Optimization

    Drupal Search Engine Optimization ,drupal开发的搜索引擎优化

    jix-core

    Docker4Drupal是针对Drupal优化的一组docker映像。 使用docker-compose.yml文件在Linux,Mac OS X和Windows上启动本地环境。 阅读有关的文档 在提问 关注以获取将来的公告 堆 Drupal堆栈由以下容器组成: 容器 ...

    drupal-fleet-yard:使用 Ansible 调配 Drupal 调优环境

    Drupal 船坞 用于构建从改编而来的 Drupal 优化系统的构建环境。要求&gt;= 4.3.x &gt;= 1.6.x默认剧本ubuntu1404 php5-fpm 5.5.23 nginx/1.4.6 mysql

    Drupal 6 Search Engine Optimization

    关于drupal6 搜索优化技术的一本书

    Drupal v7.4 PHP内容管理框架.gz

    感谢对JavaScript和CSS的优化、更好的缓存机制以及其他很多改进,你的Drupal 7站点会很快很可靠,并且可以处理高流量的访问。 开源 我们为了软件而来,最终留在了社区里。成千上万的聪明而高效的朋友们在一起工作...

    Drupal 7专业开发

    深入讨论Drupal核心知识,建立模块及优化性能,安全性等等,是Drupal开发人员的首选教程。 作者: Todd Tomlinson、John K. VanDyk 发行日期: 2010年10月

    Drupal 7.32 简体中文版.zip

    使用超过800个Drupal专用模块来扩展你的站点 更加扩展 感谢对JavaScript和CSS的优化、更好的缓存机制以及其他很多改进,你的Drupal站点会很快很可靠,并且可以处理高流量的访问。 开源 我们为了软件而来,最终留在了...

    Drupal 7.32 繁体中文版.zip

    使用超过800个Drupal专用模块来扩展你的站点 更加扩展 感谢对JavaScript和CSS的优化、更好的缓存机制以及其他很多改进,你的Drupal站点会很快很可靠,并且可以处理高流量的访问。 开源 我们为了软件而来,最终留在了...

    Drupal 内容管理系统 v8.4.0 RC1.zip

    更加扩展:感谢对JavaScript和CSS的优化、更好的缓存机制以及其他很多改进,你的Drupal 7站点会很快很可靠,并且可以处理高流量的访问。 开源:我们为了软件而来,最终留在了社区里。成千上万的聪明而高效的朋友们...

    pro_drupal_7_development_3rd_edition

    参考中文名:Drupal 7 专业开发 内容摘要:深入讨论Drupal核心知识,建立模块及优化性能,安全性等,是Drupal开发人员的首选教程 作者:Todd Tomlinson、John K. VanDyk

    Drupal7:Atomic Engager Drupal 7 模块

    在注册,以便我们可以通过我们的内容优化引擎运行您的 Drupal 站点。 与此模块搭配使用,您将获得重要的见解,以帮助吸引目标受众并在每篇文章中放大您的内容。 笔记 该模块将数据洞察发送到您的帐户,并帮助您编写...

    Drupal内容管理系统-PHP

    &lt;/p&gt;&lt;p&gt;更加扩展:感谢对JavaScript和CSS的优化、更好的缓存机制以及其他很多改进,你的Drupal 7站点会很快很可靠,并且可以处理高流量的访问。&lt;/p&gt;&lt;p&gt;开源:我们为了软件而来,最终留在了社区里。成千上万的聪明而...

    charm-drupal:Drupal Juju Charm - Bash 和 Ansible

    这个魅力为 Drupal 提供了一个完整的优化堆栈,包括以下内容: Drupal 7.x(目前...请参阅待办事项) 拉什 Nginx 与 PHP-FPM 5.3.x 指南针/Sass(这是一个选项) 魅力配置: Drupal 版本,目前支持 6 和 7。默认...

    基于Drupal站点管理平台的研究与设计

    Drupal是由Dries Buytaert开发的一款开源的软件,可以进行二次开发构建自己Drupal站点。本论文针对多个Drupal站点...通过Drupal站点管理平台的实施,解决了学校多站点管理的诸多问题,后续还需对该平台进行一些优化。

Global site tag (gtag.js) - Google Analytics