Nginx 中 map 模組的使用及效能測試

發表於2016-07-18

背景

最近我操刀了leetcode論壇遷移,整個過程持續了幾周的時間,總算暫時告了一個段落。常使用leetcode論壇的使用者應該已經發現論壇已經大變樣了吧~

期間遇到了不少坑坑窪窪,將來也還會有好多問題等待去一一解決。關於這個遷移過程中的收貨,這篇文章中就不細說了,有時間再另開一篇博文。這篇文章主要關注在url-mapping以及它的效能問題。

:url-mapping的問題從何而來呢?

舊的論壇和新的論壇是兩個不同的discuss框架。前者是phpbb,現在是nodebb。兩者的 url routing 完全不一樣,比如說同一個topic,在原來的url是 http://hostname/discuss/<topic_id>/<topic_name>,在新的論壇中是http://hostname/topic/<topic_id>/<topic_slug>(這裡就不討論兩者甚至連topic_id都不一樣的問題了)。

而在廣袤的網際網路海洋中,舊論壇的url可能到處都存在。我們不希望在論壇遷移後,使用者點那些連結就失效了。我們希望的是使用者訪問舊的url可以被重定向到新論壇的某個地址。所以就產生了url-mapping的問題。

方法

生成url-mapping

感謝nodebb-plugin-import提供了資料遷移以後自動生成url-mapping的方式,省了我自己寫指令碼生成這些mapping的時間。每一條mapping大致是這樣的:

其中的slugid的mapping是由外掛生成的。regular expression是為了匹配url中如果有param新增的。

Nginx Map

官方文件的demo可能對於剛想上手的同學來說不是那麼友好,還是直接看現成的配置學得快:

在server規則匹配中,$new值不為空,說明當前要訪問的url已經在http模組的mapping檔案中匹配到了,這個時候就不走各種location模組了,直接rewrite成新的地址。:這裡要是做成proxy_pass也行,後面的測試中就採用了proxy_pass。但線上的環境,擔心nginx的壓力太大了,就採用了rewrite方式給它減減壓。

測試

考慮到mapping的條目有點多,幾萬量級,又都是正則匹配。每個請求來的時候都會先去看看mapping中有沒有,即使mapping使用的是hash的方式也不免會讓我對它的效能產生一些擔憂,所以效能測試就必須要來一發了。

測試方案:

  1. 在新機器上跑helloworld
  2. 自動生成隨機100個url-mapping,都重定向到helloworld
  3. 使用abtest分別對helloworld和隨機url作壓測
  4. 增大url-mapping的條目,重複1,2

壓測機器

臨時租了兩臺阿里雲伺服器(因為是臨時的,所以我也就不在意在後文暴露ip了),配置都是:1核,2048M記憶體,40G硬碟。一臺用作nginx和helloworld程式,一臺專門做abtest。

:abtest也在阿里雲執行只要是為了在一個資料中心降低網路延遲。最後發現效果真不錯,rps從100多直接飆升到2700多。

helloworld

採用了nodejs的helloworld:

url-mapping

生成urlmapping寫了一個python指令碼:

nginx配置:

abtest

rps測試(request per second):併發壓測使用100000次請求,併發100個使用者的方式。

mapping條目 直接訪問(rps) map第一條url(rps) map最後一條url(rps) 不存在的url(rps)
100 2829.44 1819.63 1765.25 9740.53
1000 1816.00 1509.52 4094.68
10000 1813.22 514.24 658.32
100000 1836.02 62.40 65.80

跟預想的一樣,mapping的條目確實會對請求效率產生影響。而且幾萬條的對映在較高併發的情況下已經到了勉強能用的臨界了。還好以後mapping的條目不會再增加了,並且論壇的併發很難到100的量級。

tpr測試(time per request):因為考慮到伺服器比較穩定,減少壓測總數。同時把併發使用者減為1個。

mapping條目 直接訪問(ms) map第一條url(ms) map最後一條url(ms) 不存在的url(ms)
100 0.690 0.922 0.933 0.507
1000 0.925 1.043 0.648
10000 0.921 2.340 1.915
100000 0.926 16.321 15.469

在併發不是很高的時候mapping的條目可以更多。100000個條目大概只會影響整個請求15ms左右,可以忽略不計。如果說150ms的延遲是可以接受的,那麼在一個併發不是很高的情況下,mapping最多可以有100w條,還是很多的。

測試中的不足

  1. 壓測的url請求並不隨機
  2. 所有的url都被重定向到一個地方。不過從結果來看,nginx確實是根據條目一個個請求的。這點倒沒有什麼影響
  3. 沒有測試http://hostname/path?param=xxx這樣型別的url

相關文章