深入淺出講述提升 WordPress 性能的九大秘笈
在建站和 web 應用程序交付方面,WordPress 是全球最大的一個平臺。全球大約四分之一 的站點現在正在使用開源 WordPress 軟件,包括 eBay、 Mozilla、 RackSpace、 TechCrunch、 CNN、 MTV、紐約時報、華爾街日報 等等。
最流行的個人博客平臺 WordPress.com,其也運行在 WordPress 開源軟件上。而 NGINX 則為 WordPress.com 提供了動力。在 WordPress.com 的用戶當中,許多站點起步于 WordPress.com,然后換成了自己運行 WordPress 開源軟件;它們中越來越多的站點也使用了 NGINX 軟件。
WordPress 的吸引力源于其簡單性,無論是對于最終用戶還是安裝架設。然而,當使用量不斷增長時,WordPress 站點的體系結構也存在一定的問題 - 這里有幾個方法,包括使用緩存,以及將 WordPress 和 NGINX 組合起來,可以解決這些問題。
在這篇博客中,我們提供了九個提速技巧來幫助你解決 WordPress 中一些常見的性能問題:
- 緩存靜態資源
- 緩存動態文件
- 遷移到 NGINX
- 添加 NGINX 靜態鏈接支持
- 為 NGINX 配置 FastCGI
- 為 NGINX 配置 W3TotalCache
- 為 NGINX 配置 WP-Super-Cache
- 為 NGINX 配置安全防范措施
- 配置 NGINX 支持 WordPress 多站點
在 LAMP 架構下 WordPress 的性能
大多數 WordPress 站點都運行在傳統的 LAMP 架構下:Linux 操作系統,Apache Web 服務器軟件,MySQL 數據庫軟件(通常是一個單獨的數據庫服務器)和 PHP 編程語言。這些都是非常著名的,廣泛應用的開源工具。在 WordPress 世界里,很多人都用的是 LAMP,所以很容易尋求幫助和支持。
當用戶訪問 WordPress 站點時,瀏覽器為每個用戶創建六到八個連接來連接到 Linux/Apache 上。當用戶請求連接時,PHP 即時生成每個頁面,從 MySQL 數據庫獲取資源來響應請求。
LAMP 或許對于數百個并發用戶依然能照常工作。然而,流量突然增加是常見的,并且通常這應該算是一件好事。
但是,當 LAMP 站點變得繁忙時,當同時在線的用戶達到數千個時,它的瓶頸就會被暴露出來。瓶頸存在主要是兩個原因:
-
Apache Web 服務器 - Apache 的每個/每次連接需要消耗大量資源。如果 Apache 接受了太多的并發連接,內存可能會耗盡,從而導致性能急劇降低,因為數據必須交換到磁盤了。如果以限制連接數來提高響應時間,新的連接必須等待,這也導致了用戶體驗變得很差。
-
PHP/MySQL 的交互 - 一個運行 PHP 和 MySQL 數據庫服務器的應用服務器上每秒的請求量有一個最大限制。當請求的數量超過這個最大限制時,用戶必須等待。超過這個最大限制時也會增加所有用戶的響應時間。超過其兩倍以上時會出現明顯的性能問題。
LAMP 架構的網站出現性能瓶頸是常見的情況,這時就需要升級硬件了 - 增加 CPU,擴大磁盤空間等等。當 Apache 和 PHP/MySQL 的架構超載后,在硬件上不斷的提升卻跟不上系統資源指數增長的需求。
首選替代 LAMP 架構的是 LEMP 架構 – Linux, NGINX, MySQL, 和 PHP。 (這是 LEMP 的縮寫,E 代表著 “engine-x.” 的發音。) 我們在 技巧 3 中會描述 LEMP 架構。
技巧 1. 緩存靜態資源
靜態資源是指不變的文件,像 CSS,JavaScript 和圖片。這些文件往往在網頁的數據中占半數以上。頁面的其余部分是動態生成的,像在論壇中評論,性能儀表盤,或個性化的內容(可以看看 Amazon.com 產品)。
緩存靜態資源有兩大好處:
-
更快的交付給用戶 - 用戶可以從它們瀏覽器的緩存或者從互聯網上離它們最近的緩存服務器獲取靜態文件。有時候文件較大,因此減少等待時間對它們來說幫助很大。
-
減少應用服務器的負載 - 從緩存中檢索到的每個文件會讓 web 服務器少處理一個請求。你的緩存越多,用戶等待的時間越短。
要讓瀏覽器緩存文件,需要在靜態文件中設置正確的 HTTP 首部。看看 HTTP Cache-Control 首部,特別是設置了 max-age 參數,Expires 首部,以及 Entity 標記。這里 有詳細的介紹。
當啟用本地緩存,然后用戶請求以前訪問過的文件時,瀏覽器首先檢查該文件是否在緩存中。如果在,它會詢問 Web 服務器該文件是否改變過。如果該文件沒有改變,Web 服務器將立即響應一個304狀態碼(未改變),這意味著該文件沒有改變,而不是返回狀態碼200 OK 并檢索和發送已改變的文件。
要在瀏覽器之外支持緩存,可以考慮下面講到的技巧,以及考慮使用內容分發網絡(CDN)。CDN 是一種流行且強大的緩存工具,但我們在這里不詳細描述它。在你實現了這里講到的其它技術之后可以考慮 CDN。此外,當你的站點從 HTTP/1.x 過渡到 HTTP/2 協議時,CDN 的用處可能不太大;根據需要調查和測試,找到你網站需要的正確方法。
如果你轉向 NGINX Plus 或將開源的 NGINX 軟件作為架構的一部分,建議你考慮 技巧 3,然后配置 NGINX 緩存靜態資源。使用下面的配置,用你 Web 服務器的 URL 替換 www.example.com。
server { ### 將 www.example.com 替換為你的 URL server_name www.example.com; root /var/www/example.com/htdocs; index index.php; access_log /var/log/nginx/example.com.access.log; error_log /var/log/nginx/example.com.error.log; location / { try_files $uri $uri/ /index.php?$args; } location ~ \.php$ { try_files $uri =404; include fastcgi_params; ### 使用你 WordPress 服務器的套接字,地址和端口來替換 fastcgi_pass unix:/var/run/php5-fpm.sock; #fastcgi_pass 127.0.0.1:9000; } location ~* .(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|css|rss|atom|js|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ { expires max; log_not_found off; access_log off; } }
技巧 2. 緩存動態文件
WordPress 動態地生成網頁,這意味著每次請求時它都要生成一個給定的網頁(即使和前一次的結果相同)。這意味著用戶隨時獲得的是最新內容。
想一下,當用戶訪問一個帖子時,并在文章底部有用戶的評論時。你希望用戶能夠看到所有的評論 - 即使評論剛剛發布。動態內容就是處理這種情況的。
但現在,當帖子每秒出現十幾二十幾個請求時。應用服務器可能每秒需要頻繁生成頁面導致其壓力過大,造成延誤。為了給用戶提供最新的內容,每個訪問理論上都是新的請求,因此它們不得不在原始出處等待很長時間。
為了防止頁面由于不斷提升的負載而變得緩慢,需要緩存動態文件。這需要減少文件的動態內容來提高整個系統的響應速度。
要在 WordPress 中啟用緩存中,需要使用一些流行的插件 - 如下所述。WordPress 的緩存插件會請求最新的頁面,然后將其緩存短暫時間 - 也許只有幾秒鐘。因此,如果該網站每秒中會有幾個請求,那大多數用戶獲得的頁面都是緩存的副本。這也有助于提高所有用戶的檢索時間:
- 大多數用戶獲得頁面的緩存副本。應用服務器沒有做任何工作。
- 用戶會得到一個之前的嶄新副本。應用服務器只需每隔一段時間生成一個嶄新頁面。當服務器產生一個嶄新頁面(對于緩存過期后的第一個用戶訪問),它這樣做要快得多,因為它的請求并沒有超載。
你可以緩存運行在 LAMP 架構或者 LEMP 架構 上 WordPress 的動態文件(在 技巧 3 中說明了)。有幾個緩存插件,你可以在 WordPress 中使用。運用到了最流行的緩存插件和緩存技術,從最簡單到最強大的:
-
Hyper-Cache 和 Quick-Cache – 這兩個插件為每個 WordPress 頁面創建單個 PHP 文件。它支持繞過多個 WordPress 與數據庫的連接核心處理的一些動態功能,創建一個更快的用戶體驗。它們不會繞過所有的 PHP 處理,所以并不會如下面那些取得同樣的性能提升。它們也不需要修改 NGINX 的配置。
-
WP Super Cache – 最流行的 WordPress 緩存插件。在它易用的界面易用上提供了許多功能,如下所示。我們在 技巧 7 中展示了一個簡單的 NGINX 配置實例。
-
W3 Total Cache – 這是第二流行的 WordPress 緩存插件。它比 WP Super Cache 的功能更強大,但它有些配置選項比較復雜。樣例 NGINX 配置,請看 技巧 6。
-
FastCGI – CGI 的意思是通用網關接口(Common Gateway Interface),在因特網上發送請求和接收文件的一種通用方式。它不是一個插件,而是一種與緩存交互緩存的方法。FastCGI 可以被用在 Apache 和 Nginx 上,它也是最流行的動態緩存方法;我們在 技巧 5 中描述了如何配置 NGINX 來使用它。
這些插件和技術的文檔解釋了如何在典型的 LAMP 架構中配置它們。配置方式包括數據庫和對象緩存;最小化 HTML、CSS 和 JavaScript;集成流行的 CDN 集成環境。對于 NGINX 的配置,請看列表中的提示技巧。
注意:緩存不會用于已經登錄的 WordPress 用戶,因為他們的 WordPress 頁面都是不同的。(對于大多數網站來說,只有一小部分用戶可能會登錄)此外,大多數緩存不會對剛剛評論過的用戶顯示緩存頁面,因為當用戶刷新頁面時希望看到他們的評論。若要緩存頁面的非個性化內容,如果它對整體性能來說很重要,可以使用一種稱為 碎片緩存(fragment caching) 的技術。
技巧 3. 使用 NGINX
如上所述,當并發用戶數超過某一數量時 Apache 會導致性能問題 – 可能是數百個用戶同時使用。Apache 對于每一個連接會消耗大量的資源,因而容易耗盡內存。Apache 可以配置連接數的值來避免耗盡內存,但是這意味著,超過限制時,新的連接請求必須等待。
此外,Apache 為每個連接加載一個 mod_php 模塊副本到內存中,即使只有服務于靜態文件(圖片,CSS,JavaScript 等)。這使得每個連接消耗更多的資源,從而限制了服務器的性能。
要解決這些問題,從 LAMP 架構遷到 LEMP 架構 – 使用 NGINX 取代 Apache 。NGINX 在一定的內存之下就能處理成千上萬的并發連接數,所以你不必經歷顛簸,也不必限制并發連接數到很小的數量。
NGINX 處理靜態文件的性能也較好,它有內置的,容易調整的 緩存 控制策略。減少應用服務器的負載,你的網站的訪問速度會更快,用戶體驗更好。
你可以在部署環境的所有 Web 服務器上使用 NGINX,或者你可以把一個 NGINX 服務器作為 Apache 的“前端”來進行反向代理 - NGINX 服務器接收客戶端請求,將請求的靜態文件直接返回,將 PHP 請求轉發到 Apache 上進行處理。
對于動態頁面的生成,這是 WordPress 核心體驗,可以選擇一個緩存工具,如 技巧 2 中描述的。在下面的技巧中,你可以看到 FastCGI,W3_Total_Cache 和 WP-Super-Cache 在 NGINX 上的配置示例。 (Hyper-Cache 和 Quick-Cache 不需要改變 NGINX 的配置。)
技巧 緩存通常會被保存到磁盤上,但你可以用 tmpfs 將緩存放在內存中來提高性能。
為 WordPress 配置 NGINX 很容易。僅需四步,其詳細的描述在指定的技巧中:
- 添加永久鏈接的支持 - 讓 NGINX 支持永久鏈接。此步消除了對 .htaccess 配置文件的依賴,這是 Apache 特有的。參見 技巧 4。
- 配置緩存 - 選擇一個緩存工具并安裝好它。可選擇的有 FastCGI cache,W3 Total Cache, WP Super Cache, Hyper Cache, 和 Quick Cache。請看技巧 5、 6 和 7。
- 落實安全防范措施 - 在 NGINX 上采用對 WordPress 最佳安全的做法。參見 技巧 8。
- 配置 WordPress 多站點 - 如果你使用 WordPress 多站點,在 NGINX 下配置子目錄,子域,或多域名架構。見 技巧9。
技巧 4. 讓 NGINX 支持永久鏈接
許多 WordPress 網站依賴于 .htaccess 文件,此文件為 WordPress 的多個功能所需要,包括永久鏈接支持、插件和文件緩存。NGINX 不支持 .htaccess 文件。幸運的是,你可以使用 NGINX 的簡單而全面的配置文件來實現大部分相同的功能。
你可以在你的主 server 塊下添加下面的 location 塊中為使用 NGINX 的 WordPress 啟用 永久鏈接。(此 location 塊在其它代碼示例中也會被包括)。
try_files 指令告訴 NGINX 檢查請求的 URL 在文檔根目錄(/var/www/example.com/htdocs)下是作為文件($uri)還是目錄($uri/) 存在的。如果都不是,NGINX 將重定向到 /index.php,并傳遞查詢字符串參數作為參數。
server { server_name example.com www.example.com; root /var/www/example.com/htdocs; index index.php; access_log /var/log/nginx/example.com.access.log; error_log /var/log/nginx/example.com.error.log; location / { try_files $uri $uri/ /index.php?$args; } }
技巧 5. 在 NGINX 中配置 FastCGI
NGINX 可以緩存來自 FastCGI 應用程序的響應,如 PHP 響應。此方法可提供最佳的性能。
對于開源的 NGINX,編譯入第三方模塊 ngx_cache_purge 可以提供緩存清除能力,配置代碼如下所示。NGINX Plus 已經包含了它自己實現此代碼。
當使用 FastCGI 時,我們建議你安裝 NGINX 輔助插件 并使用下面的配置文件,尤其是要注意 fastcgi_cache_key 的使用和包括 fastcgi_cache_purge 的 location 塊。當頁面發布或有改變時,有新評論被發布時,該插件會自動清除你的緩存,你也可以從 WordPress 管理控制臺手動清除。
NGINX 的輔助插件還可以在你網頁的底部添加一個簡短的 HTML 代碼,以確認緩存是否正常并顯示一些統計數據。(你也可以使用 $upstreamcachestatus 確認緩存功能是否正常。)
fastcgi_cache_path /var/run/nginx-cache levels=1:2 keys_zone=WORDPRESS:100m inactive=60m; fastcgi_cache_key "$scheme$request_method$host$request_uri"; server { server_name example.com www.example.com; root /var/www/example.com/htdocs; index index.php; access_log /var/log/nginx/example.com.access.log; error_log /var/log/nginx/example.com.error.log; set $skip_cache 0; ### POST 請求和帶有查詢參數的網址應該交給 PHP if ($request_method = POST) { set $skip_cache 1; } if ($query_string != "") { set $skip_cache 1; } ### 以下 uris 中包含的部分不緩存 if ($request_uri ~* "/wp-admin/|/xmlrpc.php|wp-.*.php|/feed/|index.php |sitemap(_index)?.xml") { set $skip_cache 1; } ### 不要為登錄用戶或最近的評論者進行緩存 if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass |wordpress_no_cache|wordpress_logged_in") { set $skip_cache 1; } location / { try_files $uri $uri/ /index.php?$args; } location ~ \.php$ { try_files $uri /index.php; include fastcgi_params; fastcgi_pass unix:/var/run/php5-fpm.sock; fastcgi_cache_bypass $skip_cache; fastcgi_no_cache $skip_cache; fastcgi_cache WORDPRESS; fastcgi_cache_valid 60m; } location ~ /purge(/.*) { fastcgi_cache_purge WORDPRESS "$scheme$request_method$host$1"; } location ~* ^.+\.(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|css|rss|atom|js|jpg|jpeg|gif|png |ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ { access_log off; log_not_found off; expires max; } location = /robots.txt { access_log off; log_not_found off; } location ~ /\. { deny all; access_log off; log_not_found off; } }
技巧 6. 為 NGINX 配置 W3_Total_Cache
W3 Total Cache, 是 W3-Edge 的 Frederick Townes 出品的, 是一個支持 NGINX 的 WordPress 緩存框架。其有眾多選項配置,可以替代 FastCGI 緩存。
這個緩存插件提供了各種緩存配置,還包括數據庫和對象的緩存,最小化 HTML、CSS 和 JavaScript,并可選與流行的 CDN 整合。
這個插件會通過寫入一個位于你的域的根目錄的 NGINX 配置文件來控制 NGINX。
server { server_name example.com www.example.com; root /var/www/example.com/htdocs; index index.php; access_log /var/log/nginx/example.com.access.log; error_log /var/log/nginx/example.com.error.log; include /path/to/wordpress/installation/nginx.conf; location / { try_files $uri $uri/ /index.php?$args; } location ~ \.php$ { try_files $uri =404; include fastcgi_params; fastcgi_pass unix:/var/run/php5-fpm.sock; } }
技巧 7. 為 NGINX 配置 WP Super Cache
WP Super Cache 是由 Donncha O Caoimh 開發的, 他是 Automattic 的一個 WordPress 開發者, 這是一個 WordPress 緩存引擎,它可以將 WordPress 的動態頁面轉變成靜態 HTML 文件,以使 NGINX 可以很快的提供服務。它是第一個 WordPress 緩存插件,和其它的相比,它更專注于某一特定的領域。
配置 NGINX 使用 WP Super Cache 可以根據你的喜好而進行不同的配置。以下是一個示例配置。
在下面的配置中,帶有名為 supercache 的 location 塊是 WP Super Cache 特有的部分。 WordPress 規則的其余代碼用于不緩存已登錄用戶的信息,不緩存 POST 請求,并對靜態資源設置過期首部,再加上標準的 PHP 處理;這部分可以根據你的需求進行定制。
server { server_name example.com www.example.com; root /var/www/example.com/htdocs; index index.php; access_log /var/log/nginx/example.com.access.log; error_log /var/log/nginx/example.com.error.log debug; set $cache_uri $request_uri; ### POST 請求和帶有查詢字符串的網址應該交給 PHP if ($request_method = POST) { set $cache_uri 'null cache'; } if ($query_string != "") { set $cache_uri 'null cache'; } ### 以下 uris 中包含的部分不緩存 if ($request_uri ~* "(/wp-admin/|/xmlrpc.php|/wp-(app|cron|login|register|mail).php |wp-.*.php|/feed/|index.php|wp-comments-popup.php |wp-links-opml.php|wp-locations.php |sitemap(_index)?.xml |[a-z0-9_-]+-sitemap([0-9]+)?.xml)") { set $cache_uri 'null cache'; } ### 不對已登錄用戶和最近的評論者使用緩存 if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+ |wp-postpass|wordpress_logged_in") { set $cache_uri 'null cache'; } ### 當請求的文件存在時使用緩存,否則將請求轉發給 WordPress location / { try_files /wp-content/cache/supercache/$http_host/$cache_uri/index.html $uri $uri/ /index.php; } location = /favicon.ico { log_not_found off; access_log off; } location = /robots.txt { log_not_found off access_log off; } location ~ .php$ { try_files $uri /index.php; include fastcgi_params; fastcgi_pass unix:/var/run/php5-fpm.sock; #fastcgi_pass 127.0.0.1:9000; } ### 盡可能的緩存靜態文件 location ~*.(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|css |rss|atom|js|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2 |doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ { expires max; log_not_found off; access_log off; } }
技巧 8. 為 NGINX 配置安全防范措施
為了防止攻擊,可以控制對關鍵資源的訪問并限制機器人對登錄功能的過量攻擊。
只允許特定的 IP 地址訪問 WordPress 的儀表盤。
### 對訪問 WordPress 的儀表盤進行限制 location /wp-admin { deny 192.192.9.9; allow 192.192.1.0/24; allow 10.1.1.0/16; deny all; }
只允許上傳特定類型的文件,以防止惡意代碼被上傳和運行。
### 當上傳的不是圖像,視頻,音樂等時,拒絕訪問。 location ~* ^/wp-content/uploads/.*.(html|htm|shtml|php|js|swf)$ { deny all; }
拒絕其它人訪問 WordPress 的配置文件 wp-config.php。拒絕其它人訪問的另一種方法是將該文件的一個目錄移到域的根目錄之上的目錄。
### 拒絕其它人訪問 wp-config.php location ~* wp-config.php { deny all; }
對 wp-login.php 進行限速來防止暴力破解。
### 拒絕訪問 wp-login.php location = /wp-login.php { limit_req zone=one burst=1 nodelay; fastcgi_pass unix:/var/run/php5-fpm.sock; #fastcgi_pass 127.0.0.1:9000; }
技巧 9. 配置 NGINX 支持 WordPress 多站點
WordPress 多站點(WordPress Multisite),顧名思義,這個版本 WordPress 可以讓你以單個實例管理兩個或多個網站。WordPress.com 運行的就是 WordPress 多站點,其主機為成千上萬的用戶提供博客服務。
你可以從單個域的任何子目錄或從不同的子域來運行獨立的網站。
使用此代碼塊添加對子目錄的支持。
### 在 WordPress 多站點中添加對子目錄結構的支持 if (!-e $request_filename) { rewrite /wp-admin$ $scheme://$host$uri/ permanent; rewrite ^(/[^/]+)?(/wp-.*) $2 last; rewrite ^(/[^/]+)?(/.*\.php) $2 last; }
使用此代碼塊來替換上面的代碼塊以添加對子目錄結構的支持,替換為你自己的子目錄名。
### 添加支持子域名 server_name example.com *.example.com;
舊版本(3.4以前)的 WordPress 多站點使用 readfile() 來提供靜態內容。然而,readfile() 是 PHP 代碼,它會導致在執行時性能會顯著降低。我們可以用 NGINX 來繞過這個非必要的 PHP 處理。該代碼片段在下面被(==============)線分割出來了。
### 避免對子目錄中 /blogs.dir/ 結構執行 PHP readfile() location ^~ /blogs.dir { internal; alias /var/www/example.com/htdocs/wp-content/blogs.dir; access_log off; log_not_found off; expires max; } ============================================================ ### 避免對子目錄中 /files/ 結構執行 PHP readfile() location ~ ^(/[^/]+/)?files/(?.+) { try_files /wp-content/blogs.dir/$blogid/files/$rt_file /wp-includes/ms-files.php?file=$rt_file; access_log off; log_not_found off; expires max; } ============================================================ ### 子域路徑的WPMU 文件結構 location ~ ^/files/(.*)$ { try_files /wp-includes/ms-files.php?file=$1 =404; access_log off; log_not_found off; expires max; } ============================================================ ### 映射博客 ID 到特定的目錄 map $http_host $blogid { default 0; example.com 1; site1.example.com 2; site1.com 2; }
結論
可擴展性對許多要讓他們的 WordPress 站點取得成功的開發者來說是一項挑戰。(對于那些想要跨越 WordPress 性能門檻的新站點而言。)為 WordPress 添加緩存,并將 WordPress 和 NGINX 結合,是不錯的答案。
NGINX 不僅用于 WordPress 網站。世界上排名前 1000、10000 和 100000 網站中 NGINX 也是 遙遙領先的 web 服務器。
欲了解更多有關 NGINX 的性能,請看我們最近的博客,讓應用性能提升 10 倍的 10 個技巧。
NGINX 軟件有兩個版本:
- NGINX 開源軟件 - 像 WordPress 一樣,此軟件你可以自行下載,配置和編譯。
- NGINX Plus - NGINX Plus 包括一個預構建的參考版本的軟件,以及服務和技術支持。
想要開始,先到 nginx.org 下載開源軟件并了解下 NGINX Plus。
via: https://www.nginx.com/blog/9-tips-for-improving-wordpress-performance-with-nginx/
作者:Floyd Smith 譯者:strugglingyouth 校對:wxy