在使用 JGroups、MantaRay 等分散式通訊框架時,常遭遇 IPv6 導致的連線失敗、綁定異常等問題。傳統做法是作業系統層面停用 IPv6 協議,但這屬於「蹩腳方案」,影響面廣且難以維運。Java 提供標準系統屬性即可優雅解決。
啟動 JVM 時加入以下系統屬性:
-Djava.net.preferIPv4Stack=true
java -Djava.net.preferIPv4Stack=true -jar app.jarJAVA_OPTS 或 CATALINA_OPTS(Tomcat)中添加。ENV JAVA_OPTS="-Djava.net.preferIPv4Stack=true" 或 docker-compose environment 變數。
java.net.preferIPv4Stack(default: false)
若作業系統支援 IPv6,底層原生 Socket 預設為 IPv6 Socket,允許 Java 應用同時連接/接受 IPv4 與 IPv6 主機。
若應用僅需使用 IPv4 Socket,設定此屬性為true即可強制使用 IPv4 棧。
| 場景 | 現象 | 驗證方式 |
|---|---|---|
| JGroups 叢集組播失敗 | 無法形成叢集、組播包丟失 | 啟動參數加入後,日誌顯示綁定 IPv4 位址 |
| MantaRay/RMQ 連線超時 | Broker 連線嘗試 IPv6 失敗 | netstat -an 觀察 LISTEN 為 0.0.0.0:port 而非 :::port |
| Docker 容器網路模式 | 宿主機 IPv6 未啟用導致綁定失敗 | 容器內 java.net.InetAddress.getLocalHost() 返回 IPv4 |
-Djava.net.preferIPv4Addresses=true(優先使用 IPv4 位址,但仍保留 IPv6 棧)。java.net.NetUtils 程式化控制,但啟動參數仍為最通用做法。一行啟動參數解決 Java 網路程式 IPv6 兼容性難題,無需修改代碼、無需調整作業系統設定,是分散式系統、微服務、中介軟體開發的必備運維知識。