執行人: yan112388
專題解說影片
改進 kHTTPd 的並行處理能力,予以量化並有效管理連線。
著重 concurrency, workqueue
內容參考 Linux 核心設計: RCU 同步機制
RCU (Read-Copy Update) 是 Linux 核心中的一種資料同步機制,允許多個 reader 在單一 writer 更新資料的同時,得以在不需要 lock 的前提,正確讀取資料。
RCU 適用場景:
rcu_example 為一個簡易的 RCU 相關 Linux 核心模組,rcu_example
使用 rcu 鏈結串列來實做一個書籍借閱管理系統。
讀取方面的操作 is_borrowed_book
print_book()
rcu_read_lock()
與 rcu_read_unlock()
,用來標記 RCU 讀取過程的開始和結束,幫助檢測寬限期是否結束list_for_each_entry_rcu()
用於走訪 RCU 保護的串列節點將此程式碼編譯並掛載,將會自動執行 test_example
函式
使用以下命令來查看核心的輸出訊息,可以看見 test_example
的輸出內容
drop-tcp-socket
核心模組運作原理 與 TIME-WAIT
sockets解釋 drop-tcp-socket
核心模組運作原理。TIME-WAIT
sockets 又是什麼?
TIME-WAIT
sockets正常情況,TCP 連線會經過四次揮手過程才會關閉:
TIME_WAIT
socket 為一個處於 TIME_WAIT 狀態的 socket,以下內容參考 TCP/IP Illustrated, Volume 1 : The Protocols:
當 TCP 執行主動關閉並發送最後的 ACK 時,連線必須在 TIME_WAIT
狀態停留兩個最大區段壽命(maximum segment lifetime)的時間,因此TIME_WAIT
狀態也被稱為 2MSL(maximum segment lifetime,MSL) 等待狀態。
最大區段壽命 maximum segment lifetime
在這段時間內,網路中所有與該連線相關的區段都將消失,進而避免了可能會發生的的衝突:
延遲區段的誤判:
舊連線中的延遲區段可能在新連線建立後才到達,2MSL(maximum segment lifetime)的等待期確保了舊連線的所有區段都會在網路中消失。如果沒有 TIME_WAIT
,這些延遲的區段可能被誤認為是新連線的一部分。
序列號重疊:
TCP 使用序列號來識別和排序封包,如果新舊連線使用相同的四元組(來源 IP 、來源埠號、目的 IP、目的埠號),且序列號恰好重疊,可能導致資料混雜。在 TIME_WAIT
期間,相同的四元組不能被用於新的連線。
ACK 問題:
如果舊連線的 ACK 在新連線建立後到達,可能觸發不必要的重傳,導致網路阻塞。2MSL 的時間能使序列號空間得到充分的更新。
此外,TIME_WAIT
狀態還允許重傳最後的 ACK,如果最後的 ACK 丟失,對方會重發 FIN。
一個 TCP 連接進入 TIME_WAIT
狀態時,對應的 socket 就成為了 TIME_WAIT
socket。缺點為,會佔用系統資源,(如佔用了大量的通訊埠),甚至可能引起服務重啟延遲的問題。因此,在設計高效能伺服器時需要考慮 TIME_WAIT
的影響。
drop-tcp-socket
核心模組提供一個機制,允許在特定條件下強制關閉處於 TIME-WAIT
狀態的 TCP 連線,直接釋放 socket 資源。
在 drop-tcp-socket.c
中,定義了 3 種結構體
droptcp_data
儲存和管理從使用者空間讀取到的資料droptcp_pernet
儲存每個網路命名空間(network namespace)的特定資料網路命名空間(network namespace):Linux 核心中一種用來隔離作業系統跟網路相關資源的機制,NETWORK_NAMESPACES(7) 中寫道
Network namespaces provide isolation of the system resources associated with networking: network devices, IPv4 and IPv6 protocol stacks, IP routing tables, firewall rules…
每個網路命名空間有自己的網路設備、路由表、防火牆規則等,藉此達到網路虛擬化的目的。
待補充細節
droptcp_inet
表達一個 IP 地址和埠號的組合這些結構體使得模組有助於處理使用者的輸入,管理網路命名空間,並且正確地別和操作 TCP 連線。
整個流程如下:
droptcp_proc_write
、droptcp_proc_open
proc 檔案系統待補充
droptcp_proc_release
、droptcp_process
使用 while
循環輸入資料,分析地址後找到對應的 socket
droptcp_drop
、droptcp_proc_release
判斷 socket 是否處於 TIME-WAIT
狀態,如果是 TIME-WAIT
狀態,就直接釋放。如果是其他狀態,則執行正常的關閉過程。
總結:drop-tcp-socket
核心模組結合網路命名空間和 proc 檔案系統來達成目的。
參考資料: ktcp 作業頁面、kecho 的實作、學員筆記 fatcatorange
CMWQ(Concurrency Managed Workqueue) 是 Linux 核心中的一個機制,用於處理非同步的任務。
該機制使用 struct list_head
將要處理的每一個任務連接,依次取出處理,處理結束的再從 queue 中刪除
傳統的 workqueue 需要考慮 CPU 調度的問題,CMWQ 使用 worker-pool ,藉此全幫開發者處理好,可以減少消耗的資源,提高並行性和效率,
於 khttpd 中 http_server.h
新增以下結構體
修改 http_server.c
中的 http_request
結構,新增鏈結串列節點及 work_struct
結構體
在 main.c
中的 khttpd_init
,包含以下內容:
alloc_workqueue
建立一個新的 workqueue,為 CMWQ 機制提供基礎的架構kthread_run
會建立並開啟一個核心執行緒,再執行 http_server_daemon
,為每一個連線的請求建立一個 work 進行處理create_work
創建新的 workqueue_work(khttpd_wq, work)
將 work 放入workqueue 中主要流程:
建立 CMWQ -> 創建 work -> workqueue 開始運作 -> 待模組卸載,釋放所有記憶體
以下為將時間設定為連續 3 秒,使用 20 個並行連線,且總請求數量為 200,000 的壓力測試結果:
原版 khttpd
引入 CMWQ 後的 khttpd
由此可見,吞吐量有所提升
確保得以處理大量並行請求,並正確處理資源的釋放
在課程期末專題找出同樣從事 kHTTPd 專案開發的學員,在其開發紀錄提出你的疑惑和建議。
在此彙整你的認知和對比你的產出。