談 HTTP 標頭(header) "Connection: keep-alive" 的作用
Posted on May 22, 2024 in HTTP headers by Amo Chen ‐ 2 min read
根據 HTTP/1.0 版的標準,每 1 個連線都應該在 server 回應(response)完之後關閉,然而 HTTP 是基於 TCP 的通訊協定,每次建立連線都需要做 1 次 TCP 三向交握(Three-way Handshake),因此每載入 1 個新網頁都要重新建立新連線,沒辦法重新利用已建立好的連線,導致 HTTP 1.0 不夠有效率。
所以後來有人在 HTTP/1.0 的基礎上進行擴充,加入 1 項稱為 “keep-alive” 的功能,該功能就是為了讓 server 與 client 都可以重新使用已建立好的連線,避免每個要求都需要重新建立連線。
但畢竟不是每個 server 或 client 都支援這項功能,所以 client 端可以在 HTTP request 的 header 中加入 Connection: keep-alive
,藉此告知伺服器 client 端支援 “keep-alive” 功能,如果伺服器端也支援 “keep-alive” 功能,那麼伺服器也會回傳 Connection: keep-alive
,如此一來雙方都不會關掉連線,隨後的通訊就可以利用已建立好的連線。
p.s. 是的, Connection: keep-alive
並不是 client 專屬, server 與 client 都可能會送這個 header 喔!
之後如果有任何一方想主動關掉連線,則在 HTTP header 加入 Connection: close
告知即可關閉連線。
這就是 “keep-alive” 的故事。
但是到了 HTTP/1.1 之後,規定所有連線都「應該」使用 HTTP persistent connection (其實就是 “keep-alive” ),不過實作上還是會傳送 Connection: keep-alive
,藉此希望 server 或 client 不要關閉連線。
但是 HTTP persistent connection 會有佔用連線的缺點,連線數多的情況下,很可能耗盡 server 所能承受的連線數,所以後來包含 Apache httpd, Nginx 都有設計 Keep-Alive timeout 的機制,透過縮短連線時長將閒置的連線釋放出來給其他 requests 使用,例如 Nginx keepalive_timeout
預設 75 秒,意思這個連線會至少保持 75 秒, 如果這 75 秒之間都沒有任何 request, 就會關閉連線。
Keep-Alive timeout 實際上會透過 Keep-Alive: timeout=<seconds>
header 告知,如果你有看到這個 Keep-Alive
header 就代表 persistent connection 的維持是有條件的。
p.s. Keep-Alive
除了 timeout (時長)還有 max (request 數)可以設定
值得注意的是,Keep-Alive
header 與 Connection: keep-alive
一同設定才會有作用。
說了這麼多,懂 Keep-Alive
有什麼好處?不是都 Nginx, Apache 都已經實作搞定了嗎?
實際上,因為各種開發架構不一定都只使用 Nginx, Apache 等伺服器,舉 Python 為例,後端 server 有可能還會接 gunicorn, hypercorn 等等,而且這些伺服器對於 keep-alive 的設定都不太一樣,舉 gunicorn keep alive timeout 預設為 2s 為例,如果同 1 個 client (不一定是真人)每次都需要重複呼叫某個 API 許多次,但是平均都超過 2s 才會發出下一次的 request, 那麽肯定會造成每次都需要重新建立連線,如果是 requests 數量小的情況,可能無傷大雅,但如果是成千上萬的 requests 數量,勢必會因為這個小小設定影響效能!
大神們有時候只是調整 1 個小小設定,就會帶來效能提升!這其實都是對基礎知識深厚理解的表現。
References
Hypertext Transfer Protocol – HTTP/1.1