自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

追蹤 Kubernetes 中的數(shù)據(jù)包

云計(jì)算 云原生
統(tǒng)計(jì)一下在三個(gè)場(chǎng)景中,經(jīng)過(guò)內(nèi)核網(wǎng)絡(luò)協(xié)議棧的處理次數(shù)都是兩次(包括 netfilter 的處理。),即使是同 pod 或者同節(jié)點(diǎn)內(nèi)。而這兩種情況實(shí)際都發(fā)生在同一個(gè)內(nèi)核空間中。

網(wǎng)絡(luò)和操作系統(tǒng)內(nèi)核,對(duì)我來(lái)說(shuō)是既陌生又滿是吸引,希望能夠撥開(kāi)層層迷霧找到背后的真相。

在 ??上一篇文章?? 中我深入探討了 Kubernetes 網(wǎng)絡(luò)模型,這次我想更深入一點(diǎn):了解數(shù)據(jù)包在 Kubernetes 中的傳輸,為學(xué)習(xí) Kubernetes 的 eBPF 網(wǎng)絡(luò)加速做準(zhǔn)備,加深對(duì)網(wǎng)絡(luò)和操作系統(tǒng)內(nèi)核的理解。 文中可能有疏漏之處,還望大家賜教。

在開(kāi)始之前,我可以用一句話來(lái)總結(jié)我的學(xué)習(xí)成果:數(shù)據(jù)包的流轉(zhuǎn)其實(shí)就是一個(gè)網(wǎng)絡(luò)套接字描述符(Socket File Descriptor,中文有點(diǎn)冗長(zhǎng),以下簡(jiǎn)稱 socket fd)的尋址過(guò)程。 它不是簡(jiǎn)單的指 socket fd 的內(nèi)存地址,還包括它的網(wǎng)絡(luò)地址。

在 Unix 和類 Unix 系統(tǒng)中,一切皆文件,也可以通過(guò)文件描述符來(lái)操作 socket。

基礎(chǔ)知識(shí)

數(shù)據(jù)包

既然要討論數(shù)據(jù)包的流轉(zhuǎn),先看看什么是數(shù)據(jù)包。

網(wǎng)絡(luò)數(shù)據(jù)包(network packet),也稱為網(wǎng)絡(luò)數(shù)據(jù)報(bào)(network datagram)或網(wǎng)絡(luò)幀(Network frame),是通過(guò)計(jì)算機(jī)網(wǎng)絡(luò)傳輸?shù)臄?shù)據(jù)單位。拿最常見(jiàn)的 TCP 數(shù)據(jù)包來(lái)看包含如下幾個(gè)部分:

  • Ethernet header:鏈路層信息,主要包括目的 MAC 地址和源 MAC 地址,以及報(bào)文的格式,這里是 IP 包。
  • IP header:網(wǎng)絡(luò)層信息,主要包括長(zhǎng)度、源 IP 地址和目的 IP 地址以及報(bào)文的格式,當(dāng)然這里必須是 TCP 包。
  • TCP header:傳輸層信息,包括源端口和目的端口。
  • 數(shù)據(jù):一般是第 7 層的數(shù)據(jù),比如 HTTP 等。

這里沒(méi)有介紹的 checksum 和 FCS 通常是用來(lái)檢查數(shù)據(jù)包在傳輸過(guò)程中是否被篡改或者發(fā)生了錯(cuò)誤。

圖片

應(yīng)用程序使用 socket 向網(wǎng)絡(luò)發(fā)送數(shù)據(jù)的過(guò)程可以簡(jiǎn)單理解為使用頭信息封裝數(shù)據(jù)的過(guò)程:TCP 數(shù)據(jù)包、IP 數(shù)據(jù)包、Ethernet 數(shù)據(jù)包;反過(guò)來(lái),從網(wǎng)絡(luò)接收以太網(wǎng)數(shù)據(jù)包到應(yīng)用程序可以處理的數(shù)據(jù),就是解包的過(guò)程。封包和解包的過(guò)程是由內(nèi)核網(wǎng)絡(luò)協(xié)議棧來(lái)完成的。

下面分別說(shuō)一下 socket 和內(nèi)核網(wǎng)絡(luò)協(xié)議棧的處理。

socket 套接字

Socket 是一種在計(jì)算機(jī)網(wǎng)絡(luò)中使用的編程接口,位于用戶空間(用戶應(yīng)用程序運(yùn)行的空間)和內(nèi)核網(wǎng)絡(luò)協(xié)議棧(內(nèi)核中對(duì)數(shù)據(jù)進(jìn)行封包和解包的組件)之間。

圖片

作為編程接口,socket 提供了如下操作(只列出部分):

  • socket
  • connect
  • bind
  • listen
  • accept
  • 數(shù)據(jù)傳輸
  • send
  • sendto
  • sendmsg
  • recv
  • recvfrom
  • recvmsg
  • getsockname
  • getpeername
  • getsockopt? 、setsockopt 獲取或設(shè)置 socket 層或協(xié)議層選項(xiàng)
  • close

通過(guò)下面的圖,可以直觀感受各個(gè)操作的作用:

圖片

開(kāi)始講解內(nèi)核網(wǎng)絡(luò)協(xié)議棧之前,先說(shuō)下數(shù)據(jù)包在內(nèi)存中的數(shù)據(jù)結(jié)構(gòu):sk_buff[1]。

sk_buff

sk_buff 是 Linux 內(nèi)核中用于管理網(wǎng)絡(luò)數(shù)據(jù)包的數(shù)據(jù)結(jié)構(gòu),它包含了接收和發(fā)送的網(wǎng)絡(luò)數(shù)據(jù)包的各種信息和屬性,如數(shù)據(jù)包的協(xié)議、數(shù)據(jù)長(zhǎng)度、源和目標(biāo)地址等。sk_buff 是一種可以在網(wǎng)絡(luò)層和數(shù)據(jù)鏈路層之間傳遞的數(shù)據(jù)結(jié)構(gòu),可以被用于所有類型的網(wǎng)絡(luò)協(xié)議棧,例如 TCP/IP、UDP、ICMP 等。

sk_buff 在 Linux 內(nèi)核中廣泛應(yīng)用于網(wǎng)絡(luò)協(xié)議棧的各個(gè)層級(jí),如數(shù)據(jù)鏈路層、網(wǎng)絡(luò)層、傳輸層等。sk_buff 數(shù)據(jù)結(jié)構(gòu)的字段很多,有 4 個(gè)重要的字段且都是指針類型。sk_buff 在不同層的使用,就是通過(guò)修改這些指針來(lái)完成的:加 header (封包)和移除 header(解包)。

這個(gè)過(guò)程操作做的是指針,數(shù)據(jù)是零拷貝的,可以極大地提升效率。

圖片

內(nèi)核網(wǎng)絡(luò)協(xié)議棧

封包

應(yīng)用程序使用 socket 的 sendmsg 操作發(fā)送數(shù)據(jù)(這里不深入講解 netfilter、traffic control、queue discipline):

  1. 先分配 sk_buff
  2. 接下來(lái)開(kāi)始網(wǎng)絡(luò)協(xié)議棧的處理
  3. 設(shè)置傳輸層信息(這里是 TCP 頭中的源和目的端口)
  4. 根據(jù)目標(biāo) IP 查找路由
  5. 設(shè)置網(wǎng)絡(luò)層信息(源和目的 IP 地址等)
  6. 調(diào)用 netfilter(LOCAL_OUT)
  7. 設(shè)置接口(interface)和協(xié)議(protocol)
  8. 調(diào)用 netfilter(POST_ROUTING)
  9. 如果包過(guò)長(zhǎng),分段傳輸
  10. L2 尋址,即查找可以擁有目標(biāo) IP 地址的設(shè)備的 MAC 地址
  11. 設(shè)置鏈路層信息,
  12. 至此內(nèi)核網(wǎng)絡(luò)協(xié)議棧的操作完成
  13. 調(diào)用 tc(traffic control)egress(可以對(duì)包進(jìn)行重定向)
  14. 進(jìn)入隊(duì)列 queue discipline(qdisc)
  15. 寫(xiě)入 NIC(network interface controler)
  16. 發(fā)送到網(wǎng)絡(luò)

解包

NIC 收到網(wǎng)絡(luò)發(fā)來(lái)的數(shù)據(jù)包(這里不深入講解 direct memory access、netfilter、traffic control):

  1. 將數(shù)據(jù)包寫(xiě)如 DMA 中(Direct Memory Access 直接內(nèi)存訪問(wèn),不需要依賴 CPU,由 NIC 直接寫(xiě)入到內(nèi)存中)
  2. 分配 sk_buff,并填充元數(shù)據(jù),比如 protocol 為 Ethernet 類型,接收數(shù)據(jù)包的網(wǎng)絡(luò)接口等
  3. 將鏈路層信息保存在 sk_buff 的 mac_header 字段中,并“移除”數(shù)據(jù)包中的鏈路層信息(移動(dòng)指針)
  4. 接下來(lái)開(kāi)始網(wǎng)絡(luò)協(xié)議棧的處理
  5. 將網(wǎng)絡(luò)層信息保存在 network_header 字段中
  6. 調(diào)用 tc ingress
  7. “移除”網(wǎng)絡(luò)層信息
  8. 將傳輸層信息保存在 transport_header 字段中
  9. 調(diào)用 netfilter(PRE_ROUTING)
  10. 查找路由
  11. 合并多個(gè)分包
  12. 調(diào)用 netfilter(LOCAL_IN)
  13. “移除”傳輸層信息
  14. 查找監(jiān)聽(tīng)目標(biāo)端口的 socket,或者發(fā)送 reset
  15. 將數(shù)據(jù)寫(xiě)入 socket 的接收隊(duì)列中
  16. 發(fā)信號(hào)通知有數(shù)據(jù)寫(xiě)入隊(duì)列
  17. 至此內(nèi)核網(wǎng)絡(luò)協(xié)議棧的操作完成
  18. sk_buff 從 socket 接收隊(duì)列中出隊(duì)
  19. 將數(shù)據(jù)寫(xiě)入應(yīng)用程序的緩沖區(qū)
  20. 釋放 sk_buff

Kubernetes 的網(wǎng)絡(luò)模型

另一部分的基礎(chǔ)知識(shí)就是 Kubernetes 的網(wǎng)絡(luò)模型了,可以參考之前的那篇 深入探索 Kubernetes 網(wǎng)絡(luò)模型和網(wǎng)絡(luò)通信。

Kubernetes 中的數(shù)據(jù)包流轉(zhuǎn)

這里繼續(xù)討論之前文章中的三種通信場(chǎng)景,pod 間的通信使用 pod IP 地址。如果要討論通過(guò) Service 來(lái)訪問(wèn),則要加入 netfilter 的討論篇幅會(huì)增加不少。

同 pod 內(nèi)的容器間通信

pod 內(nèi)兩個(gè)容器間的方式通常使用回環(huán)地址 127.0.0.1?,在封包的 #4 路由過(guò)程中確定了使用回環(huán)網(wǎng)卡 lo進(jìn)行傳輸。

圖片

同節(jié)點(diǎn)上的 pod 間通信

curl? 發(fā)出的請(qǐng)求在封包 #4 過(guò)程中確定使用 eth0? 接口。然后通過(guò)與 eth0? 相連的隧道 veth1 到達(dá)節(jié)點(diǎn)的根網(wǎng)絡(luò)空間。

veth1? 通過(guò)網(wǎng)橋 cni0? 與其他 pod 相連虛擬以太接口 vethX? 相連。在封包 #10 L2 尋址中,ARP 請(qǐng)求通過(guò)網(wǎng)橋發(fā)送給所有相連的接口是否擁有原始請(qǐng)求中的目的 IP 地址(這里是 10.42.1.9)

拿到了 veth0? 的 MAC 地址后,在封包 #11 中設(shè)置數(shù)據(jù)包的鏈路層信息。數(shù)據(jù)包發(fā)出后,經(jīng)過(guò) veth0? 隧道進(jìn)入 pod httpbin? 的 eth0 接口中,然后開(kāi)始解包的過(guò)程。

解包的過(guò)程沒(méi)啥特別,確定了 httpbin 使用的 socket。

圖片

不同節(jié)點(diǎn)的 pod 間通信

這里稍微不同,就是在通過(guò) cni0? 發(fā)送 ARP 請(qǐng)求沒(méi)有收到應(yīng)答,使用根命名空間也就是主機(jī)的路由表,確定了目標(biāo)主機(jī) IP 地址后,然后通過(guò)主機(jī)的 eth0 放 ARP 請(qǐng)求并收到目標(biāo)主機(jī)的響應(yīng)。將其 MAC 地址在封包 #11 中寫(xiě)入。

數(shù)據(jù)包發(fā)送到目標(biāo)主機(jī)后,開(kāi)始解包的過(guò)程,最終進(jìn)入目標(biāo) pod。

在集群層面有一張路由表,里面存儲(chǔ)著每個(gè)節(jié)點(diǎn)的 Pod IP 網(wǎng)段(節(jié)點(diǎn)加入到集群時(shí)會(huì)分配一個(gè) Pod 網(wǎng)段(Pod CIDR),比如在 k3s 中默認(rèn)的 Pod CIDR 是 10.42.0.0/16?,節(jié)點(diǎn)獲取到的網(wǎng)段是 10.42.0.0/24、10.42.1.0/24、10.42.2.0/24,依次類推)。通過(guò)節(jié)點(diǎn)的 Pod IP 網(wǎng)段可以判斷出請(qǐng)求 IP 的節(jié)點(diǎn),然后請(qǐng)求被發(fā)送到該節(jié)點(diǎn)。

圖片

總結(jié)

統(tǒng)計(jì)一下在三個(gè)場(chǎng)景中,經(jīng)過(guò)內(nèi)核網(wǎng)絡(luò)協(xié)議棧的處理次數(shù)都是兩次(包括 netfilter 的處理。),即使是同 pod 或者同節(jié)點(diǎn)內(nèi)。而這兩種情況實(shí)際都發(fā)生在同一個(gè)內(nèi)核空間中。

假如同一個(gè)內(nèi)核空間中的兩個(gè) socket 可以直接傳輸數(shù)據(jù),是不是就可以省掉內(nèi)核網(wǎng)絡(luò)協(xié)議棧處理帶來(lái)的延遲?

下篇繼續(xù)。

參考資料

[1] sk_buff: https://elixir.bootlin.com/linux/latest/source/include/linux/skbuff.h#L843

責(zé)任編輯:武曉燕 來(lái)源: 云原生指北
相關(guān)推薦

2023-07-16 23:11:36

DNS查詢kubelet

2017-08-22 11:30:15

LinuxWireshark過(guò)濾數(shù)據(jù)包

2013-01-28 13:32:52

路由器網(wǎng)絡(luò)設(shè)置數(shù)據(jù)傳輸

2020-11-18 07:54:31

太網(wǎng)數(shù)據(jù)包架構(gòu)

2021-07-15 09:57:39

Wireshark數(shù)據(jù)包長(zhǎng)度

2017-04-07 09:30:49

Linux網(wǎng)絡(luò)數(shù)據(jù)包

2019-04-29 07:53:11

TCP數(shù)據(jù)包TCP網(wǎng)絡(luò)編程

2012-12-04 09:54:33

路由器數(shù)據(jù)包TCP

2017-03-28 13:25:14

Linux網(wǎng)絡(luò)數(shù)據(jù)包

2013-01-21 15:11:39

路由器數(shù)據(jù)包路由技術(shù)

2013-05-21 14:41:42

數(shù)據(jù)包分析內(nèi)聯(lián)監(jiān)控

2010-12-15 14:04:11

Ngrep

2021-05-12 00:07:27

TCPIP協(xié)議

2022-01-14 10:59:07

數(shù)據(jù)包tcpdump

2014-07-09 09:43:59

2020-11-23 10:25:44

tcpdump數(shù)據(jù)包Linux

2024-06-07 06:29:49

2010-05-26 17:42:29

IPv6數(shù)據(jù)包

2011-11-28 16:03:49

wireshark數(shù)據(jù)包

2011-05-19 13:34:50

無(wú)線信息包
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)