调优LAMP 应用程序的5 种简单方法:
简介
Wikipedia、Facebook 和 Yahoo! 等主要 web 属性使用 LAMP 架构来为每天数百万的请求提供服务,而 Wordpress、Joomla、Drupal 和 SugarCRM 等 web 应用程序软件使用其架构来让组织轻松部署基于 web 的应用程序。
该架构的优势在于其简单性。而 .NET 这样的堆栈和 Java™ 技术可能使用大量硬件、昂贵的软件栈和复杂的性能调优,LAMP 堆栈可以运行于商品硬件之上,使用开源软件栈。由于软件栈是一个松散的组件集,而非一个整体堆栈,性能调优是一大挑战,因为需要分析和调优每个组件。
然而,这有几个个简单性能任务会对任何规模的网站的性能产生巨大的影响。在本文中,我们将探讨旨在优化 LAMP 应用程序性能的 5 个这样的任务。这些项目应当很少需要对您的应用程序进行架构更改,使其成为最大化您的 web 应用程序所需的响应能力和硬件需求的安全、便捷的选择。
优化您的数据库
数据库优化很快会成为一个前沿话题,我几乎没有空间在这里完全公正地做这个话题。但是如果您在寻求优化您的数据库的速度,首先应当采取一些步骤,这应当对常见问题有所帮助。
将数据库放在自己的机器上
数据库查询自身可以变得相当激烈,通常在对大小合理的数据集执行简单的 SELECT 语句时限定在 100% 的 CPU。如果您的 web 服务器和数据库服务器都在竟用单一机器上的 CPU 时间,这无疑将减慢您的请求速度。因此我想第一步最好是将 web 服务器和数据库服务器放在单独的机器上,确保您的数据库服务器是两者中更强健的(数据库服务器喜欢大量内存和多个 CPU)。
合理设计和编制表索引
数据库性能的最大问题可能源自于不良数据库设计和缺失索引。SELECT 语句通常是运行在典型 web 应用程序中的最常见的查询类型。它们也是在数据库服务器上运行的最耗时的查询。此外,这些类型的 SQL 语句对适当的索引和数据库设计最敏感,因此查看以下指示,获取实现最优性能的技巧。
•确保每个表都有一个主键。这为表提供一个默认顺序和快速方式来联接其他表。
•确保一个表中的任何外键(即链接记录到另一个表中的记录的键)的索引得到合理编制。许多数据库会自动对这些键施加约束,以便值真正匹配另一个表中的一条记录,这有助于摆脱这一困难。
•试图限制一个表中的列数。一个表中有太多列比仅有一些列时进行查询所需的扫描时间要长。此外,如果您有不常用的含多个列的一个表,您也在通过 NULL 值字段浪费磁盘空间。文本或 blob 等可变大小字段也是如此,其中表大小的增长可以远超过需求。在这种情况下,您应当考虑将其他栏分成不同的表,在记录的主键上将其联合起来。
分析在服务器上运行的查询
改进数据库性能的最佳方法是分析在您的数据库服务器上运行什么查询,且运行它们需要多长时间。几乎每个数据库都有具有这种功能的工具。对于 MySQL,您可以利用慢查询日志来查找有问题的查询。要使用它,在 MySQL 配置文件中将 slow_query_log 设置为 1,然后将 log_output 设置为 FILE,将它们记录到文件 hostname-slow.log 中。您可以设置 long_query_time 阈值,确定查询必须运行多少秒才被看作是 “慢查询”。我想建议将该阈值首先设置为 5 秒,随着时间的推移将其缩减为 1 秒,具体取决于您的数据集。如果您探究该文件,您会看到类似于清单 1 的详细查询。
清单 1. MySQL 慢查询日志
- /usr/local/mysql/bin/mysqld, Version: 5.1.49-log, started with:
- Tcp port: 3306 Unix socket: /tmp/mysql.sock
- Time Id Command Argument
- # Time: 030207 15:03:33
- # User@Host: user[user] @ localhost.localdomain [127.0.0.1]
- # Query_time: 13 Lock_time: 0 Rows_sent: 117 Rows_examined: 234
- use sugarcrm;
- select * from accounts inner join leads on accounts.id = leads.account_id;
我们想要考虑的关键对象是 Query_time,显示查询需要的时间。另一项要考虑的是 Rows_sent 和 Rows_examined 的数量,因为这些可指这样的情况:其中如果一个查询察看太多行或返回太多行,就会被错误地书写。您可以更深入地钻研如何写查询,即在查询开始处加上 EXPLAIN,它会返回查询计划,而非结果集,如清单 2 所示。
清单 2. MySQL EXPLAIN 结果
- mysql> explain select * from accounts inner join leads on accounts.id = leads.account_id;
- +----+-------------+----------+--------+--------------------------+---------+---
- | id | select_type | table | type | possible_keys
- | key | key_len | ref | rows | Extra |
- +----+-------------+----------+--------+--------------------------+---------+--------
- | 1 | SIMPLE | leads | ALL | idx_leads_acct_del | NULL | NULL
- | NULL | 200 | |
- | 1 | SIMPLE | accounts | eq_ref | PRIMARY,idx_accnt_id_del | PRIMARY | 108
- | sugarcrm.leads.account_id | 1 | |
- +----+-------------+----------+--------+--------------------------+---------+---------
- 2 rows in set (0.00 sec)
MySQL 手册更深入探究 EXPLAIN 输出的主题(参见 参考资料),但是我考虑的一项重要内容是 ‘type’ 列为 ‘ALL’ 的地方,因为这需要 MySQL 做一个全表扫描,且不需要键来执行查询。这些帮助您在添加索引时会大幅提高查询速度。