在製作研修資料、並且依照過去慣例組出 nginx + 應用程式伺服器 的架構時,
我想到了一個曾經好幾次浮現過的疑問:
「在有 ALB 和 CloudFront 的環境裡,為什麼還需要 nginx?」
抱著這個疑問,我決定好好面對並深入探究一下。
我作為工程師接觸的第一個框架是 Ruby on Rails(7 系列)。
當時我學到 nginx + puma 是事實上的標準組合,並且理解 nginx 的角色包含 SSL 終端、靜態檔案提供、負載平衡等。
之後在學 AWS 時,我又知道 ALB 也能做 SSL 終端與負載平衡,前面再加上 CloudFront 的話,也可以提供靜態檔案。
雖然心裡曾經想過「那 nginx 到底是為了什麼而存在」,但一直沒有餘裕深入思考,直到今天才終於正面面對這個問題。
Web 伺服器和應用程式伺服器,本質上都是作為軟體的「伺服器」。
整理之後,再次意識到「伺服器」其實並不是什麼特別的東西。
從內部來看,也只是呼叫 OS 的 socket API(socket → bind → listen → accept)而已。
再次讓我意識到,它其實跟瀏覽器或 Slack 一樣,只是「普通的應用程式」而已。
像這篇文章這樣,我沒有考慮「因為放在哪裡,所以可以歸類成哪一種伺服器」這種話題,而是用比較淺的角度整理。
nginx(Web 伺服器):
puma(應用程式伺服器):
也就是說,並不是「哪一個比較優秀」,而是因為捨棄通用性、改走專精路線,所以才快,本質上是一種取捨。
我再次認識到,nginx 並不是能執行 Ruby 的存在,而是單純在處理 HTTP 這件事上有壓倒性的優勢。
puma 的 worker 是「珍貴的資源」。在處理一個 request 的期間,該 worker 會一直被占用,因此:
把單純、快速、輕量的工作交給專門的伺服器,讓應用程式伺服器專注於商業邏輯。這就是分工的本質,我是這麼理解的。
如果有 ALB + CloudFront,nginx 的許多角色其實都可以被取代:
我問了 AI 之後,據說在 ECS + Fargate + Node.js 或 Go 的架構裡,不再夾 nginx 的案例正在增加(雖然可信度不高就是了……)
如我原本預想的,ALB 也能處理慢速客戶端的 buffering,所以就算應用程式伺服器直接從 ALB 接收 request,似乎也沒什麼問題。
不過,隨著調查深入,我還是覺得能在 nginx 裡自己寫 config 並加以控制,這種感覺很不錯;另外,僅僅為了提供靜態資產就在前面放一層 CDN(CloudFront),也讓我有點抗拒。從個人經驗來說,我不太喜歡不必要地增加快取層。
最後還是會回到:要在哪裡增加「層」,以及想把多少事情交給受管服務,這類問題上。
※ 不過在 Rails + puma 的架構中,基於歷史因素與 puma 的設計理念,現在前面仍然放 nginx 似乎還是主流。