研究網路卡地址註冊時的一點思考
本文轉載自公眾號kiritomoe,不僅僅學習結果,更多的是學習優秀的人是如何思考。
我曾經寫過一篇和本文標題類似的文章《研究優雅停機時的一點思考》,上文和本文都有一個共同點:網路卡地址註冊和優雅停機都是一個很小的知識點,但是背後牽扯到的知識點卻是龐大的體系,我在寫這類文章前基本也和大多數讀者一樣,處於“知道有這麼個東西,但不瞭解細節”的階段,但一旦深挖,會感受到其中的奇妙,並有機會接觸到很多平時不太關注的知識點。
另外,我還想介紹一個叫做”元閱讀“的技巧,可能這個詞是我自己造的,也有人稱之為”超視角閱讀“。其內涵指的是,普通讀者從我的文章中學到的是某個知識點,而元閱讀者從我的文章中可能會額外關注,我是如何掌握某個知識點的,在一個知識點的學習過程中我關注了哪些知識點相關的點,又是如何將他們聯絡在一起,最終形成一個體系的。這篇文章就是一個典型的例子,我會對一些點進行發散,大家可以嘗試著跟我一起來思考”網路卡地址註冊“這個問題。
1 如何選擇合適的網路卡地址
可能相當一部分人還不知道我這篇文章到底要講什麼,我說個場景,大家應該就明晰了。在分散式服務呼叫過程中以 Dubbo 為例,服務提供者往往需要將自身的 IP 地址上報給註冊中心,供消費者去發現。在大多數情況下 Dubbo 都可以正常工作,但你如果留意過 Dubbo 的 github issue,其實有不少人反饋:Dubbo Provider 註冊了錯誤的 IP。如果你能立刻聯想到:多網路卡、內外網地址共存、VPN、虛擬網路卡等關鍵詞,那我建議你一定要繼續將本文看下去,因為我也想到了這些,它們都是本文所要探討的東西!那麼“如何選擇合適的網路卡地址”呢?Dubbo 現有的邏輯到底算不算完備?是否有改進措施?我們不急著回答它,而是帶著這些問題一起來進行研究,相信到文末,其中答案,各位看官自有評說。
2 Dubbo 是怎麼做的
Dubbo 獲取網路卡地址的邏輯在各個版本中也是千迴百轉,走過彎路,也做過最佳化,我們用最新的 2.7.2-SNAPSHOT 版本來介紹,在看以下原始碼時,大家可以懷著質疑的心態去閱讀,在 dubbo github 的 master 分支可以獲取原始碼。獲取 localhost 的邏輯位於 org.apache.dubbo.common.utils.NetUtils#getLocalAddress0()
之中
private static InetAddress getLocalAddress0() {
InetAddress localAddress = null;
// 首先嚐試獲取 /etc/hosts 中 hostname 對應的 IP
localAddress = InetAddress.getLocalHost();
Optional<InetAddress> addressOp = toValidAddress(localAddress);
if (addressOp.isPresent()) {
return addressOp.get();
}
// 沒有找到適合註冊的 IP,則開始輪詢網路卡
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
if (null == interfaces) {
return localAddress;
}
while (interfaces.hasMoreElements()) {
NetworkInterface network = interfaces.nextElement();
Enumeration<InetAddress> addresses = network.getInetAddresses();
while (addresses.hasMoreElements()) {
// 返回第一個匹配的適合註冊的 IP
Optional<InetAddress> addressOp = toValidAddress(addresses.nextElement());
if (addressOp.isPresent()) {
return addressOp.get();
}
}
}
return localAddress;
}
Dubbo 這段獲取 localhost 的邏輯大致分成了兩步
先去 /etc/hosts 檔案中找 hostname 對應的 IP 地址,找到則返回;找不到則轉 2
輪詢網路卡,尋找合適的 IP 地址,找到則返回;找不到返回 null,再 getLocalAddress0 外側還有一段邏輯,如果返回 null,則註冊 127.0.0.1 這個本地迴環地址
首先強調下,這段邏輯並沒有太大的問題,先別急著挑刺,讓我們來分析下其中的一些細節,並進行驗證。
2.1 嘗試獲取 hostname 對映 IP
Dubbo 首先選取的是 hostname 對應的 IP,在原始碼中對應的 InetAddress.getLocalHost();
在 *nix
系統實際部署 Dubbo 應用時,可以首先使用 hostname
命令獲取主機名
xujingfengdeMacBook-Pro:~ xujingfeng$ hostnamexujingfengdeMacBook-Pro.local
緊接著在 /etc/hosts
配置 IP 對映,為了驗證 Dubbo 的機制,我們隨意為 hostname 配置一個 IP 地址
127.0.0.1 localhost1.2.3.4 xujingfengdeMacBook-Pro.local
接著呼叫 NetUtils.getLocalAddress0()
進行驗證,控制檯列印如下:
xujingfengdeMacBook-Pro.local/1.2.3.4
2.2 判定有效的 IP 地址
在 toValidAddress 邏輯中,Dubbo 存在以下邏輯判定一個 IP 地址是否有效
private static Optional<InetAddress> toValidAddress(InetAddress address) { if (address instanceof Inet6Address) { Inet6Address v6Address = (Inet6Address) address; if (isValidV6Address(v6Address)) { return Optional.ofNullable(normalizeV6Address(v6Address)); } } if (isValidV4Address(address)) { return Optional.of(address); } return Optional.empty();}
依次校驗其符合 Ipv6 或者 Ipv4 的 IP 規範,對於 Ipv6 的地址,見如下程式碼:
static boolean isValidV6Address(Inet6Address address) { boolean preferIpv6 = Boolean.getBoolean("java.net.preferIPv6Addresses"); if (!preferIpv6) { return false; } try { return address.isReachable(100); } catch (IOException e) { // ignore } return false;}
首先獲取 java.net.preferIPv6Addresses
引數,其預設值為 false,鑑於大多數應用並沒有使用 Ipv6 地址作為理想的註冊 IP,這問題不大,緊接著透過 isReachable 判斷網路卡的連通性。例如一些網路卡可能是 VPN/虛擬網路卡的地址,如果沒有配置路由表,往往無法連通,可以將之過濾。
對於 Ipv4 的地址,見如下程式碼:
static boolean isValidV4Address(InetAddress address) { if (address == null || address.isLoopbackAddress()) { return false; } String name = address.getHostAddress(); boolean result = (name != null && IP_PATTERN.matcher(name).matches() && !Constants.ANYHOST_VALUE.equals(name) && !Constants.LOCALHOST_VALUE.equals(name)); return result;}
對比 Ipv6 的判斷,這裡我們已經發現前後不對稱的情況了
Ipv4 相比 Ipv6 的邏輯多了 Ipv4 格式的正則校驗、本地迴環地址校驗、ANYHOST 校驗
Ipv4 相比 Ipv6 的邏輯少了網路卡連通性的校驗
大家都知道,Ipv4 將 127.0.0.1 定為本地迴環地址, Ipv6 也存在迴環地址:0:0:0:0:0:0:0:1 或者表示為 ::1。改進建議也很明顯,我們放到文末統一總結。
2.3 輪詢網路卡
如果上述地址獲取為 null 則進入輪詢網路卡的邏輯(例如 hosts 未指定 hostname 的對映或者 hostname 配置成了 127.0.0.1 之類的地址便會導致獲取到空的網路卡地址),輪詢網路卡對應的原始碼是 NetworkInterface.getNetworkInterfaces()
,這裡面涉及的知識點就比較多了,支撐起了我寫這篇文章的素材,Dubbo 的邏輯並不複雜,進行簡單的校驗,返回第一個可用的 IP 即可。
性子急的讀者可能忍不住了,多網路卡!合適的網路卡可能不止一個,Dubbo 怎麼應對呢?按道理說,我們也替 Dubbo 說句公道話,客官要不你自己指定下?我們首先對於多網路卡的場景達成一致看法,我們們才能繼續把這篇文章完成下去:我們只能儘可能過濾那些“不對”的網路卡。Dubbo 看樣子對所有網路卡是一視同仁了,我們是不是可以嘗試最佳化一下其中的邏輯呢?
許多開源的服務治理框架在 stackoverflow 或者其 issue 中,註冊錯 IP 相關的問題都十分高頻,大多數都是輪詢網路卡出了問題。既然事情發展到這兒,勢必需要了解一些網路、網路卡的知識,我們才能過濾掉那些明顯不適合 RPC 服務註冊的 IP 地址了。
3 Ifconfig 介紹
我並沒有想要讓大家對後續的內容望而卻步,特地選擇了這個大家最熟悉的 Linux 命令!對於那些吐槽:“天吶,都 2019 年了,你怎麼還在用 net-tools/ifconfig,iproute2/ip 瞭解一下”的言論,請大家視而不見。無論你使用的是 mac,還是 linux,都可以使用它去 CRUD 你的網路卡配置。
3.1 常用指令
啟動關閉指定網路卡:
ifconfig eth0 upifconfig eth0 down
ifconfig eth0 up
為啟動網路卡 eth0, ifconfig eth0 down
為關閉網路卡 eth0。ssh 登陸 linux 伺服器操作的使用者要小心執行這個操作了,千萬不要蠢哭自己。不然你下一步就需要去 google:“禁用 eth0 網路卡後如何遠端連線 Linux 伺服器” 了。
為網路卡配置和刪除IPv6地址:
ifconfig eth0 add 33ffe:3240:800:1005::2/64 #為網路卡eth0配置IPv6地址ifconfig eth0 del 33ffe:3240:800:1005::2/64 #為網路卡eth0刪除IPv6地址
用 ifconfig 修改 MAC 地址:
ifconfig eth0 hw ether 00:AA:BB:CC:dd:EE
配置 IP 地址:
[root@localhost ~]# ifconfig eth0 192.168.2.10[root@localhost ~]# ifconfig eth0 192.168.2.10 netmask 255.255.255.0[root@localhost ~]# ifconfig eth0 192.168.2.10 netmask 255.255.255.0 broadcast 192.168.2.255
啟用和關閉arp協議:
ifconfig eth0 arp #開啟網路卡eth0 的arp協議ifconfig eth0 -arp #關閉網路卡eth0 的arp協議
設定最大傳輸單元:
ifconfig eth0 mtu 1500 #設定能透過的最大資料包大小為 1500 bytes
3.2 檢視網路卡資訊
在一臺 ubuntu 上執行 ifconfig-a
ubuntu@VM-30-130-ubuntu:~$ ifconfig -a
eth0 Link encap:Ethernet HWaddr 52:54:00:a9:5f:ae
inet addr:10.154.30.130 Bcast:10.154.63.255 Mask:255.255.192.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:149673 errors:0 dropped:0 overruns:0 frame:0
TX packets:152271 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:15205083 (15.2 MB) TX bytes:21386362 (21.3 MB)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
docker0 Link encap:Ethernet HWaddr 02:42:58:45:c1:15
inet addr:172.17.0.1 Bcast:172.17.255.255 Mask:255.255.0.0
UP BROADCAST MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
tun0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
UP POINTOPOINT NOARP MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:100
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
為了防止駭客對我的 Linux 發起攻擊,我還是偷偷對 IP 做了一點“改造”,請不要為難一個趁著打折+組團購買廉價雲伺服器的小夥子。對於部門網路卡的詳細解讀:
eth0 表示第一塊網路卡, 其中 HWaddr 表示網路卡的實體地址,可以看到目前這個網路卡的實體地址(MAC 地址)是 02:42:38:52:70:54
inet addr 用來表示網路卡的 IP 地址,此網路卡的 IP 地址是 10.154.30.130,廣播地址, Bcast: 172.18.255.255,掩碼地址 Mask:255.255.0.0
lo 是表示主機的迴環地址,這個一般是用來測試一個網路程式,但又不想讓區域網或外網的使用者能夠檢視,只能在此臺主機上執行和檢視所用的網路介面。比如把 HTTPD 伺服器的指定到回壞地址,在瀏覽器輸入 127.0.0.1 就能看到你所架 WEB 網站了。但只是你能看得到,區域網的其它主機或使用者無從知曉。
第一行:連線型別:Ethernet(乙太網)HWaddr(硬體mac地址)
第二行:網路卡的IP地址、子網、掩碼
第三行:UP(代表網路卡開啟狀態)RUNNING(代表網路卡的網線被接上)MULTICAST(支援組播)MTU:1500(最大傳輸單元):1500位元組(ipconfig 不加 -a 則無法看到 DOWN 的網路卡)
第四、五行:接收、傳送資料包情況統計
第七行:接收、傳送資料位元組數統計資訊。
緊接著的兩個網路卡 docker0,tun0 是怎麼出來的呢?我在我的 ubuntu 上裝了 docker 和 openvpn。這兩個東西應該是日常干擾我們做服務註冊時的罪魁禍首了,當然,也有可能存在 eth1 這樣的第二塊網路卡。ifconfig -a 看到的東西就對應了 JDK 的 api : NetworkInterface.getNetworkInterfaces()
。我們簡單做個總結,大致有三個干擾因素
以 docker 網橋為首的虛擬網路卡地址,畢竟這東西這麼火,怎麼也得單獨列出來吧?
以 TUN/TAP 為代表的虛擬網路卡地址,多為 VPN 場景
以 eth1 為代表的多網路卡場景,有錢就可以裝多網路卡了!
我們後續的篇幅將針對這些場景做分別的介紹,力求讓大家沒吃過豬肉,起碼看下豬怎麼跑的。
4 干擾因素一:Docker 網橋
熟悉 docker 的朋友應該知道 docker 會預設建立一個 docker0 的網橋,供容器例項連線。如果嫌預設的網橋不夠直觀,我們可以使用 bridge 模式自定義建立一個新的網橋:
ubuntu@VM-30-130-ubuntu:~$ docker network create kirito-bridgea38696dbbe58aa916894c674052c4aa6ab32266dcf6d8111fb794b8a344aa0d9ubuntu@VM-30-130-ubuntu:~$ ifconfig -abr-a38696dbbe58 Link encap:Ethernet HWaddr 02:42:6e:aa:fd:0c inet addr:172.19.0.1 Bcast:172.19.255.255 Mask:255.255.0.0 UP BROADCAST MULTICAST MTU:1500 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
使用 docker network 指令建立網橋之後,自動建立了對應的網路卡,我只給出了 ifconfig-a
的增量返回部分,可以看出多了一個 br-a38696dbbe58 的網路卡。
我有意區分了“網橋”和“網路卡”,可以使用 bridge-utils/brctl 來檢視網橋資訊:
ubuntu@VM-30-130-ubuntu:~$ sudo brctl showbridge name bridge id STP enabled interfacesbr-a38696dbbe58 8000.02426eaafd0c nodocker0 8000.02425845c215 no
網橋是一個虛擬裝置,這個裝置只有 brctl show 能看到,網橋建立之後,會自動建立一個同名的網路卡,並將這個網路卡加入網橋。
5 干擾因素二:TUN/TAP 虛擬網路裝置
平時我們所說的虛擬網路卡、虛擬機器,大致都跟 TUN/TAP 有關。我的讀者大多數是 Java 從業者,相信我下面的內容並沒有太超綱,不要被陌生的名詞唬住。對於被唬住的讀者,也可以直接跳過 5.1~5.3,直接看 5.4 的實戰。
5.1 真實網路卡工作原理
上圖中的 eth0 表示我們主機已有的真實的網路卡介面 (interface)。
網路卡介面 eth0 所代表的真實網路卡透過網線(wire)和外部網路相連,該物理網路卡收到的資料包會經由介面 eth0 傳遞給核心的網路協議棧(Network Stack)。然後協議棧對這些資料包進行進一步的處理。
對於一些錯誤的資料包,協議棧可以選擇丟棄;對於不屬於本機的資料包,協議棧可以選擇轉發;而對於確實是傳遞給本機的資料包,而且該資料包確實被上層的應用所需要,協議棧會透過 Socket API 告知上層正在等待的應用程式。
5.2 TUN 工作原理
我們知道,普通的網路卡是透過網線來收發資料包的話,而 TUN 裝置比較特殊,它透過一個檔案收發資料包。
如上圖所示,tunX 和上面的 eth0 在邏輯上面是等價的, tunX 也代表了一個網路介面,雖然這個介面是系統透過軟體所模擬出來的.
網路卡介面 tunX 所代表的虛擬網路卡透過檔案 /dev/tunX 與我們的應用程式(App) 相連,應用程式每次使用 write 之類的系統呼叫將資料寫入該檔案,這些資料會以網路層資料包的形式,透過該虛擬網路卡,經由網路介面 tunX 傳遞給網路協議棧,同時該應用程式也可以透過 read 之類的系統呼叫,經由檔案 /dev/tunX 讀取到協議棧向 tunX 傳遞的所有資料包。
此外,協議棧可以像操縱普通網路卡一樣來操縱 tunX 所代表的虛擬網路卡。比如說,給 tunX 設定 IP 地址,設定路由,總之,在協議棧看來,tunX 所代表的網路卡和其他普通的網路卡區別不大,當然,硬要說區別,那還是有的,那就是 tunX 裝置不存在 MAC 地址,這個很好理解,tunX 只模擬到了網路層,要 MAC *地址沒有任何意義。當然,如果是 *tapX 的話,在協議棧的眼中,tapX 和真實網路卡沒有任何區別。
是不是有些懵了?我是誰,為什麼我要在這篇文章裡面學習 TUN!因為我們常用的 VPN 基本就是基於 TUN/TAP 搭建的,如果我們使用 TUN 裝置搭建一個基於 UDP 的 VPN ,那麼整個處理過程可能是這幅樣子:
5.3 TAP 工作原理
TAP 裝置與 TUN 裝置工作方式完全相同,區別在於:
TUN 裝置是一個三層裝置,它只模擬到了 IP 層,即網路層 我們可以透過 /dev/tunX 檔案收發 IP 層資料包,它無法與物理網路卡做 bridge,但是可以透過三層交換(如 ip_forward)與物理網路卡連通。可以使用
ifconfig
之類的命令給該裝置設定 IP 地址。TAP 裝置是一個二層裝置,它比 TUN 更加深入,透過 /dev/tapX 檔案可以收發 MAC 層資料包,即資料鏈路層,擁有 MAC 層功能,可以與物理網路卡做 bridge,支援 MAC 層廣播。同樣的,我們也可以透過
ifconfig
之類的命令給該裝置設定 IP 地址,你如果願意,我們可以給它設定 MAC 地址。
關於文章中出現的二層,三層,我這裡說明一下,第一層是物理層,第二層是資料鏈路層,第三層是網路層,第四層是傳輸層。
5.4 openvpn 實戰
openvpn 是 Linux 上一款開源的 vpn 工具,我們透過它來複現出影響我們做網路卡選擇的場景。
安裝 openvpn
sudo apt-get install openvpn
安裝一個 TUN 裝置:
ubuntu@VM-30-130-ubuntu:~$ sudo openvpn --mktun --dev tun0Mon Apr 29 22:23:31 2019 TUN/TAP device tun0 openedMon Apr 29 22:23:31 2019 Persist state set to: ON
安裝一個 TAP 裝置:
ubuntu@VM-30-130-ubuntu:~$ sudo openvpn --mktun --dev tap0Mon Apr 29 22:24:36 2019 TUN/TAP device tap0 openedMon Apr 29 22:24:36 2019 Persist state set to: ON
執行 ifconfig-a
檢視網路卡,只給出增量的部分:
tap0 Link encap:Ethernet HWaddr 7a:a2:a8:f1:6b:df
BROADCAST MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:100
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
tun0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
inet addr:10.154.30.131 P-t-P:10.154.30.131 Mask:255.255.255.255
UP POINTOPOINT NOARP MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:100
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
這樣就解釋了文章一開始為什麼會有 tun0 這樣的網路卡了。這裡讀者可能會有疑惑,使用 ifconfig 不是也可以建立 tap 和 tun 網路卡嗎?當然啦,openvpn 是一個 vpn 工具,只能建立名為 tunX/tapX 的網路卡,其遵守著一定的規範,ifconfig 可以隨意建立,但沒人認那些隨意建立的網路卡。
6 干擾因素三:多網路卡
這個沒有太多好說的,有多張真實的網路卡,從普哥那兒搞到如上的 IP 資訊。
7 MAC 下的差異
雖然 ifconfig 等指令是 *nux 通用的,但是其展示資訊,網路卡相關的屬性和命名都有較大的差異。例如這是我 MAC 下執行 ifconfig-a
的返回:
xujingfengdeMacBook-Pro:dubbo-in-action xujingfeng$ ifconfig -alo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384 options=1203<RXCSUM,TXCSUM,TXSTATUS,SW_TIMESTAMP> inet 127.0.0.1 netmask 0xff000000 inet6 ::1 prefixlen 128 inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1 nd6 options=201<PERFORMNUD,DAD>gif0: flags=8010<POINTOPOINT,MULTICAST> mtu 1280stf0: flags=0<> mtu 1280XHC0: flags=0<> mtu 0XHC20: flags=0<> mtu 0en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500 ether 88:e9:fe:88:a0:76 inet6 fe80::1cab:f689:60d1:bacb%en0 prefixlen 64 secured scopeid 0x6 inet 30.130.11.242 netmask 0xffffff80 broadcast 30.130.11.255 nd6 options=201<PERFORMNUD,DAD> media: autoselect status: activep2p0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 2304 ether 0a:e9:fe:88:a0:76 media: autoselect status: inactiveawdl0: flags=8943<UP,BROADCAST,RUNNING,PROMISC,SIMPLEX,MULTICAST> mtu 1484 ether 66:d2:8c:8c:dd:85 inet6 fe80::64d2:8cff:fe8c:dd85%awdl0 prefixlen 64 scopeid 0x8 nd6 options=201<PERFORMNUD,DAD> media: autoselect status: activeen1: flags=8963<UP,BROADCAST,SMART,RUNNING,PROMISC,SIMPLEX,MULTICAST> mtu 1500 options=60<TSO4,TSO6> ether aa:00:d0:13:0e:01 media: autoselect <full-duplex> status: inactiveen2: flags=8963<UP,BROADCAST,SMART,RUNNING,PROMISC,SIMPLEX,MULTICAST> mtu 1500 options=60<TSO4,TSO6> ether aa:00:d0:13:0e:00 media: autoselect <full-duplex> status: inactivebridge0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500 options=63<RXCSUM,TXCSUM,TSO4,TSO6> ether aa:00:d0:13:0e:01 Configuration: id 0:0:0:0:0:0 priority 0 hellotime 0 fwddelay 0 maxage 0 holdcnt 0 proto stp maxaddr 100 timeout 1200 root id 0:0:0:0:0:0 priority 0 ifcost 0 port 0 ipfilter disabled flags 0x2 member: en1 flags=3<LEARNING,DISCOVER> ifmaxaddr 0 port 9 priority 0 path cost 0 member: en2 flags=3<LEARNING,DISCOVER> ifmaxaddr 0 port 10 priority 0 path cost 0 nd6 options=201<PERFORMNUD,DAD> media: <unknown type> status: inactiveutun0: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> mtu 2000 inet6 fe80::3fe0:3e8b:384:9968%utun0 prefixlen 64 scopeid 0xc nd6 options=201<PERFORMNUD,DAD>utun1: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> mtu 1380 inet6 fe80::7894:3abc:5abd:457d%utun1 prefixlen 64 scopeid 0xd nd6 options=201<PERFORMNUD,DAD>
內容很多,我挑幾點差異簡述下:
內容展示形式不一樣,沒有 Linux 下的接收、傳送資料位元組數等統計資訊
真實網路卡的命名不一樣:eth0 -> en0
虛擬網路卡的命名格式不一樣:tun/tap -> utun
對於這些常見網路卡命名的解讀,我摘抄一部分來自 stackoverflow 的回答:
In arbitrary order of my familarity / widespread relevance:
lo0
is loopback.
en0
at one point "ethernet", now is WiFi (and I have no idea what extraen1
oren2
are used for).
fw0
is the FireWire network interface.
stf0
is an IPv6 to IPv4 tunnel interface to support the transition from IPv4 to the IPv6 standard.
gif0
is a more generic tunneling interface [46]-to-[46].
awdl0
is Apple Wireless Direct Link
p2p0
is related to AWDL features. Either as an old version, or virtual interface with different semantics thanawdl
.
the "Network" panel in System Preferences to see what network devices "exist" or "can exist" with current configuration.
many VPNs will add additional devices, often "utun#" or "utap#" following TUN/TAP (L3/L2)virtual networking devices.
use
netstat-nr
to see how traffic is currently routed via network devices according to destination.interface naming conventions started in BSD were retained in OS X / macOS, and now there also additions.
8 Dubbo 改進建議
我們進行了以上探索,算是對網路卡有了一點了解了。回過頭來看看 Dubbo 的獲取網路卡的邏輯,是否可以做出改進呢?
Dubbo Action 1:
保持 Ipv4 和 Ipv6 的一致性校驗。為 Ipv4 增加連通性校驗;為 Ipv6 增加 LoopBack 和 ANYHOST 等校驗。
Dubbo Action 2:
NetworkInterface network = interfaces.nextElement();if (network.isLoopback() || network.isVirtual() || !network.isUp()) { continue;}
JDK 提供了以上的 API,我們可以利用起來,過濾一部分一定不正確的網路卡。
Dubbo Action 3:
我們本文花了較多的篇幅介紹了 docker 和 TUN/TAP 兩種場景導致的虛擬網路卡的問題,算是較為常見的一個影響因素,雖然他們的命名具有固定性,如 docker0、tunX、tapX,但我覺得透過網路卡名稱的判斷方式去過濾註冊 IP 有一些 hack,所以不建議 dubbo contributor 提出相應的 pr 去增加這些 hack 判斷,儘管可能會對判斷有所幫助。
對於真實多網路卡、內外網 IP 共存的場景,不能僅僅是框架側在做努力,使用者也需要做一些事,就像愛情一樣,我可以主動一點,但你也得反饋,才能發展出故事。
Dubbo User Action 1:
可以配置 /etc/hosts
檔案,將 hostname 對應的 IP 顯示配置進去。
Dubbo User Action 2:
可以使用啟動引數去顯示指定註冊的 IP:
-DDUBBO_IP_TO_REGISTRY=1.2.3.4
也可以指定 Dubbo 服務繫結在哪塊網路卡上:
-DDUBBO_IP_TO_BIND=1.2.3.4
9 參考文章
TUN/TAP 裝置淺析
what-are-en0-en1-p2p-and-so-on-that-are-displayed-after-executing-ifconfig
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31555607/viewspace-2643032/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- bond 雙網路卡(兩網路卡使用同一個地址)(Redhat5.5)Redhat
- linux更改網路卡的mac地址LinuxMac
- 一個網路卡下設定兩個ip地址
- 如果修改VMware下的網路卡MAC地址Mac
- 如何修改linux的網路卡mac地址LinuxMac
- ffmpeg分析系列之一(註冊該註冊的)
- 【SpringBoot】服務對註冊中心的註冊時機Spring Boot
- WebStorm mac 下載地址及註冊碼WebORMMac
- 外商投資企業變更註冊地址
- oracle取客戶端網路卡地址Oracle客戶端
- Linux下一塊網路卡設定多個IP地址Linux
- SCO一個網路卡上面繫結多個IP地址(轉)
- [轉]怎樣檢視區域網內其他機器的網路卡實體地址及查詢本機的網路卡實體地址
- 用ollyDbg尋找VB程式的註冊核心的一點思路
- intel 82754L網路卡修改MAC地址IntelMac
- APP註冊這點事兒APP
- 一張網路卡:同時使用千兆和萬兆網路
- 物聯網路卡的優缺點
- 電子郵件地址註冊過程詳解
- MyEclipse 8.5 官方下載地址及其註冊碼Eclipse
- 【SpringCloud】consul註冊中心註冊的服務為內網(區域網)IPSpringGCCloud內網
- 註冊時間差計算
- BeanDefinition註冊流程、spring 擴充套件點一(NamespaceHandler)BeanSpring套件namespace
- 網路精確時鐘 2.25註冊演算法分析演算法
- redo與undo的一點點思考
- Android外掛化研究代ACTIVITY註冊Android
- 註冊中心 Eureka 原始碼解析 —— 應用例項註冊發現(一)之註冊原始碼
- 遊戲安全的一點思考遊戲
- 政府網站域名有什麼特點?如何註冊政府網站域名?網站
- Windows下換網路卡IP地址佔用的解決(轉)Windows
- 什麼是物聯網路卡?物聯網路卡的優點是什麼?
- Windows下單網路卡繫結多個IP地址Windows
- AIX中為單網路卡配置多IP地址(轉)AI
- 索引表和 ES 的一點點思考索引
- Linux作業系統獲取網路卡初始的MAC地址Linux作業系統Mac
- 修改VMware虛擬機器網路卡MAC地址的方法總結虛擬機Mac
- 入行兩年的一點思考
- 我對人生的一點思考