最近在家里經常遇到 ssh 超時的問題,一開始也沒太當回事,感覺是網絡不穩定導致的,但是后來慢慢的發現這種超時問題只會出現在跟 ssh 相關的程序中,例如 git、ssh。這成功的引起了我的注意,於是我開始嘗試着去排查。
首先我測試了一下 ping 遠程服務器,發現結果還是比較正常的,所以在 icmp 協議上,連接應該是沒有問題的。然后安裝 tcping
軟件包,測試 tcp 連接,結果顯示也是正常的,那么看起來就是 ssh 協議的問題了。於是接着嘗試讓 ssh 輸出調試信息:
$ ssh -v -o ConnectTimeout=10 test-server
輸出結果如下:
# .....
debug1: SSH2_MSG_KEXINIT sent
debug1: SSH2_MSG_KEXINIT received
debug1: kex: algorithm: curve25519-sha256
debug1: kex: host key algorithm: ecdsa-sha2-nistp256
debug1: kex: server->client cipher: chacha20-poly1305@openssh.com MAC: <implicit> compression: none
debug1: kex: client->server cipher: chacha20-poly1305@openssh.com MAC: <implicit> compression: none
debug1: expecting SSH2_MSG_KEX_ECDH_REPLY
# 一直等待,直到超時
可以看到,ssh 連接的建立一直阻塞在了 expecting
這個階段,用這行命令的輸出在網絡上查找,發現了是 MTU 過大引起的問題: mtu missmatch。
這片文章給出的解決方案是將系統的 MTU 的設置成一個較小的值(例如,576)。使用 ip
命令簡單的執行了一下,發現確實可以解決 ssh 超時的問題:
查看當前的 MTU 設置
$ ip link list
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: wlp4s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DORMANT group default qlen 1000
link/ether ac:bc:32:d4:cd:af brd ff:ff:ff:ff:ff:ff
接着修改無線網卡的 MTU 設置:
$ sudo ip link set dev wlp4s0 mtu 576
但是我的潛意識告訴我這么干並不優雅,於是我在 Arch Wiki 上面找到了這個內容。這里面提到一個內核參數 —— tcp_mtu_probing
,啟用這項內核功能可以讓操作系統根據網絡狀況自動的調節 MTU 大小,從而在性能與穩定性之間找到一個微妙的平衡,具體的介紹可以看 Cloudflare 這篇介紹
只要先在 /etc/sysctl.d/99-sysctl.conf
加上下面的內容:
net.ipv4.tcp_mtu_probing = 1
然后使用 sysctl
加載配置就好了:
$ sudo sysctl --system