很多人在網(wǎng)絡學習中存在這兩個問題
本文轉(zhuǎn)載自微信公眾號「開發(fā)內(nèi)功修煉」,作者張彥飛allen。轉(zhuǎn)載本文請聯(lián)系開發(fā)內(nèi)功修煉公眾號。
大家好,我是飛哥!在互聯(lián)網(wǎng)時代里,我覺得網(wǎng)絡是最重要的一門技術(shù)了。但是我覺得從國內(nèi)計算機系的學生,到已經(jīng)工作了的工程師,在網(wǎng)絡的學習上整體存在兩個問題。
第一個是對實踐的重視程度不夠。這個問題在大學計算機課程中尤為突出。但這也不只是在學生群體中存在,很多工作了的工程師也是。在學習一個新技術(shù)的時候止步于眼睛看完就拉到,不想著去動手寫一寫,做測試跑一跑驗證一下。
第二是對實現(xiàn)的重視程度不夠。大部分的人都愿意把精力放在自己代碼能波及的范圍內(nèi)。盲目相信工程中的黑盒依賴,把底層當成黑盒來使用,不愿意花功夫去了解一點底層實現(xiàn),這是對于成長非常不利的。拿汽車來舉例,我們工程師更應該是知曉汽車各項參數(shù)的優(yōu)秀賽車手,而不是靠車謀生的出租司機。
今天我就這兩點我就結(jié)合咱們內(nèi)功修煉技術(shù)文章的創(chuàng)作過程,來分別展開了和大家聊聊~
一、對實踐的重視程度不夠
對于大部分應用場景來說,計算機科學與技術(shù)這個專業(yè)在技術(shù)的占比是遠遠要高于科學占比的,也就是說它的技術(shù)屬性更多。對于一門技術(shù)來講,動手就是非常非常重要的。
而我們國內(nèi)的教學模式太過于偏重理論了,所以很多人都會覺得網(wǎng)絡技術(shù)這門課太抽象了。這不是學生的問題,而是教育方法的缺陷。你應該也沒聽說過有哪門技術(shù)是光看書就能看會的。
根據(jù)美國學者艾德加·戴爾1946年發(fā)現(xiàn)的金字塔學習理論,見下圖。傳統(tǒng)的理論性的學習如聽講和閱讀對知識的吸收率只有 10% 左右,而動手實踐對知識的吸收率能達到 75% 以上。從效率上來講,通過實踐的方式進行學習的效率對理論學習的 7 -8 倍。
我覺得正確的學習方法應該是邊學理論邊動手實踐。動手包括兩類方法,一類是用一些命令行工具進行觀測,另外一類就是寫程序驗證。
如果你是一位計算機系學生,我建議首先要準備一臺 Linux 電腦(工程師就不用說了,應該大部分都用上 Linux 了)。在 Linux 下有很多成熟的網(wǎng)絡相關(guān)的工具可供你使用。現(xiàn)在國內(nèi)的互聯(lián)網(wǎng)公司的服務器基本上也都是 Linux。而且用 Linux 有個好處就是源碼是公開的。實在遇到不懂的問題,可以更容易地搜答案。這點比 Windows 強太多了。
對于第一類動手觀測法,我的建議是你學到某一層的時候,就找到一些相關(guān)的工具來做幾個實驗。比如你可以啟動一個 Nginx(或者干脆自己寫一個 Server),用 curl 等工具發(fā)起 TCP 連接建立請求。這時候用 tcpdump 動手進行抓包,看看每次握手的時候,包體究竟是長什么樣的。有資深工作經(jīng)驗的同學可以試試 systemtab、perf 等高級工具。
我把 linux 下的各種網(wǎng)絡工具簡單整理了一下,各位有需要可以把這張圖保存下來。
值得多提一下的是 systemtab 這個工具,他能夠跟蹤內(nèi)核中的函數(shù)并打印一些調(diào)試信息??梢垣@取內(nèi)核函數(shù)里的變量值,也可以打印調(diào)用堆棧。不過需要安裝對應版本的內(nèi)核調(diào)試包。
另外一個工具就是 perf,它可以統(tǒng)計和跟蹤內(nèi)核活動。通過 perf list 可以查看當前系統(tǒng)支持的所有性能事件、檢查點。
第二類方法就是動手編程。對于學生來說,剛開始可以從一些簡單的開始,比如就寫個 tcp server, tcp client 讓他們相互連接然后傳輸一些簡單的數(shù)據(jù)。然后可以開始練一些更為復雜一點的。比如寫一套 FTP Server 和 Client, 讓它們之間能夠?qū)崿F(xiàn)簡單的文件下載。或者寫一個 Web Server,支持通過瀏覽器來下載 Web Server 上的靜態(tài)文件。
或者參考 Libevent、Redis、Sogou WorkFlow 等項目包封裝一個簡單的網(wǎng)絡庫出來。再比如說模擬 tcpdump 來寫一個抓包工具。(可以參考我的這篇文章,里面提供了一個簡單的 demo)。
對于工程師來說也是一樣。新學到一個的技術(shù)方案的時候,要盡量多動手去測試一下,驗證驗證。比如對于零拷貝來說,如果不使用零拷貝的話,單純的使用 read 文件 + write 發(fā)送的方式和直接使用 sendfile 的方法比起來性能大概是差多少,能不能得出一些真實數(shù)據(jù)上的結(jié)論。
比如使用裸 epoll 的 QPS 數(shù)據(jù)最高能到多少, Golang 中的 net 包對 epoll 使用協(xié)程封裝一次后能達到多少,完全不使用 epoll 的同步阻塞網(wǎng)絡 IO 性能數(shù)據(jù)幾何。
如果你經(jīng)過實踐測試驗證之后,你對性能的理解會得到質(zhì)的提升。對于我個人來講,我也是一直通過理論 + 實踐的方法來對知識進行學習的,效果真的不錯。
比如我在網(wǎng)絡中,我想弄懂一條空的 TCP 連接消耗多大的內(nèi)存。我自己在工作之余抽了好長時間去翻內(nèi)核源碼,然后動手做實驗。當實驗完成的時候,我對 TCP 連接的內(nèi)存開銷的理解就非常的深了。
漫畫 | 花了七天時間測試,我徹底搞明白了 TCP 的這些內(nèi)存開銷!
我一直想弄清楚一臺服務器在實際中最大能支撐多少條 TCP 連接,我也是通過動手實驗的方法來學習的,當時我前前后后至少花了半個多月。參見:
漫畫 | 一臺Linux服務器最多能支撐多少個TCP連接
漫畫 | 理解了TCP連接的實現(xiàn)以后,客戶端的并發(fā)也爆發(fā)了!
如果你也想玩玩,直接用我這篇文章里提供的源碼就好。
百看不如一練,動手測試單機百萬連接的保姆級教程!
在比如在內(nèi)存和硬盤的性能上,我也是通過理論 + 實測的方法來深度理解的。
機械硬盤隨機IO慢的超乎你的想象
實際測試內(nèi)存在順序IO和隨機IO時的訪問延時差異
如果你能能堅持通過動手加實踐的方法來學習,相信你的技術(shù)水平一定會遠遠超過其他的同學。
二、對實現(xiàn)的重視程度不夠
翻開任何一本計算機網(wǎng)絡相關(guān)的教材大部分都是在講協(xié)議(首先聲明一下,我不反對理解這些基礎的協(xié)議是挺重要的),那么協(xié)議具體是咋實現(xiàn)的,講這些的貌似很少。
我們的日常開發(fā)都是基于操作系統(tǒng)在協(xié)議的實現(xiàn)基礎上來進行工作的。對實現(xiàn)理解不到位會導致很多線上問題或者是性能優(yōu)化都無從下手。雖然市場上也有一些內(nèi)核實現(xiàn)相關(guān)的資料,但是又太難啃不動。
比如大家都知道服務器先 listen 一下,然后才能 accpet 接收連接請求。但是,到底為啥要先 listen ,似乎沒有人和我們說過。不理解這個的話,就對全連接隊列半連接隊列理解不深,遇到問題就不好處理。
再比如說,現(xiàn)在的互聯(lián)網(wǎng)大部分都是通過 TCP 連接來工作的,那么一臺機器最多能撐多少個 TCP 連接?按道理說,整個業(yè)界都在講高并發(fā),這應該算是很入門的一個問題了。但當年我產(chǎn)生這個疑問的時候,卻在 Google 上搜了個遍也沒找到令我滿意的答案。
再比如一個網(wǎng)絡包是如何從網(wǎng)卡到達你的進程里的? 這個問題表面上看起來簡單,但事實上很多性能優(yōu)化方案都和這個接收過程有關(guān),能不能深度理解這個過程決定了你在網(wǎng)絡性能上有多少的優(yōu)化措施可用。例如多隊列網(wǎng)卡的優(yōu)化方案是在硬中斷這一步開始將工作分散在多個 CPU 核上,進而提升性能的。我?guī)啄昵跋氚堰@個問題徹底搞搞清楚,搜遍了互聯(lián)網(wǎng),翻遍了各種經(jīng)典書都沒能找到想要的答案。
還比如為啥 TCP 握手耗時過長,一條 TCP 連接會消耗多大的內(nèi)存。同步阻塞網(wǎng)絡 IO 為啥就性能慢了,為啥 epoll 用上了以后就要性能高很多。這些和工程實踐相關(guān)的問題光知道網(wǎng)絡協(xié)議理論是任何用都沒有的,都是應該建立在對網(wǎng)絡實現(xiàn)的深刻理解上才能更好地應對。
針對這個問題,我在實現(xiàn)層面把網(wǎng)絡都扒了一遍,成果都通過咱們開發(fā)內(nèi)功修煉公眾號發(fā)表。
例如,為什么服務端程序都需要先 listen 一下?事實上是因為服務器在接收客戶端連接之前,提前準備了半連接和全連接兩個隊列。一個用于保存第一次握手請求,另一個用于保存第三次握手??蛻舳四厥窃? connect 發(fā)起前,在內(nèi)核里選擇好端口號的。