我最近在工作中做一個設(shè)置,我有一個面向用戶的 Nginx 服務(wù),它將訪問轉(zhuǎn)發(fā)到運行在AWS Elastic Load Balancer (如你所知. ELB)上的一個服務(wù)。這本身似乎不是一個困難的任務(wù),你只需要找到 ELB 的主機名,將 ngin x指向它,這樣不就搞定了,對吧?
location/{PRoxy_passhttp://service-1234567890.us-east-1.elb.amazonaws.com;}測試沒有問題,再正確設(shè)置一下防火墻/安全組配置,它就應該可以很好的工作了。幾個小時之后,你可能會發(fā)現(xiàn),服務(wù)不再工作了,盡管沒有做任何改變。直接訪問 ELB 端點是可以工作的,但訪問 Nginx 卻總是超時提醒。

為了弄清楚為什么服務(wù)突然中止,需要先了解一下 ELB 是如何工作的:
當你創(chuàng)建一個彈性負載均衡(Elastic Load Balancer),你將會得到 DNS 的返回記錄,AWS 會告訴你所有在使用的訪問服務(wù)。DNS 記錄是一個輪詢 DNS(round robin DNS)記錄,它指向兩個或更多的 ip 地址——這取決于你有多少可用的區(qū)域。DNS 記錄被設(shè)置成 60 秒的存活時間(time to live),這意味幾乎不會有記錄緩存。
短 TTL 可以讓 AWS 快速改變機器的運行負載,在不中斷服務(wù)的情況下,不會有任何復雜的虛擬 IP 問題。這也是他們特別告訴你不要查找主機名和發(fā)送流量到其中某個 IP 地址的原因,那樣的話,你的服務(wù)可能會在未來某個未定義的時間,IP 地址可能會停止為負載均衡工作。
回到 Nginx問題在于,對于 Nginx 來說,當它讀取到一個配置時,它就會立刻向 DNS 請求主機名,然后使用其結(jié)果,直到下次重新加載配置。在這段時間到來之前,ELB 可能改變 IP 地址,讓你的 Nginx 把請求轉(zhuǎn)發(fā)到一些不為你服務(wù)的地址。
Nginx Plus解決這個問題的方式是為Nginx Plus付費,它添加 resolve 標記對在 upstream 分組上的服務(wù)器進行指示。那就是讓 Nginx 驕傲的 DNS 對 TTL 的記錄,偶爾按順序重新處理記錄,并取得服務(wù)器使用的更新列表。
為這個功能花費每年每服務(wù)器 $1.500,看起來花費很多。當然這是你希望得到 Nginx Plus 帶來的其他功能,如果你不需要它們,這將會是一個昂貴的升級。
免費的選擇一個更加實惠的選擇是寫這樣一個配置:
resolver172.16.0.23;set$upstream_endpointhttp://service-1234567890.us-east-1.elb.amazonaws.com;location/{proxy_pass$upstream_endpoint;}它將會生效并且 Nginx 會遵循記錄 DNS 記錄的 TTL,萬一一個請求進來,會重新解釋它而且緩存的記錄會過期。為什么會這樣?
答案可以在proxy_pass指令文檔結(jié)尾找到,它聲明了:
服務(wù)器名,端口以及傳遞的URI也可以使用變量被指定:
proxy_passhttp://$host$uri;甚至像這樣:
proxy_pass$request;在這個案例中,服務(wù)器名會在所描述的server groups中被查找,如果沒找到,會使用resolver來決定.
當我們給 proxy_pass 提供一個變量的時候,我們基本上是利用其改變行為,但這樣確實需要我們在配置中指定一個 DNS resolver。例子里邊用到的 DNS resolver應該能夠在 AWS 上面跑在默認 VPC或者 EC2 中的所有服務(wù)器工作(適用)。你也可以隨時查看 /etc/resolv.conf 找出哪些 AWS 為你的服務(wù)器提供并使用了哪些 DNS 服務(wù)器。
關(guān)于轉(zhuǎn)發(fā) URI 的 Caveat(警告)如果你在 Nginx 中設(shè)置的 Location 不只是 /,那么你需要注意到當給定一個變量作為參數(shù)時,proxy_pass 細微的改變行為。
先說重要的,快速概括 proxy_pass 如何在正常在操作中工作:
正常的表現(xiàn)行為
設(shè)想我們有一個 Nginx 配置包括這些:
location/foo/{proxy_passhttp://127.0.0.1:8080;}當我們發(fā)送一個 /foo/bar/baz 的請求到這個站點,Nginx 會轉(zhuǎn)發(fā)請求到 http://127.0.0.1:8000/foo/bar/baz。
location/foo/{#Notethetrailingslash↓proxy_passhttp://127.0.0.1:8080/;}Nginx 會在 Location 記錄里邊去掉部分指定的 URI,然后把剩下的部分傳給 upstream 服務(wù)器。所以請求 /foo/bar/baz 會被轉(zhuǎn)發(fā)到 http://127.0.0.1:8080/bar/baz。
改變行為
當我們使用一個變量作為 proxy_pass 的參數(shù)的時候,上面帶有尾部斜杠的行為會改變。例如我們有這樣的配置。
resolver172.16.0.23;set$upstream_endpointhttp://service-1234567890.us-east-1.elb.amazonaws.com/;location/foo/{proxy_pass$upstream_endpoint;}當我們向那個配置發(fā)送請求 /foo/bar/baz,轉(zhuǎn)發(fā)請求將不會去到/并且不是預想中的 /bar/baz。
為此解決方案就是從 upstream 的 endpoint 去掉尾部斜杠,然后像這樣手動重寫:
resolver172.16.0.23;set$upstream_endpointhttp://service-1234567890.us-east-1.elb.amazonaws.com;location/foo/{rewrite^/foo/(.*)/$1break;proxy_pass$upstream_endpoint;}然后當你發(fā)送請求 /foo/bar/baz,upstream 會接受到我們想要的請求 /bar/baz。
結(jié)束語要知道這不單單只適用于設(shè)置用 elb 做 upstream 服務(wù)器,它適用于配置所有在 nginx 做 upstream 服務(wù)器的修改 DNS 配置的情況。
希望這對你有用,如果你有任何建議或者只是想單純聯(lián)系我,用 twitter 聯(lián)系吧Tenzer。
碼農(nóng)必須要加班?NO!
知道碼農(nóng)們都想擺脫加班狗、外賣臉的稱號,所以我們來了!
我們做了一個能讓程序員之間共享知識技能的APP,覺得可以顛覆程序員的工作方 式!
有人說我們癡心妄想,但我們不那么認為。
為了能煽爛說我們癡心妄想的人的臉,現(xiàn)在我們急需程序員業(yè)內(nèi)的牛嗶-人物來給 我們“號脈”!“診斷費”豐厚!畢竟我們不差錢兒,只是想做到最好!
圈圈字典中講到,牛嗶-人物是指群成員數(shù)高于1000人的QQ群主或關(guān)注人數(shù)高于 2000人的貼吧吧主或粉絲人數(shù)高于10000人的微博博主或成員數(shù)高于2000主題貼的版主 或單帖閱讀量高于2000博客主或人脈超級廣的圈內(nèi)紅人。
對于未能達標的未來大神們,我們只能含淚表示:蜀黍,咱們來日方長,這次暫 時不約好嗎?待他日你立地成神,我必生死相依!
來?還是不來?
圈圈互動 接頭暗號:1955246408 (QQ)
新聞熱點
疑難解答