調優LAMP應用程序的5種簡單方法:優化數據庫
調優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 做一個全表掃描,且不需要鍵來執行查詢。這些幫助您在添加索引時會大幅提高查詢速度。