Linux: Nginx proxy_pass域名解析引起的故障

背景

業務架構:前端

clipboard.png

部署細節:
  兩容器均部署在同一機器上,經過 docker-compose 編排,而且經過link方式連接。node

故障描述

在有次更新代碼時,發現前端可以打開,可是全部接口請求全是502(Bad GateWay)python

clipboard.png

故障排查

查看前端容器compose_ui_1的日誌,刷了一大波502(Bad GateWay)nginx

clipboard.png

UI沒問題的話,第一反映就是 compose_api_1 跪了,因此直接去容器看看日誌
clipboard.pngdocker

容器日誌看起來很正常,沒有崩潰,並且這個日誌就好像歷來沒收到請求那樣,可是很明顯我前端確定有訪問的,感受很奇怪。將接口取出來單獨訪問試試看:
clipboard.pngflask

接口單獨訪問結果仍是很殘暴的502(Bad GateWay),感受仍是不太可信,是否是端口或者主機什麼訪問錯誤了?
本機開啓 wireshark 抓包確認下請求的主機和端口:
clipboard.pngsegmentfault

這樣就很確保前端compose_ui_1訪問的主機和端口是正確的,並且確切結果是502(Bad GateWay),這樣只能從compose_api_1下手排查了。後端

以前也是遇到類似的問題,由於compose_api_1是經過uwsgi部署的python flask,那會老是用法以爲有點問題,改過uwsgi配置以後消停了一會。如今又捲土重來了。api

先判斷下compose_api_1是否是真的跪了。。。雖然對這個沒抱什麼但願。。。緩存

直接訪問 後端api 接口
clipboard.png

額。。。尷尬。。。彷彿冤枉錯好人了。這不對吧,抓包看看再次確認下先:
clipboard.png

彷彿真的是。。。再 see see 容器日誌:
clipboard.png

額。。。好吧。。。我錯了,compose_api_1沒跪。

因而問題來了。。。後端接口沒問題,前端訪問出錯了,見鬼了?

有種預感是容器的特性致使的問題。希望不要。。

先進去compose_ui_1容器抓包分析下,看看整個請求鏈有沒有問題:
clipboard.png

彷佛發現了點貓膩,Flags[R.]是表明 tcp連接 被 reset 重置 了,可是爲何無緣無故重置呢?

看到 172.17.0.5.8080 返回的, 先 telnet 問問先:
clipboard.png

What???這就很迷了,首先這個 172.17.0.5.8080 哪來的呢?其次就是爲毛端口不通?

忽然想到一個很重要的問題:

容器之間是怎麼知道它要把請求發給誰呢 ?

在前面已經交代過,這兩個容器是經過 link 的方式連接的,像下面這樣:

clipboard.png

谷歌搜了下 link 工做原理:

link機制經過環境變量的方式提供了這些信息,除此以外像db的密碼這些信息也會經過環境變量提供,docker將source container中定義的環境變量所有導入到received container中,在received container中能夠經過環境變量來獲取鏈接信息。

使用了link機制後,能夠經過指定的名字來和目標容器通訊,這實際上是經過給/etc/hosts中加入名稱和IP的解析關係來實現的

因此就是說在 compose_ui_1 的 根據指定的名字並在 /etc/hosts 翻譯出具體的ip而後進行通訊咯?
看看容器的名字是啥?

clipboard.png

compose_ui_1/etc/hosts

root@e23430ed1ed7:/# cat /etc/hosts
127.0.0.1    localhost
::1    localhost ip6-localhost ip6-loopback
fe00::0    ip6-localnet
ff00::0    ip6-mcastprefix
ff02::1    ip6-allnodes
ff02::2    ip6-allrouters
172.17.0.4    detectapi fc1537d83fdf compose_api_1
172.17.0.3    authapi ff83f8e3adf2 compose_authapi_1
172.17.0.3    authapi_1 ff83f8e3adf2 compose_authapi_1
172.17.0.3    compose_authapi_1 ff83f8e3adf2
172.17.0.4    api_1 fc1537d83fdf compose_api_1
172.17.0.4    compose_api_1 fc1537d83fdf
172.17.0.6    e23430ed1ed7

若是真是按照資料所說,那 172.17.0.4:8080 纔是 compose_api_1 的地址隱射纔對吧?,試下先
clipboard.png
雖然返回了 auth product is None,但其實這是有效的請求。

再看看 compose_api_1 容器的日誌:
clipboard.png

因此基本沒跑了, 爲何前端訪問直接就是 502, 緣由就是 ui容器向錯誤的地址發送請求了

那麼爲何會這樣呢?無緣無故抽風了?

剛纔根據 host 的記錄實驗了,按照它的映地址發起接口請求,是沒有問題的:

查看下 compose_ui_1nginx 日誌
clipboard.png

尷尬。。。 nginx 日誌竟然直接鏈接到標準輸出和標準錯誤。。。
那爲了簡單點,仍是直接用 docker logs 查看吧
clipboard.png

看來 nginx 的轉發已是錯誤的,爲何會轉發到 172.17.0.5, 看看 nginx 關於轉發的配置:
clipboard.png

這個 detectapi 和 上面貼出的 hosts 表能找到正確的地址 172.17.0.4 呀?搞不明白爲何會轉發到 172.17.0.5

難道是系統的域名解析錯誤了?
clipboard.png

尼瑪這真是太神奇了。

男人的直覺告訴我 nginx 有貓膩!

重啓下容器的 nginx,然而容器也被重啓了。。。
clipboard.png

再訪問頁面,竟然能夠了。。。
clipboard.png

再看看容器的nginx日誌,已經轉發成功了
clipboard.png

這樣子的話,其實應該能定位到,問題是出在了 nginx 上面?

故障定位

只是爲何 nginx 會有這樣的錯誤呢?不太應該呀。。 感受應該是 nginx 內部域名解析緩存問題。

而後查了下資料,呵呵,還真有。https://www.zhihu.com/questio...

clipboard.png

這就很是尷尬了。對這個問題抱有點懷疑,諮詢了資深大佬,而後大佬的回覆就是:

若是 proxy_pass 後面跟的域名的話,在 nginx 啓動的時候就會初始化好,之後就只會複用這個值;參考:ngx_http_upstream_init_round_robin 函數
若是 proxy_pass 後面跟的是upstream,配置纔會走解析和緩存的邏輯;

改善措施

  1. 不直接 proxy_pass 真實域名,而是轉發到 upstream 配置;
  2. 也可參考剛纔的知乎連接處理方案:https://www.zhihu.com/questio...

延展問題

  1. 爲何 compose_ui_1 指定的 compose_api_1 會出錯?
  2. proxy_pass 若是後面跟真實域名,是真的直接複用仍是有時間緩存?

原本想用 gdb 調試下這個問題,然而花了一天時間,毛都沒有。不過也有點小收穫,那就是如何配置nginx來支持gdb

1.修改編譯配置文件:auto/cc/conf

ngx_compile_opt="-c"  改爲 ngx_compile_opt="-c -g"

2../configure 時,增長編譯參數:--with-cc-opt='-O0', 避免編譯器優化;
例如:./configure --prefix=/usr/local/nginx --with-cc-opt='-O0' ....
若是不這樣的話,編譯器會優化代碼,致使調試過程當中,循環中的一些變量值沒法打印,會報下面的錯誤:

value optimized out

下面能夠看下調試的效果:
nginx worker process 處理入口:ngx_http_static_handler

clipboard.png
歡迎各位大神指點交流, QQ討論羣: 258498217
轉載請註明來源: https://segmentfault.com/a/11...

相關文章
相關標籤/搜索