問題背景
當一個服務完成部署並取得網域名稱之後,最常見的問題之一就是「服務無法被呼叫」。例如 API request 無法連線、瀏覽器無法打開網站、或是某些服務在內網或外網環境下突然失效。
這類問題在實務上非常常見,而排查的關鍵是先確認網路連線的每一層是否正常。
網路問題通常可以依照 OSI 模型的層級逐步排查。從最底層的名稱解析開始,到 IP 連線、port 開啟狀態,再到 HTTP 與應用層服務。只要建立清楚的排查順序,就可以快速縮小問題範圍。
Source: https://stackoverflow.com/questions/67094784/osi-model-layer
在實務排查中,可以建立一個簡單但非常有效的檢查流程:
DNS
↓
Network Layer: ping
↓
Transport Layer (test port): nc / telnet
↓
Application Layer (test HTTP): curl
這個流程的核心概念是:每一個工具都在檢查不同的網路層級,因此它們的成功或失敗代表的意義完全不同。
第一步:確認 DNS 是否能解析
當服務無法連線時,第一件要確認的事情是「hostname 是否能被解析成 IP 位址」。這個步驟通常透過 nslookup 進行。
nslookup google.com如果查詢成功,通常會得到類似以下的結果:
Name: google.com
Address: 142.250.72.14
這代表 DNS server 知道 google.com 對應到哪個 IP 位址。換句話說,名稱解析是正常的。
需要注意的是,DNS lookup 只負責將 hostname 轉換為 IP 位址,它並不會測試網路是否能夠連線到該主機,也不會確認服務是否存在。因此即使 nslookup 成功,也不代表你可以成功連線到該服務。
另一個常見的誤解是 DNS 與 port 的關係。DNS lookup 的結果並不包含 port 資訊。DNS 只負責名稱解析,而 port 是在後續建立 TCP 或 UDP 連線時,由 client 決定要連到哪個服務。換句話說,port 屬於傳輸層 (Transport Layer) 的概念,而不是 DNS 的職責。
第二步:確認 IP 層的連通性
當 DNS 可以正常解析之後,下一步通常會使用 ping 來確認網路是否能夠到達該 IP。
ping google.comping 的原理是透過 ICMP (Internet Control Message Protocol) 傳送 Echo Request,並等待對方回傳 Echo Reply。只要目標主機回應 ICMP,就代表網路路由可以到達該 IP。
因此
ping成功的意義是:你的電腦可以透過網路到達該 IP,並且對方允許 ICMP 回應。
然而,這裡有一個非常重要的觀念:ping 測試的是 IP 層的連通性,而不是應用服務是否正常。
例如,即使 ping 成功,也無法保證以下事情:
- HTTP server 是否存在
- port 是否開啟
- API 是否可以正常回應
- 某個應用程式是否正在運行
原因是 ping 運作在 Network Layer,它並不涉及 TCP、UDP 或 HTTP,因此也沒有 port 的概念。
這也是為什麼以下指令會失敗:
ping https://www.google.com/
ping: cannot resolve https://www.google.com/: Unknown host
正確的做法是只使用 hostname:
ping www.google.com
為什麼「有 IP 回應」不代表「有伺服器服務」
另一個常見的誤解是:只要 ping 成功,就代表某台 server 正在運行。
實際上,回應 ICMP 的不一定是應用伺服器。只要某個網路設備的 network stack 回應 ICMP,就會被 ping 視為成功。
可能回應 ping 的設備包括:
- 作業系統的 network stack (Linux / Windows)
- Router
- Firewall
- Load balancer
以 google.com 為例,當你執行 ping google.com 時,回應的很可能是 Google 的 edge load balancer,而不是實際提供搜尋服務的 web server。
因此 ping 的結果只能說明網路層是通的,但並不能說明服務層是否正常。
第三步:確認 Transport Layer 的 port 是否開啟
在確認 IP 層連通之後,下一個需要檢查的是 Transport Layer。這一層負責建立 TCP 或 UDP 連線,而服務是否存在,通常取決於某個 port 是否有程式正在 listen。
這個階段常用的工具包括 nc (netcat) 或 telnet。
例如可以測試 HTTPS port 是否開啟:
nc -zv google.com 443
// -z: zero I/O mode 不真正傳送資料只測試 port 是否可以建立連線
// -v: verbose mode
如果成功,通常會看到類似輸出:
Connection to google.com port 443 [tcp/https] succeeded
這代表可以成功建立 TCP 連線,也就是說該主機的 443 port 有服務正在監聽。
如果連線失敗,可能會看到:
Connection refused
Operation timed out
如果系統沒有 nc,也可以使用 telnet:
telnet google.com 443
telnet 成功時會顯示 TCP 連線建立成功,雖然不會解析 HTTP,但足以確認 Transport Layer 是否正常。
這個步驟的重要性在於:即使 ping 成功,也不能保證某個 port 有服務存在。只有當 TCP 連線能成功建立時,才表示該服務可能真的在運行。
第四步:使用 curl 測試 HTTP 與應用層
當 DNS、IP、以及 port 都確認正常之後,下一步就是檢查 HTTP 層。最常用的工具是 curl。
curl 是一個 HTTP client,它會模擬一個完整的 HTTP request。當執行 curl 時,實際上會經過以下幾個步驟:
- DNS lookup
- 建立 TCP 連線
- TLS handshake(如果是 HTTPS)
- 發送 HTTP request
- 接收 HTTP response
例如:
curl [http://authorcontentsource.cmoney.internal](https://www.google.com/)
如果這個指令成功,代表整個連線流程都正常,包括:
- DNS 解析成功
- 網路路由可達
- TCP port 開啟
- HTTP server 正常回應
也就是說,當 curl 成功時,通常可以確認應用層服務是可用的。
使用 curl -v 觀察完整連線流程
在排查問題時,curl -v(verbose mode)非常有幫助,因為它會顯示整個連線過程。
curl -v https://google.com
輸出中通常可以看到類似資訊:
* Host google.com:443 was resolved.
* IPv6: 2404:6800:4012:6::200e
* IPv4: 142.250.204.46
* Trying 142.250.204.46:443...
* Connected to google.com (142.250.204.46) port 443
這些訊息實際上對應不同的網路層:
第一行代表 DNS lookup 已完成,hostname 已經被解析為 IP。
* Host google.com:443 was resolved.
第二行表示 client 正在嘗試建立 TCP 連線到指定的 IP 與 port。
* IPv4: 142.250.204.46
* Trying 142.250.204.46:443...
第三行顯示 TCP 連線成功建立。
* Connected to google.com (142.250.204.46) port 443
接著如果是 HTTPS,會看到 TLS handshake 的過程。
* (304) (OUT), TLS handshake, Client hello (1):
* CAfile: /etc/ssl/cert.pem
* CApath: none
* (304) (IN), TLS handshake, Server hello (2):
* (304) (IN), TLS handshake, Unknown (8):
* (304) (IN), TLS handshake, Certificate (11):
* (304) (IN), TLS handshake, CERT verify (15):
* (304) (IN), TLS handshake, Finished (20):
* (304) (OUT), TLS handshake, Finished (20):
最後則是實際送出的 HTTP request。
透過 curl -v,可以非常清楚地看到從 DNS → TCP → TLS → HTTP 的完整流程,因此在排查連線問題時非常有價值。
建立清楚的排查心智模型
網路問題排查的核心並不是記住很多工具,而是理解每個工具所對應的網路層級。
nslookup 解決的是名稱解析問題。
ping 檢查的是 IP 層的連通性。
nc 或是 telnet 檢查確認傳輸層是否能建立連線。
curl 則是直接測試 HTTP 與應用層服務。
只要按照這樣的順序逐步排查,就能快速判斷問題出在哪一層,而不需要盲目地檢查整個系統。