最近跟同事 @jackdoe 經常在工作時,討論到各種抽象層 的不必要性。如果希望程式執行效率好,多半的選擇是「大部份的事都不要做」,這樣子執 行起來就快了。

其中經常討論到的就是 HTTP 客戶端的實做,目前多數的函式庫都盡量完整實做 HTTP/1.1 中的 各項規格,函式庫完整雖好,但若伺服端實際只用了很小部份的 HTTP/1.1,那其實有很多部份的 函式庫程式碼是不會執行到的。如果只做必要之事,那想必能有最快的執行速度。

於是就試著做出了 Hijk 這件作品。基本上是個 HTTP 客戶端函式庫,類似於 HTTP::TinyFurl 。但它只實做了讀寫 HTTP Message 這件事,完 全沒有其他的部份。

因此,它並不支援這些 HTTP 表頭所延伸出的各功能:

  • Redirect
  • Proxy
  • Transfer-Encoding, Chunk
  • Content-Encoding

但是這樣的函式庫就足以應付許多資料伺服器。比如,ElasticSearch。在ElasticSearch 伺 服器端生成的 HTTP Message 中,跟本不可能出現前述表頭,因此,客戶端其實也不必費事 解讀。

像 LWP::UserAgent、WWW::Mechanize 這類的 HTTP 客戶端,都是在模擬瀏覽器行為,因此選 擇支援 Referrer 及 Cookie,也支援 HTML 表單編碼等等。但如果伺服器主要的目的是為了 提供資料,這些模擬多半都是多餘的。

用這簡單的效能評測程式 bench-thisurl.pl 來比較處理單次回應所花的時間,Hijk 約是 HTTP::Tiny 的 17%,及 LWP 的 11% 。 (HTTP Server 是 ElasticSearch)

> perl -I ../lib ./bench-thisurl.pl http://localhost:9200/
hijk: Ran 1274 iterations (251 outliers).
hijk: Rounded run time per iteration: 2.9935e-04 +/- 3.4e-07 (0.1%)
httptiny: Ran 1337 iterations (318 outliers).
httptiny: Rounded run time per iteration: 1.7371e-03 +/- 1.8e-06 (0.1%)
lwpua: Ran 1546 iterations (543 outliers).
lwpua: Rounded run time per iteration: 2.6915e-03 +/- 1.4e-06 (0.1%)

Hijk 的 API 該意設計成比較低階,使用起來必需要理解一部份 HTTP 細節才行。但也多虧 了 ElasticSearch 的伺服器端只利用到 HTTP 1.1 的極小部份,才能有辨法擠出這些效能來。