如何提升 WordPress REST API 的請求速度


這幾週體會到什麼叫做吃痰吃飽的人生 Orz…

不知道是不是新冠肺炎的後遺症還是得了什麼怪病,我已經連續咳痰咳了快三個禮拜,期間看過三次西醫兩次中醫,吃了各式各樣的藥結果到了今天還是沒好轉,有吃藥的時候就好一點,藥一停症狀就全部回來,現在每天起床一想到又要咳一整天就覺得心好累,對於從來沒有生過這麼久的病的我來說實在很非常難熬。

這陣子咳嗽吐痰變成我的開發日常,每次在咳的時候聲音超大都覺得隔壁鄰居會跟管理員投訴我噪音污染,昨天又去看了中醫拿了七天藥,只能再吃一週看會有什麼變化,如果你手邊有什麼好藥拜託跟我說,實在不想每天過著吃痰的生活了…

使用勾點 option_active_plugin 來程式化設定需要載入的外掛,藉此在某些特定情境下減少外掛的使用以提升頁面讀取速度,提供給第三方服務呼叫使用的 REST API 就非常適合使用。

自從改變接案模式後,跟每個案子相處的時間都已經超過一年半載,時間越長就會碰到以往短期專案遇不到的狀況,像是新需求的開發、外掛的相容性整合以及除蟲作業,其中最容易遇到的就是效能問題,尤其是在網站經營數年後這類問題會逐漸浮現。

WordPress REST API 回應速度遲緩

客戶的使用情境是採用了第三方服務來做客戶關係管理,該服務可以整合對話機器人以便根據顧客對話結果與屬性去做相對應的留言互動,由於要讓機器人互動有專屬的客製化訊息,因此需要從網站這邊取得資料後進行傳送。

流程是第三方服務在接收到顧客的訊息後,會以 Webhook 的方式呼叫站內 REST API 來取得機器人的回覆訊息,這內文是給機器人閱讀的格式以將其轉換成顧客看得懂的圖文按鈕,因此為了要讓顧客有對話的感覺,互動過程一定要很順暢。

但很可能是網站經營久了用了不少的外掛,或是資料庫肥大而造成第三方服務請求站內 REST API 的時候回應速度很慢,這就像你在跟人聊天時你講完一句話對方過了三秒才回覆你一樣,會讓整個互動體驗變得很差。

提升 WordPress REST API 請求速度的方法

為了解決這個問題,我依序嘗試了幾種方法。首先,最根本的解法就是透過網站效能分析工具來查看每一次 API 的請求經過哪些步驟與資料庫查詢,從中找尋效能瓶頸,我習慣用的是外掛 Query Monitor 以及網站分析服務 New Relic 的 APM。

追查結果矛頭都指向資料庫 wp_options 以及 wp_postmeta ,這兩張表格花了非常多的時間在進行查詢,因為所有外掛的設定功能都會記錄在 wp_options,而文章、頁面的自訂欄位都寫在 wp_postmeta,也因此長年經營的 WordPress 網站這兩個表格一定都會很肥。

一、資料庫表格索引

要把這兩張表瘦身除了移除掉不需要的紀錄以外,還可以利用資料庫的索引功能來增加讀取速度,資料索引的邏輯可以想像成是你到大賣場去找一件商品,你不用在每一個貨架裡面做地毯式搜索,而是先抬頭看看標誌找大類別,或是詢問賣場人員問你需要的東西可能會在哪一個區塊,而這些尋找商品的輔助就是一種索引。

因此當資料庫設定索引後就不用從表格中逐一搜尋,只要有索引表就能在擁有大量資料的表格中快速找到對應的資料,但索引也不是無敵的,當資料量沒有很多的時候反而會有反效果,一般來說會在我們發現資料庫讀取緩慢時使用。

設定 wp_options 表格索引可以參考這篇教學: https://silicondales.com/tutorials/wordpress/big-wordpress-problem-slow-wp-admin-uncached-pageloads-slow/#Method_2_-_Add_an_Index_to_wp_options_database_on_autoload

害怕輸入 SQL 也有現成外掛可以使用: https://wordpress.org/plugins/index-wp-mysql-for-speed/https://wordpress.org/plugins/index-wp-mysql-for-speed/

MySQL 索引原理介紹: https://www.jyt0532.com/2021/01/30/index/

二、建立 REST API 快取

一般的頁面可以使用快取來增加讀取速度,那麼請求 REST API 也可以有快取嗎?當然可以,快取是我第二個考量的解決方案,因為比起慢慢整理資料庫使用快取很快就能讓客戶看到效果,在研究如何把 REST API 加入快取的同時也發現到有這樣的外掛:

https://wordpress.org/plugins/wp-rest-cache/

WP REST Cache 這支外掛可以把 WordPress 內建的 API 都快取起來,同時也支援自定義文章與分類,還能手動清除快取以及查詢已快取的資料,如果只是單純要快取 Post 相關的 API 就十分方便,但實測之後發現它無法解決我的問題。

第一個問題在於它沒有支援自定義 API 請求路徑,也就是說它只吃 wp-json/wp/v2/posts 路徑下的回傳資料,由於整合第三方服務必須要自行設計 API 路徑與回傳內容,要讓這支外掛也能支援的話勢必要額外花時間處理了。

其次是該外掛只支援請求方法為 GET 的存取,如果今天你的 API 是使用 POST 或是 PUT 來進行呼叫的話會無法保存快取,通常除了 GET 以外其他的方法都不能使用快取,不然會造成資料無法更新的問題,綜合以上因素快取自定義 API 這條路對我來說行不通。

三、停用不需要的外掛

WordPress 最強大的部分無疑是外掛,但並非每個頁面都需要載入所有的外掛,如何讓 REST API 請求只載入必要外掛成為我另一個思考方向,想不到研究了一下還真的有人跟我想得一樣,這是由 Delicious Media 所提出的解決方案:

https://www.deliciousmedia.co.uk/journal/wordpress-rest-api-performance/

這方法很聰明,他們寫了一支外掛然後裝在 mu-plugins 資料夾裡面,之所以要放在這邊是因為這個資料夾中的外掛會最先啟用,這樣就能及早讀取到該外掛以修改外掛的啟用設定,非常適合 REST API 請求的使用場景。

這支外掛的程式碼短短 44 行就能搞定:

該外掛使用了勾點 option_active_plugins 來修改啟用中的外掛,帶有一個陣列參數也就是啟用外掛的清單,只要修改這個陣列就能決定需要載入哪些外掛,修改的方式是透過這支外掛提供的勾點 quickrest_plugin_map 來處理。

假設我們自己設計的 API 路徑為 wp-json/myapi/v1/post,只要在自己的外掛中加入以下程式碼來修改需要啟用的外掛即可:

$new_map 這個陣列就是指定當請求 wp-json/myapi 的時候會啟用的外掛,陣列的 key 是 API 的命名空間,value 則是另外一個陣列,以「外掛資料夾/外掛主檔案」的形式來指定,所以範例中代表的是當請求 wp-json/myapi/v1/post 的時候,只會載入 ACF Pro 以及 WooCommerce 兩支外掛,其他沒指定的就不會載入。

但在我實測後發現如果是以勾點 quickrest_plugin_map 來指定啟用外掛並不會生效,請求 API 的結果都顯示無法找到路由,推測原因可能是我的外掛載入順序的問題,因此最後我還是直接把判斷寫在 QuickRest 外掛本體裡面,修改結果如下:

首先先判斷請求的網址是否帶有 wp-json 關鍵字,有的話就代表這次的請求是呼叫 API,並且取得 API 的命名空間,當命名空間為 myapi 時,則取得所有外掛與所需外掛的交集,之所以使用 array_intersect 取得陣列交集是確保指定的外掛已安裝在網站內,以避免啟用到沒有安裝的外掛。

當請求 wp-json/myapi/v1/post 就能明顯感受到速度的提升,像回到一開始剛裝完 WordPress 還沒有任何資料的順暢感,但這樣的作法還是有風險,你必須要 100% 掌控你的 API 有用到哪些外掛,當 API 整合新外掛的功能時也要記得把該外掛更新到啟用列表中,不然接手的人應該會除錯除到瘋掉…

結語

要提升 REST API 的請求速度有很多種作法,具體要採用哪種作法需視網站經營的實際情況來做判斷,看是要先治標撐過這次行銷活動,還是要規劃足夠的時間來徹底治本,這都需要與站長仔細評估後再做出因應的解決之道。

你曾經遇過這一類的問題嗎?你是如何解決的?歡迎回信跟我交流,下週如果身體狀況安好的話我會繼續 WooCommerce Store API 的系列文,我們下週見!

WordPress 開發日常

Read more from WordPress 開發日常

自從 LINE Notify 終止服務後所有站長都在找尋替代方案,如果還是想在 LINE 裡面收到管理員的訂單通知,只能採用與一般顧客相同的方式,也就是申請官方帳號接收通知,雖然一樣有免費額度可以使用,但對於量大的站長來說又是一筆新的支出成本。 如果不想要新增這筆開銷,勢必要尋找其他即時通訊軟體來接收通知,像是採用 Discord 或是 Telegram,如果站長本身就沒有在使用這些軟體需要額外安裝,安裝後還需要申請開發者帳號取得金鑰,而網站這邊也要另外使用外掛或是請工程師進行串接。 難道沒有更方便、更優雅的方式來解決這個問題嗎?不僅可以在桌機上收到通知,同時還能推播到手機甚至是穿戴型裝置上,最重要的是每一則推播不會被收費、也不用擔心原本免費的方案終止服務或是漲價,而這解決方案我們在各大新聞網站都曾見過它,那就是網頁推播通知技術 ( Web Push Notification )。 外掛介紹 DWP 網站助理整合網頁推播通知,可以讓訂閱者在訂單狀態改變時收到推播訊息,支援所有平台,包含 Windows、MacOS、Android 以及 iOS...

這禮拜有幸約到網路創業家蕭上農 Fox 大大進行一對一的創業諮詢面談,從我小時候就是看著他的創業故事長大的,一直有持續在關注他分享的內容,現在自己也走在創業的這條路上,想說何不約一下已經走過這一遭的 Fox,想知道他是怎麼看 WooCommerce 外掛創業的機會。 我們談到三個大主題:OrderNotify 現況分析、創業主題的選擇、AI 浪潮下產品開發的思維。 OrderNotify 現況分析 根據我提供的銷售狀況來看,Fox 覺得這個產品在這些年的業績已經足以代表市場不夠大,目前針對的使用者族群太細了,要有使用 WooCommerce 架站又要有認真經營 LINE 官方帳號的商家數量群體本身就不夠大。 以漏斗的角度來看,這已經是最最下面的底層,業績無法有突破純粹是市場太小,如果是鎖定更大的市場,像是支援 Whatsapp 或是開發 Shopify 的 App 才有足夠大的量能讓個人開發者過活,或是要把眼光放在海外而非僅限於台灣,朝著漏斗的上方移動才行。 我用 Built with 查了一下台灣 WooCommerce 的網站數量是 10,610,以我目前的顧客數量 120...

創業是一場實驗,可以依照自己的想法去實踐的過程非常有趣,雖然免不了許多挫折失敗的時刻,但只要一想到令人興奮的點子又是希望破表。我從這篇文章開始紀錄創業的過程,希望一年後回過頭來看可以回憶起一年前的自己都在想些什麼五四三XD 上一次完全沒有案件收入的狀況要回朔到十幾年前,當時不知道該怎麼找案子,手邊的生活急用金只有兩個月,在時間壓力下只能重回職場先求溫飽。這一次從接案者的身份「離職」,為此我做足了準備,希望在資金燒完前可以找到合適自己的商業模式, 三月份我將心力放在產品的更新與行銷上,做了很多以前沒做過的事,處處充滿了新鮮感,但也因為都沒做過,不曉得哪些有效哪些沒效,所以打算以後在每個月的最後一週寫一篇創業日記,紀錄做對跟做錯了哪些事,算是幫自己回顧這一路上的過程。 第一個月設定的主要目標:行銷,在與 ChatGPT 諮詢過後,它給我的建議是公司產品是有市場的,但因為曝光量不足,所以營收無法提升,要增加曝光度為首要目標。剛好這個月 LINE Notify 停用,就決定以這個切入點來強化產品功能並撰寫行銷內容。 三月份的總工作時數為 41.12 小時,加上客服時間總計約 48...