來源于公眾號(hào)我是程序員小賤 ,作者L的存在
計(jì)算機(jī)網(wǎng)絡(luò)的重要程度不言而言,也是非常的復(fù)雜。今天我將從輸入U(xiǎn)RL這個(gè)簡(jiǎn)單例子開始,一起探索數(shù)據(jù)包的心路歷程。先看文章的大綱。
1 源頭------網(wǎng)址
網(wǎng)址即平時(shí)所說的URL。就是經(jīng)常使用的以“Http://”開頭的那一串東東,其實(shí)常用的還有很多,比如 "FTP" , "FILE"等,我們所訪問的目標(biāo)網(wǎng)站不同,網(wǎng)址開頭的寫法也就不同,下面列出常見的幾種URL。
從上圖可知,URL 中可以包含服務(wù)器的域名,文件的路徑,收件人郵件地址,用戶名,密碼等信息。總之URL想表達(dá)的是:
訪問時(shí)所使用的協(xié)議。"HTTP" , "FTP" , "FILE"等
用戶名/密碼可選
所需訪問或下載文件的路徑
URL的相貌我們已經(jīng)銘記于心,而且對(duì)于 URL 各個(gè)子模塊也有了基本的認(rèn)識(shí),可別小看這幾個(gè)小模塊,慢工出細(xì)活。我們拆分后仔細(xì)看看
URL拆分
理解URL個(gè)元素的含義
從上面的結(jié)果我們可以得出,Web 服務(wù)器名稱為 www.xiaolan.com ,文件路徑名為 /dir1/index.html。所以這個(gè)URL表示我要訪問www.xiaolan.com這個(gè)web服務(wù)器上路徑為/dir/index.html的文件。
下面我們對(duì)這個(gè)URL稍微改動(dòng):
(a)http://www.xiaolan.com/dir/
這里注意,dir 后面的文件名被省略了,這樣的話服務(wù)器會(huì)使用默認(rèn)的文件名,就反復(fù)咱們定義變量的時(shí)候,如果沒有賦初值,通常會(huì)給默認(rèn)值。同樣的道理,服務(wù)器也會(huì)給一個(gè)默認(rèn)的文件名,不同的服務(wù)器默認(rèn)的文件會(huì)不一樣,通常會(huì)是 Index.html。
這個(gè)就比較狠了,后面的"/"直接沒有,那該訪問啥呢?如果沒有路徑名,則代表訪問根目錄下面設(shè)置的默認(rèn)文件。
(d)http://www.xiaolan.com/whatisthis
這末尾的 whatisthis 是什么呢?在這種情況,如果服務(wù)器中存在 whatisthis 的文件,則按照文件處理。如果是 wahtsthis 為目錄,則按照目錄進(jìn)行處理。
2 HTTP初探
通過第一步對(duì)URL的解析,知道了我們所訪問的目標(biāo)是什么,接下來是不是就要請(qǐng)求數(shù)據(jù)了呢?在做請(qǐng)求之前,我們一起回憶一下HTTP的基礎(chǔ)知識(shí)
首先HTTP協(xié)議定義了客戶端和服務(wù)器之間交互的消息內(nèi)容和步驟。簡(jiǎn)單的說呢即請(qǐng)求的信息包括了"請(qǐng)求啥"以及"你要進(jìn)行什么操作",和我們面試的時(shí)候一樣,簡(jiǎn)歷上面寫了XX項(xiàng)目,我們是不是也需要清楚自己的項(xiàng)目是什么,你在項(xiàng)目中什么角色一樣且做了哪些部分,別寫上去的東西一問三不知就比較尷尬了
在HTTP中請(qǐng)求啥這部分叫做 "URI",URI主要存放網(wǎng)頁數(shù)據(jù)的文件名或者是CGI程序如"/Manage/index.html"等。
“進(jìn)行啥操作”統(tǒng)稱為方法。希望服務(wù)器能完成什么工作,比如讀取URI中表示的數(shù)據(jù)。哪都有哪些方法可以使用呢,這張圖總結(jié)常用的幾種方法以及含義
這里提一下比較常用且面試常問的兩個(gè)方法
- GET
當(dāng)訪問 Web 服務(wù)器獲取網(wǎng)頁數(shù)據(jù)的時(shí)候,使用的幾乎都是 Get 方法。在請(qǐng)求消息中表明使用Get方法,然后在URI 中表明文件名,比如是 /manage/index.html。服務(wù)器收到消息后,會(huì)打開/manage/index.html并讀取里面的數(shù)據(jù),然后存放于相應(yīng)消息中并返回給客戶端,最后在屏幕中完成呈現(xiàn)。
- POST
當(dāng)我們?cè)谫徫锾顚懙刂沸畔ⅲ蛘咛顚憜柧硇畔⒌臅r(shí)候,將內(nèi)容填寫到表格中,然后點(diǎn)擊提交這個(gè)過程,實(shí)際上通常就是采用的POST方式。這樣看來,采用POST的方式提交數(shù)據(jù),我們需要準(zhǔn)備三樣?xùn)|西,分別為:所提供的方法,URL 和服務(wù)端。服務(wù)器收到請(qǐng)求數(shù)據(jù)后發(fā)送給 URI 所指定的應(yīng)用程序,然后服務(wù)端獲取應(yīng)用程序的執(zhí)行結(jié)果并在響應(yīng)信息中返回給客戶端。
OK,現(xiàn)在我們目標(biāo)基本上明確了,將各個(gè)需要發(fā)送的內(nèi)容組合并發(fā)給服務(wù)器。服務(wù)器進(jìn)行解析,根據(jù)客戶端的需求完成使命后將需要反饋的信息存放在響應(yīng)消息中,那么對(duì)于客戶端而言,也不知道到底是不是想要的結(jié)果。所以,服務(wù)端會(huì)在響應(yīng)頭中用一個(gè)狀態(tài)碼表示操作的結(jié)果是成功還是失敗,比如 200 表示成功,404可能為沒找到文件。
此時(shí)客戶端收到了服務(wù)端的響應(yīng)信息,瀏覽器覺得這太 lowb 了,給你渲染下并完美的呈現(xiàn)在我們眼前。HTTP的使命就此完成。
3 HTTP請(qǐng)求頭------保命天子
看到這里,我相信大家應(yīng)該了解了 HTTP 的大概樣貌。萬事兒都是有原則的,那么請(qǐng)求的也是有格式的,不聽話就要被打屁屁。
先寫方法,加上空格,然后寫上 URI(文件或者程序的路徑名),行末尾協(xié)商HTTP版本號(hào)即完成第一行的任務(wù)。
第二行為消息頭。這一行主要是對(duì)第一行內(nèi)容的進(jìn)一步補(bǔ)充。比如會(huì)告知客戶端支持的數(shù)據(jù)類型、壓縮格式,數(shù)據(jù)有效期等,具體的我放張圖,需要的可以去了解下。
第三行為空行,然后加上需要發(fā)送的數(shù)據(jù),這為消息體。整個(gè)消息也就結(jié)束
4 HTTP響應(yīng)-----我行我素
響應(yīng)的內(nèi)容和請(qǐng)求信息的內(nèi)容類似。只是響應(yīng)中的第一行內(nèi)容為狀態(tài)碼,表示執(zhí)行結(jié)果是否成功。常見的HTTP狀態(tài)碼如下圖所示
響應(yīng)信息返回后顯示在屏幕中,如果為純文字,到此就結(jié)束了。但是大部分時(shí)候都會(huì)有圖片,視頻,音頻等信息,這個(gè)時(shí)候怎么辦?
瀏覽器會(huì)從響應(yīng)信息中的文字搜索相應(yīng)的標(biāo)簽,如果有圖片等其他信息,則再次請(qǐng)求服務(wù)器,按照相應(yīng)的文件名向服務(wù)器發(fā)送請(qǐng)求并顯示在剛才預(yù)留的空間中。至此,我們?cè)L問網(wǎng)頁的初級(jí)過程版本就差不多結(jié)束了。下面用一個(gè)案例加深下印象。
上圖是簡(jiǎn)化版,在這里再穩(wěn)固幾點(diǎn)
Get和Post哪些區(qū)別
請(qǐng)求頭和響應(yīng)頭哪些位置是需要空格或者空行
常用響應(yīng)狀態(tài)碼和請(qǐng)求方法
到此,我們從表面上知道,從敲入網(wǎng)址,構(gòu)造請(qǐng)求消息,收到響應(yīng),并能將美女圖片給呈現(xiàn)在眼前,這樣就完事了?不好意思,我們時(shí)刻都有一顆的去大廠的心,意味著我們不能只知道表面現(xiàn)象還要適當(dāng)去了解更多的細(xì)節(jié)。
5 刨根
雖然瀏覽器能夠解析我們的網(wǎng)址,但是它并不具備將消息發(fā)送到網(wǎng)絡(luò)中的能力,那是誰打的輔助?當(dāng)然是操作系統(tǒng)大哥,為了讓操作系統(tǒng)大哥幫忙,我們得先拜訪下操作系統(tǒng)大哥,問問需要我們提供哪些資源,需要什么,我們就全力配合它。
- IP地址
我們?cè)跒g覽器輸入的是網(wǎng)址,但是操作系統(tǒng)需要的是IP地址,所以我們需要想辦法進(jìn)行轉(zhuǎn)換。轉(zhuǎn)換的方法就需要請(qǐng)教 DNS 了。很簡(jiǎn)單,我們告訴DNS,"我的域名是www.xiaolan.com,請(qǐng)告訴我的 IP 地址",OK,DNS服務(wù)器很爽快,回復(fù)"你的IP地址是xxx.xxx.xxx.xxx"。那么問題來了,我們是如何向 DNS 發(fā)送的這個(gè)查詢呢?我們先來復(fù)習(xí)DNS
DNS
有些小伙伴說 Mac 地址不能作為標(biāo)識(shí)嗎?可是太不容易記憶了,從而出現(xiàn)了簡(jiǎn)化了 IP 形式,可以它被直接暴露給外網(wǎng)不說,還讓人類覺得比較麻煩,干脆用幾個(gè)字母算了,也就是域名了。域名不僅僅能夠代替 IP,還有很多其他的用途比如在 Web 應(yīng)用中用來標(biāo)識(shí)虛擬主機(jī)。
說了這么多,協(xié)議頭部,到底有哪些字段,其含義是什么都還不知道,那怎么去分析報(bào)文,下面我們一起再看看報(bào)文什么樣子
DNS報(bào)文結(jié)構(gòu)
基礎(chǔ)結(jié)構(gòu)部分
DNS報(bào)文基礎(chǔ)部分為DNS首部。其中包含了事務(wù)ID,標(biāo)志,問題計(jì)數(shù),回答資源計(jì)數(shù),回答計(jì)數(shù),權(quán)威名稱服務(wù)器計(jì)數(shù)和附加資源記錄數(shù)。
事務(wù)ID:報(bào)文標(biāo)識(shí),用來區(qū)分 DNS 應(yīng)答報(bào)文是對(duì)哪個(gè)請(qǐng)求進(jìn)行響應(yīng)
標(biāo)志:DNS 報(bào)文中標(biāo)志字段
問題計(jì)數(shù):DNS 查詢請(qǐng)求了多少次
回答資源記錄數(shù):DNS 響應(yīng)了多少次
權(quán)威名稱服務(wù)器計(jì)數(shù): 權(quán)威名稱服務(wù)器數(shù)目
附加資源記錄數(shù): 權(quán)威名稱服務(wù)器對(duì)應(yīng) IP 地址的數(shù)目
重點(diǎn)!!!!基礎(chǔ)結(jié)構(gòu)中的標(biāo)志字段細(xì)分如下:
標(biāo)志字段
QR(Response):查詢請(qǐng)求,值為0;響應(yīng)為1
Opcode:操作碼。0表示標(biāo)準(zhǔn)查詢;1表示反向查詢;2服務(wù)器狀態(tài)請(qǐng)求
AA(Authoritative):授權(quán)應(yīng)答,該字段在響應(yīng)報(bào)文中有效。通過0,1區(qū)分是否為權(quán)威服務(wù)器。如果值為 1 時(shí),表示名稱服務(wù)器是權(quán)威服務(wù)器;值為 0 時(shí),表示不是權(quán)威服務(wù)器。
TC(Truncated):表示是否被截?cái)唷.?dāng)值為1的時(shí)候時(shí),說明響應(yīng)超過了 512字節(jié)并已被截?cái)啵藭r(shí)只返回前512個(gè)字節(jié)。
RD(Recursion Desired):期望遞歸。該字段能在一個(gè)查詢中設(shè)置,并在響應(yīng)中返回。該標(biāo)志告訴名稱服務(wù)器必須處理這個(gè)查詢,這種方式被稱為一個(gè)遞歸查詢。如果該位為 0,且被請(qǐng)求的名稱服務(wù)器沒有一個(gè)授權(quán)回答,它將返回一個(gè)能解答該查詢的其他名稱服務(wù)器列表。這種方式被稱為迭代查詢。
RA(Recursion Available):可用遞歸。該字段只出現(xiàn)在響應(yīng)報(bào)文中。當(dāng)值為 1 時(shí),表示服務(wù)器支持遞歸查詢。
Z:保留字段,在所有的請(qǐng)求和應(yīng)答報(bào)文中,它的值必須為 0。
rcode(Reply code):通過返回只判斷相應(yīng)的狀態(tài)。
當(dāng)值為0時(shí),表示沒有錯(cuò)誤;當(dāng)值為1時(shí),表示報(bào)文格式錯(cuò)誤(Format error),服務(wù)器不能理解請(qǐng)求的報(bào)文;當(dāng)值為 2 時(shí),表示域名服務(wù)器失敗(Server failure),因?yàn)榉?wù)器的原因?qū)е聸]辦法處理這個(gè)請(qǐng)求;當(dāng)值為 3 時(shí),表示名字錯(cuò)誤(Name Error),只有對(duì)授權(quán)域名解析服務(wù)器有意義,指出解析的域名不存在;當(dāng)值為 4 時(shí),表示查詢類型不支持(Not Implemented),即域名服務(wù)器不支持查詢類型;當(dāng)值為 5 時(shí),表示拒絕(Refused),一般是服務(wù)器由于設(shè)置的策略拒絕給出應(yīng)答,如服務(wù)器不希望對(duì)某些請(qǐng)求者給出應(yīng)答。
問題部分
該部分是用來顯示DNS查詢請(qǐng)求的問題,其中包含正在進(jìn)行的查詢信息,包含查詢名(被查詢主機(jī)名字)、查詢類型、查詢類。
查詢名:一般為查詢的域名,也可能是通過IP地址進(jìn)行反向查詢
查詢類型:查詢請(qǐng)求的資源類型。常見的如果為A類型,表示通過域名獲取IP。具體如下圖所示
- 查詢類:地址類型,通常為互聯(lián)網(wǎng)地址為1
資源記錄部分
資源記錄部分包含回答問題區(qū)域,權(quán)威名稱服務(wù)器區(qū)域字段、附加信息區(qū)域字段,格式如下
資源記錄部分
域名:所請(qǐng)求的域名
類型:與問題部分查詢類型值一直
類:地址類型,和問題部分查詢類值一樣
生存時(shí)間:以秒為單位,表示資源記錄的生命周期
資源數(shù)據(jù)長度:資源數(shù)據(jù)的長度
資源數(shù)據(jù):按照查詢要求返回的相關(guān)資源數(shù)據(jù)
DNS解析詳解
知道了DNS大概是什么,它的域名結(jié)構(gòu)和報(bào)文結(jié)構(gòu),是時(shí)候看看到底怎么解析的以及如何保證域名的解析比較穩(wěn)定和可靠
DNS核心系統(tǒng)
根域名服務(wù)器(Root DNS Server),大哥,管理頂級(jí)域名服務(wù)并放回頂級(jí)域名服務(wù)器IP,比如"com","cn"
頂級(jí)域名服務(wù)器(Top-level DNS Server),每個(gè)頂級(jí)域名服務(wù)器管理各自下屬,比如com可以返回baidu.com域名服務(wù)器的IP
權(quán)威域名服務(wù)器(Authoritative DNS Server),管理當(dāng)前域名下的IP地址,比如Tencent.com可以返回www.tencent.com的 IP 地址
核心系統(tǒng)
舉個(gè)例子,假設(shè)我們?cè)L問"www.google.com"
訪問根域名服務(wù)器,這樣我們就會(huì)知道"com"頂級(jí)域名的地址
訪問"com"頂級(jí)域名服務(wù)器,可知道"google.com"域名服務(wù)器的地址
最后方位"google.com"域名服務(wù)器,就可知道"www.google.com"的IP地址
嘿嘿,目前全世界13組根域名服務(wù)器還有上百太鏡像,但是為了讓它能力更強(qiáng),處理任務(wù)效率更高,盡量減少域名解析的壓力,通常會(huì)加一層"緩存",意思是如果訪問過了,就緩存,下一次再訪問就直接取出,也就是咱么經(jīng)常配置的"8.8.8.8"等
操作系統(tǒng)中同樣也對(duì)DNS解析做緩存,比如說曾訪問過"www.google.com",
其次,還有我們熟知的hosts文件,當(dāng)在操作系統(tǒng)中沒有命中則會(huì)在hosts中尋找。
這樣依賴,相當(dāng)于有了 DNS 服務(wù)器,操作系統(tǒng)的緩存和 hosts 文件,能就近(緩存)完成解析就好,不用每次都跑到很遠(yuǎn)的地方去解析,這樣大大減輕的 DNS 服務(wù)器的壓力。畫了一個(gè)圖,加深印象
DNS解析過程
嗯?想必應(yīng)該知道這個(gè)過程了,我們?cè)倥e個(gè)例子,假設(shè)我們?cè)L問www.qq.com
客戶端發(fā)送一個(gè) DNS 請(qǐng)求,請(qǐng)問 qq 你的IP的什么啊,同時(shí)會(huì)在本地域名服務(wù)器(一般是網(wǎng)絡(luò)服務(wù)是臨近機(jī)房)打聲招呼
本地收到請(qǐng)求以后,服務(wù)器會(huì)有個(gè)域名與IP的映射表。如果存在,則會(huì)告訴你,如果想訪問qq,那么你就訪問XX地址。不存在則會(huì)去問上級(jí)(根域服務(wù)器):"老鐵,你能告訴我 www.qq.com"的IP么
根 DNS 收到本地 DNS 請(qǐng)求后,發(fā)現(xiàn)是.com,"www.qq.com喲,這個(gè)由.com大哥管理,我馬上給你它的頂級(jí)域名地址,你去問問它就好了"
這個(gè)時(shí)候,本地 DNS 跑去問頂級(jí)域名服務(wù)器,"老哥,能告訴下www.qq.com"的ip地址碼",這些頂級(jí)域名負(fù)責(zé)二級(jí)域名比如qq.com
頂級(jí)域名回復(fù):"小本本記好,我給你 www.qq.com 區(qū)域的權(quán)威 DNS 服務(wù)器地址",它會(huì)告訴你
本地DNS問權(quán)威DNS服務(wù)器:"兄弟,能不能告訴我 www.qq.com 對(duì)應(yīng)IP是啥"
權(quán)威DNS服務(wù)器查詢后將響應(yīng)的IP地址告訴了本地 DNS,本地服務(wù)器將 IP 地址返回給客戶端,從而建立連接。
那如果我們寫段cs程序都得這么麻煩的?不不,上面的是大佬們做好,我們只需要使用相關(guān)庫就好了,這里就得說說Socket庫了。
Socket庫
實(shí)際上,這是一段程序包含在操作系統(tǒng)的 Socket 庫中,我們只需要調(diào)用相關(guān)的庫就可以獲得IP。那 Socket 庫又是個(gè)什么東西?
庫,文庫, Github 倉庫,總之一定是 xxx 的集合。為了簡(jiǎn)便開發(fā),大佬們會(huì)將很多方法封裝為庫,開發(fā)人員直接調(diào)用即可,這樣不僅節(jié)省編程的工作量,也提高開發(fā)的工作效率,但是如果庫出了問題,你就可能不是 GG 半會(huì)兒了。Socket 亦是如此,提供了一些網(wǎng)絡(luò)編程相關(guān)的庫,方便開發(fā)人員調(diào)用操作系統(tǒng)的網(wǎng)絡(luò)功能。如下圖,當(dāng)我們調(diào)用 gethostbyname 的時(shí)候,就會(huì)向 DNS 服務(wù)器發(fā)送查詢消息,然后 DNS 服務(wù)器進(jìn)行響應(yīng)。響應(yīng)的信息就會(huì)包含查詢到的IP地址,解析器取出IP地址并寫入指定的內(nèi)存中,瀏覽器只需要從內(nèi)存地址中取出 IP 地址然后加上HTTP請(qǐng)求信息交給操作系統(tǒng)大哥即可
現(xiàn)在我們拿到了 IP 地址,就可以委托協(xié)議棧向這個(gè)目標(biāo) IP 發(fā)送信息了,下面我看看使用Socket庫發(fā)送數(shù)據(jù)的過程
理解下上圖,服務(wù)端創(chuàng)建套接字,我們可以想象為一個(gè)水管,當(dāng)服務(wù)端監(jiān)聽進(jìn)入等待狀態(tài)后,客戶端就可以連接服務(wù)端并塞數(shù)據(jù)到管子中,進(jìn)行數(shù)據(jù)的收發(fā)。當(dāng)然,如果不想聊天了,任何一方都可以斷開,套接字隨機(jī)也就斷開,通信結(jié)束。總結(jié)為這幾個(gè)階段
創(chuàng)建套接字階段
管子連接到服務(wù)端套接字
收發(fā)數(shù)據(jù)
斷開并刪除套接字
那么再具體的實(shí)現(xiàn)中是怎樣的呢?
創(chuàng)建套接字,調(diào)用socket函數(shù)會(huì)返回一個(gè)描述符,這個(gè)描述符類似于門牌號(hào),通過門牌號(hào)就可知道你住在那一房間。隨后的通信直接關(guān)聯(lián)此描述符即可
連接
創(chuàng)建完套接字,我們就得開始建立連接了,可是還是需要協(xié)議棧的幫忙,那么協(xié)議棧都干了啥呢?
我們從上到下來刮一遍
最上面是網(wǎng)絡(luò)應(yīng)用程序,其中包含了瀏覽器,郵件客戶端等,緊接著是Socket庫,其中一個(gè)功能就是向 DNS服務(wù)器發(fā)出請(qǐng)求獲取IP。
往下是操作系統(tǒng)大哥內(nèi)臟,其中包含了協(xié)議棧。上面是傳輸層常見的TCP和UDP,分別負(fù)責(zé) TCP 協(xié)議的收發(fā)數(shù)據(jù)和 UD P的首發(fā)數(shù)據(jù)。
往下是IP,控制網(wǎng)絡(luò)數(shù)據(jù)包的收發(fā)操作。主要負(fù)責(zé)將網(wǎng)絡(luò)數(shù)據(jù)包發(fā)送給通信對(duì)象。其中包含ICMP,ARP等協(xié)議。其中ICMP主要負(fù)責(zé)告知網(wǎng)絡(luò)數(shù)據(jù)包在發(fā)送的過程中產(chǎn)生的錯(cuò)誤信息,ARP負(fù)責(zé)根據(jù)IP地質(zhì)查詢MAC地質(zhì)
再往下就是網(wǎng)卡驅(qū)動(dòng)負(fù)責(zé)的硬件網(wǎng)卡了。直白點(diǎn)說是對(duì)網(wǎng)線的信號(hào)執(zhí)行發(fā)送接收操作
將剛才我們創(chuàng)建的客戶端套接字與服務(wù)器那邊的套接字連接上。使用的函數(shù)為connect,其中需要三個(gè)參數(shù):
- 描述符
connnet會(huì)將描述符告訴協(xié)議棧,協(xié)議棧知道描述符后就來判斷到底使用哪個(gè)套接字去連接服務(wù)端
- 地址
這個(gè)IP地址即使剛才我們通過DNS獲取的IP地址,并將IP地址告知協(xié)議棧
- 端口
IP地址是用來區(qū)分網(wǎng)絡(luò)中各個(gè)計(jì)算機(jī)而分配的數(shù)值。可以理解為公安局的公用電話,我們打電話過去找某人還需要知道名字吧,不然打過去找誰?這個(gè)某某人就類似端口號(hào),根據(jù)這個(gè)端口號(hào)我們能找到具體的聯(lián)系人。所以通過IP+端口的方式確定具體的套接字。端口號(hào)那么多,到底指定多少端口?不慌,其實(shí)服務(wù)器上面使用的大部分端口都事先定義好了,比如HTTP多為80,SMPT通常為35端口。這樣子就可以正兒八經(jīng)的通信了
通信
一旦套接字建立連接,隨著就可以委托協(xié)議棧完成數(shù)據(jù)的發(fā)送操作。具體流程
應(yīng)用程序準(zhǔn)備好需要發(fā)送的數(shù)據(jù)
構(gòu)造HTTP請(qǐng)求信息
調(diào)用write委托協(xié)議棧發(fā)送數(shù)據(jù)
那連接的真正含義是什么?
在真正的實(shí)體情況下,所謂連接通常是網(wǎng)線的連接,網(wǎng)線確實(shí)一直連接著,在這里,連接的意思是通信的雙方能夠交換控制信息,并在套接字中記錄這些信息。
- 連接意義之一是告知協(xié)議棧IP和端口
當(dāng)創(chuàng)建完套接字以后,并沒有存放任何的數(shù)據(jù),自然也就不知道和誰說話。這個(gè)時(shí)候,如果應(yīng)用程序要求發(fā)送數(shù)據(jù),對(duì)于協(xié)議棧而言還是一臉懵逼。只有將IP和端口告知協(xié)議棧,他才會(huì)開始干活
服務(wù)端通過Socket庫中的read接收消息,這里注意,調(diào)用read的時(shí)候需要制定用于存放響應(yīng)消息的內(nèi)存地址,也叫做接收緩存區(qū)。
- 連接意義二:
服務(wù)端創(chuàng)建套接字,但是不知道和誰通信。所以等待客戶端告知"我是XX,我的IP是xxx,端口號(hào)是XXX"
具體操作步驟
通過connect將IP地址和端口信息傳遞給協(xié)議棧的TCP模塊,它會(huì)和服務(wù)端的TCP模塊交換信息。具體交換哪些信息呢。客戶端準(zhǔn)確找到服務(wù)端以后,會(huì)將頭部控制位中的SYN置為1。TCP 模塊將信息傳遞給IP模塊并委托它進(jìn)行發(fā)送,服務(wù)端將接收到的IP模塊傳送給TCP模塊 ,TCP模塊根據(jù)控制信息找到端口號(hào)相同的套接字并將狀態(tài)修改為正在連接。此時(shí)將會(huì)進(jìn)行響應(yīng),響應(yīng)的過程中將ACK控制位設(shè)置為1表示已經(jīng)收到對(duì)應(yīng)的網(wǎng)絡(luò)包。TCP屬于全雙工通信,為了盡全力保證網(wǎng)絡(luò)傳輸信息的不丟失,會(huì)進(jìn)行雙方確認(rèn)機(jī)制。
此時(shí)網(wǎng)絡(luò)包到達(dá)客戶端,通過IP模塊到達(dá)TCP模塊,TCP模塊通過頭部信息確認(rèn)連接服務(wù)器的這個(gè)操作是否成果。如果此時(shí)SYN為1則表示連接成功。然后將響應(yīng)中的ACK設(shè)置1告訴服務(wù)器你的響應(yīng)我收到了。這樣連接操作完成。控制流程交給應(yīng)用程序
6 應(yīng)用階段
當(dāng)連接后到達(dá)應(yīng)用程序后,此時(shí)將決定我們需要發(fā)送什么數(shù)據(jù) ,怎么發(fā)數(shù)據(jù),是按照流的方式還是逐字節(jié)發(fā)送,以及發(fā)什么內(nèi)容,這樣的多樣性對(duì)于協(xié)議棧而言是不怎么關(guān)心的。對(duì)于協(xié)議棧,它不會(huì)是收到什么數(shù)據(jù)就馬上發(fā)送,它會(huì)將數(shù)據(jù)先暫存緩沖區(qū),如果收到數(shù)據(jù)就發(fā)送,難免會(huì)出現(xiàn)大量的小包,這樣會(huì)讓網(wǎng)絡(luò)效率下降。那對(duì)于協(xié)議棧而言,到底一次滿足多少才進(jìn)行發(fā)送呢?
- 根據(jù)MTU判斷
MTU是一個(gè)網(wǎng)絡(luò)的最大長度,以太網(wǎng)中為1500字節(jié),減去MTU的頭部長度,所能容納的最大數(shù)據(jù)長度為1460即MSS。這樣就可避免出現(xiàn)大量的小包問題
- 根據(jù)時(shí)間。
協(xié)議棧內(nèi)部有個(gè)計(jì)時(shí)器,到達(dá)時(shí)間就將網(wǎng)絡(luò)包發(fā)送出去。
仔細(xì)理解這兩點(diǎn),你會(huì)發(fā)現(xiàn)兩者沖突了。因?yàn)槿绻紤]長度的優(yōu)先級(jí)更高,那么網(wǎng)絡(luò)效率高,但是可能等待緩沖區(qū)的時(shí)間比較長。如果時(shí)間優(yōu)先級(jí)更高,延遲時(shí)間就短,但是降低了網(wǎng)絡(luò)效率。所以在應(yīng)用程序中提供了選項(xiàng),在開發(fā)的過程中可以根據(jù)實(shí)際情況進(jìn)行設(shè)置。
如果HTTP請(qǐng)求消息太長了怎么辦呢?
數(shù)據(jù)大了則進(jìn)行拆分,拆分后為了能完整組裝,每個(gè)小塊提前做好標(biāo)識(shí)。當(dāng)判斷需要發(fā)送這些數(shù)據(jù)的時(shí)候,就在每一塊的數(shù)據(jù)前面加上TCP頭部,然后交給IP模塊進(jìn)行數(shù)據(jù)的發(fā)送 。
ACK確認(rèn)機(jī)制
如果能發(fā)出數(shù)據(jù),但是我們發(fā)了數(shù)據(jù)卻不知道是否已經(jīng)收到,或者中途有沒有出現(xiàn)損失數(shù)據(jù)卻不知情。所以,引入ACK的確認(rèn)機(jī)制進(jìn)行可靠的傳輸。
我們客戶端在發(fā)送數(shù)據(jù)的時(shí)候,會(huì)告知對(duì)方發(fā)送的數(shù)據(jù)從第幾個(gè)字節(jié)開始且長度是多少,對(duì)于接收方而言也是能很好地清楚是否完整的接收。比如上次接收到的是520字節(jié),那么接下來收到的包是521,說明中間沒什么問題。如果收到的包是1314,中間這段時(shí)間可能就出軌了。這樣子,如果沒有遺漏,接收方就會(huì)將一共接收到了多少字節(jié)寫到ACK中并發(fā)送給對(duì)方。不知道大家理解沒有,我再換個(gè)方式說一遍。發(fā)送電報(bào):“我現(xiàn)在發(fā)送的數(shù)據(jù)是從XX字節(jié)開始的部分,一共有XX字節(jié)哈”,接收端:“到XX字節(jié)之前的數(shù)據(jù)我都接收完了",這就是確認(rèn)機(jī)制。在此跑一個(gè)面試題,為什么序號(hào)不是從"1"開始?
TCP正是采用這樣的確認(rèn)機(jī)制,數(shù)據(jù)在傳輸過程中,在諸如網(wǎng)絡(luò)集線器等設(shè)備就不在有錯(cuò)誤補(bǔ)償機(jī)制,這些設(shè)備檢測(cè)到錯(cuò)誤就直接丟棄相應(yīng)的包。TCP采用ACK的確認(rèn)機(jī)制,這個(gè)確認(rèn)的回復(fù)時(shí)間是根據(jù)什么來定?是固定時(shí)間內(nèi)必須返回ACK呢,還是會(huì)根據(jù)距離遠(yuǎn)近等動(dòng)態(tài)調(diào)整呢?
通常來說,在局域網(wǎng)中ACK的返回相對(duì)會(huì)比互聯(lián)網(wǎng)返回所需時(shí)間更短。TCP采用動(dòng)態(tài)調(diào)整等待時(shí)間的方法。這里所說的等待時(shí)間是根據(jù)ACK返回所需時(shí)間來判斷的。也就是說TCP在發(fā)送數(shù)據(jù)后就會(huì)持續(xù)觀測(cè)ACK返回時(shí)間,如果發(fā)現(xiàn)慢了則會(huì)延長等待的時(shí)間。
我們每發(fā)一個(gè)包,等待確認(rèn)后再發(fā)送另一個(gè)包。那么在等待的這個(gè)過程是不是就浪費(fèi)了時(shí)間呢。為了改變這樣的情況,TCP采用了滑動(dòng)窗口的方式管理數(shù)據(jù)發(fā)送和ACK號(hào)的操作。
滑動(dòng)窗口
發(fā)送一個(gè)包后,不傻等ACK的返回,而是繼續(xù)發(fā)送后續(xù)的包,這樣就充分的利用這段空閑時(shí)間。但是這樣也出現(xiàn)了一個(gè)問題,可能出現(xiàn)發(fā)送包的頻率太快以致于接收方處理不過來出現(xiàn)堆積。
首先,TCP接收方收到包以后,并不是馬上處理交給應(yīng)用程序,而是先存在暫存區(qū),但是發(fā)送方實(shí)在是太快了,接收方處理不過來,暫存區(qū)也滿了。怎么解決?我們希望發(fā)送方能夠隨時(shí)知道接收方的接收數(shù)據(jù)能力,這樣就不會(huì)無腦的扔數(shù)據(jù)過去了。ok,TCP 就是這樣處理的,它會(huì)告訴發(fā)送方自己最多還能處理多少數(shù)據(jù),然后發(fā)送方就會(huì)根據(jù)接收方的大小進(jìn)行數(shù)據(jù)發(fā)送控制,這也就是滑動(dòng)窗口的精髓所在。
通過這樣長途跋涉終于發(fā)送了HTTP請(qǐng)求信息,等待著響應(yīng)信息,客戶端通過read獲取響應(yīng)信息,和發(fā)送數(shù)據(jù)時(shí)協(xié)議棧工作類似,從接收緩沖區(qū)中取出數(shù)據(jù)并傳遞給應(yīng)用程序
斷開連接
在 Web 使用的HTTP協(xié)議規(guī)定,如果web服務(wù)器發(fā)送完消息后,就應(yīng)該主動(dòng)的斷開操作。客戶端知道斷開后,就當(dāng)再執(zhí)行read調(diào)用時(shí)就會(huì)被提醒收發(fā)數(shù)據(jù)已結(jié)束,隨即也調(diào)用 close 進(jìn)行斷開操作。前面我們說過,每獲取一次數(shù)據(jù)就會(huì)執(zhí)行一次連接,這樣的效率是非常低的,所以在 HTTP1.1 中就可以一次連接多次請(qǐng)求和響應(yīng)。·
假設(shè)服務(wù)器端調(diào)用close程序,此時(shí)協(xié)議棧會(huì)生成斷開信息的TCP頭部,也就是將控制位中的FIN置為1,然后委托給IP模塊向客戶端發(fā)送數(shù)據(jù)
客戶端收到服務(wù)端的 Fin 為1的包后,為了告知服務(wù)端已經(jīng)收到了這個(gè) Fin 包,會(huì)返回一個(gè)ACK號(hào),等待應(yīng)用程序來處理數(shù)據(jù)。當(dāng)應(yīng)用程序調(diào)用read的時(shí)候,發(fā)現(xiàn)服務(wù)端告訴它的是數(shù)據(jù)已經(jīng)全部收到,所以客戶端隨即開始關(guān)閉操作,生成FIN比特為1的TCP包,然后交給IP模塊發(fā)送給服務(wù)器,然后服務(wù)端段返回 ACK 表示收到。這樣客戶端與服務(wù)端全部關(guān)閉結(jié)束。
7 IP
上面講述了想要實(shí)現(xiàn)通信,在TCP連接揮手時(shí)需要請(qǐng)IP模塊幫忙并封裝為包發(fā)送給就近的網(wǎng)絡(luò)設(shè)備,網(wǎng)絡(luò)設(shè)備根據(jù)頭部控制信息確定目的地址,如何確定的呢?轉(zhuǎn)發(fā)設(shè)備中有一張映射表,其中表中能表示"你可以將包發(fā)送到XX目的地",此時(shí)IP協(xié)議再委托以太網(wǎng)協(xié)議,尋找路由器的以太網(wǎng)地址(mac地址),如果有多個(gè)轉(zhuǎn)發(fā)設(shè)備,原理過程一樣,最終到達(dá)接收方的網(wǎng)絡(luò)設(shè)備。
整個(gè)流程算是了解了,我們繼續(xù)深究下IP模板到底是如何完成收發(fā)操作的。當(dāng)TCP委托IP模塊進(jìn)行數(shù)據(jù)包傳送的時(shí)候,告訴了目的地址是在哪里,然后經(jīng)過一系列的中間網(wǎng)絡(luò)設(shè)備尋找以太網(wǎng)地址也就是mac地址,所以現(xiàn)在擁有了IP頭部和mac頭部,發(fā)送給網(wǎng)卡等硬件設(shè)備,網(wǎng)卡將數(shù)字信息轉(zhuǎn)換為電信號(hào)或光信號(hào)并發(fā)送出去。
當(dāng)接收方收到數(shù)據(jù)包會(huì)做出響應(yīng),其路線相反。數(shù)據(jù)包以電信號(hào)的方式從網(wǎng)線發(fā)出,傳遞給IP模塊,IP模塊將MAC頭部、IP頭部后面數(shù)據(jù)傳遞給TCP模塊
IP地址通過TCP模塊獲取目的地址,而TCP模塊是從應(yīng)用程序中獲取IP地址,對(duì)于IP模塊而言,只是乖乖的將包發(fā)往應(yīng)用程序指定的接收方,那假設(shè)這個(gè)IP地址是錯(cuò)誤的怎么辦呢,IP模塊不管,他只是負(fù)責(zé)打個(gè)包發(fā)出去,因?yàn)檫@個(gè)事兒是應(yīng)用程序的任務(wù)。現(xiàn)在我們已經(jīng)知道IP模塊中有填寫目的IP地址,還有哪些重要的控制信息呢
從上圖我們發(fā)現(xiàn)還需要32字節(jié)的發(fā)送方IP地址,如果當(dāng)前計(jì)算機(jī)只有一張網(wǎng)卡,那就是計(jì)算機(jī)的IP地址。
- 協(xié)議號(hào):代表包從哪個(gè)模塊來。如果是TCP模塊則填寫06,如果是UDP模塊填寫17。
MAC
生成了IP頭部后,需要在IP頭部加上MAC頭部,其中包含了接收方和發(fā)送方的MAC地址信息,因?yàn)樵谝蕴W(wǎng)的世界里需要按照以太網(wǎng)的規(guī)則辦事兒
- 以太網(wǎng)類型
以太網(wǎng)類型代表后面內(nèi)容的類型,比如如果是IP地址相關(guān)則為0800
- 發(fā)送方MAC地址
MAC地址在網(wǎng)卡生產(chǎn)時(shí)就放入ROM中,取出存放于MAC頭部即可。
- 接收方MAC地址
要知道接收方的MAC地址,又需要找?guī)褪至?ARP),在局域網(wǎng)中大喊一聲“xx這個(gè)IP地址是哪個(gè)?麻煩把你的MAC地址告訴我”,此時(shí)就有人給予回應(yīng)"這是我的IP地址,我的MAC地址是XX",但是我們不可能每次都一頓喊,所以就有殺手锏"ARP緩存",一次詢問后就會(huì)保存于緩存表中,下次再來如果能匹配到表就可直接獲取MAC地址。
此時(shí)IP模塊完成所有任務(wù)。下面就到網(wǎng)卡
8 網(wǎng)卡
上面辛辛苦苦的將包組裝完成,但都是數(shù)字信息,我們需要轉(zhuǎn)換為電信號(hào)或者光信號(hào)才能在網(wǎng)絡(luò)上傳輸,這就網(wǎng)卡的作用。但是就當(dāng)當(dāng)?shù)囊粔K網(wǎng)卡能干啥,啥也干不了,他需要插上去并裝上網(wǎng)卡驅(qū)動(dòng),計(jì)算機(jī)開機(jī)啟動(dòng)之時(shí)對(duì)網(wǎng)卡進(jìn)行初始化才能開始使用。
網(wǎng)卡驅(qū)動(dòng)從IP模塊獲取包之后,復(fù)制到網(wǎng)卡緩沖區(qū),然后告知MAC層,MAC模塊從緩沖區(qū)取出包并加上頭部和起始幀,末尾加上幀校驗(yàn)序列
發(fā)送信號(hào)分為兩種方式,一種是集線器方式,一種是交換機(jī)的全雙工模式。
集線器方式
發(fā)送信號(hào)之前需要先檢查線路中是否存在其他信號(hào),以免造成沖突。MAC模塊從頭部開始逐比特轉(zhuǎn)換為電信號(hào),然后交給 PHY 模塊發(fā)送出去,PHY模塊將信號(hào)轉(zhuǎn)換為可以在網(wǎng)線上傳輸?shù)母袷讲⑼ㄟ^網(wǎng)線發(fā)送出去。但是我們知道,由于電磁波接觸到金屬等半導(dǎo)體后會(huì)產(chǎn)生電流,與信號(hào)摻雜在一起,這樣勢(shì)必就會(huì)對(duì)原有的信號(hào)造成影響,為了盡量的避免這種影響,使用了雙絞線的方式來抑制噪聲。為什么雙絞線就可以抑制噪聲嘞,因?yàn)楫?dāng)電磁波接觸到信號(hào)線時(shí),假設(shè)電流方向?yàn)橛遥?dāng)使用雙絞線的方式螺旋纏繞后,兩個(gè)信號(hào)線所產(chǎn)生的的電流方向就會(huì)相反,從而相當(dāng)于負(fù)負(fù)得正低效,不的不說闊學(xué)家們牛掰
全雙工模式
全雙工模式可以讓發(fā)送和接收操作同時(shí)進(jìn)行且不產(chǎn)生碰撞,因?yàn)樵谌p工模式下,無需等待其他信號(hào)就可發(fā)送信號(hào),所以比半雙工更快
接收方
在半雙工的通信過程中,發(fā)送信號(hào)到達(dá)結(jié)合搜模塊,信號(hào)的開頭是報(bào)頭,從起始幀分隔符開始將后面的信號(hào)轉(zhuǎn)換為數(shù)字信息,即 PHY模塊 先開始工作,將信號(hào)轉(zhuǎn)換為通用格式并交付給MAC模塊,MAC模塊從頭開始將信號(hào)轉(zhuǎn)換為數(shù)字信號(hào)并存放緩沖區(qū),這里注意,到達(dá)信號(hào)末尾的時(shí)候需要檢查FCS,檢查方法是通過響應(yīng)算法計(jì)算出結(jié)果并和包末尾比較,如果不一致則會(huì)當(dāng)做錯(cuò)誤包丟棄。FCS沒問題,再通過MAC頭部接收方的地址查看是否給自己的包,如果不是也就沒必要亂收,直接丟棄,如果MAC地址一致則將包存放緩沖區(qū),此時(shí)MAC模塊完成任務(wù)。
我們知道計(jì)算機(jī)會(huì)執(zhí)行千萬種任務(wù),它不會(huì)隨時(shí)監(jiān)控網(wǎng)卡的行蹤,所以需要打斷計(jì)算機(jī)當(dāng)前執(zhí)行的任務(wù),告訴它網(wǎng)卡現(xiàn)在發(fā)生的事情,這就是中斷。網(wǎng)卡驅(qū)動(dòng)被中斷處理程序調(diào)用后,會(huì)從網(wǎng)卡的緩沖區(qū)中取出收到的包,并通過 MAC 頭部中的以太類型字段判斷協(xié)議的類型,如果是0080則代表IP協(xié)議,那么網(wǎng)卡驅(qū)動(dòng)就講這樣包給TCP/IP協(xié)議棧。此時(shí)IP模塊開始工作
檢查IP頭部,保證格式正確
查看接收方IP,如果接收的IP地址與客戶端發(fā)送過來IP一致則接受這個(gè)包,否則就很可能除了問題,此時(shí)IP模塊會(huì)通過ICMP將錯(cuò)誤告知發(fā)送方,ICMP包含了哪些錯(cuò)誤提示呢,總結(jié)如下
此時(shí)IP模塊交給TCP模塊,TCP模塊根據(jù)IP頭部的接收方和發(fā)送方IP地址,以及TCP頭部的的發(fā)送,接收端口信息,組成<發(fā)送地址,接收地址,源端口,目的端口>四元組信息查找對(duì)應(yīng)的套接字,從而可查看通信的狀態(tài)并執(zhí)行相關(guān)的通信。
9 防火墻
看似一切到達(dá)服務(wù)器還比較順利,順利歸順利,但是我們的大部分項(xiàng)目中不得不考慮安全因素,不是什么數(shù)據(jù)包都可以隨便進(jìn)來,所以必須使用某種手段過濾掉一部分?jǐn)?shù)據(jù)包,這就是防火墻
不知道大家用過Tcpdump、Wireshark等工具沒,它的過濾機(jī)制類似于防火墻的原理,那么為了實(shí)現(xiàn)過濾,我們就需要深刻了解各層協(xié)議的頭部構(gòu)造,只有熟悉其頭部字段,才能在過濾表達(dá)式中施展魔法。
通過IP 端口等過濾
比如常見明文協(xié)議HTTP使用的80端口,我們可以通過設(shè)置IP+端口的方式限制其他數(shù)據(jù)包的通行。
設(shè)置控制位的方式
比如在TCP三次握手的時(shí)候會(huì)交換或者更新ack syn等信息,我們則可以通過設(shè)置相應(yīng)位置來達(dá)到我們過濾的目的
隨著系統(tǒng)越來與牛逼,收益越來越來,老板跑來:“小伙計(jì),用戶反映請(qǐng)求后半天收不到消息誒”。豈不是廢話么,系統(tǒng)做得好,跑路少不了,錢不到手,怎敢跑路,成,一頓性能測(cè)試猛如虎,哎呀,加個(gè)負(fù)載均衡試試?
負(fù)載均衡
隨著用戶訪問量的劇增,單臺(tái)服務(wù)器明顯感覺到了壓力,再這樣下去用戶可能直接要干我,同事小A牛逼啊,上來就是:"上性能高一點(diǎn)的服務(wù)器啊",小B也不賴:“多買幾臺(tái)服務(wù)器不就完事了?” 好,我們就聽聽小B的方案
從曾經(jīng)的一臺(tái)服務(wù)器,增加到現(xiàn)在到五臺(tái)服務(wù)器,相當(dāng)于每臺(tái)服務(wù)器分擔(dān)1/5,這樣壓力自然小了很多,那問題來了,怎么才能將請(qǐng)求分散到各臺(tái)服務(wù)器呢?哪都有哪些負(fù)載均衡的方案?
砸錢
最初實(shí)現(xiàn)負(fù)載均衡采取的方案很直接,直接上硬件,當(dāng)然也就比較貴,互聯(lián)網(wǎng)的普及,和各位科學(xué)家的無私奉獻(xiàn),各個(gè)企業(yè)開始部署自己的方案,從而出現(xiàn)負(fù)載均衡服務(wù)器
HTTP重定向負(fù)載均衡
也屬于比較直接,當(dāng)HTTP請(qǐng)求到達(dá)負(fù)載均衡服務(wù)器后,使用一套負(fù)載均衡算法計(jì)算到后端服務(wù)器的地址,然后將新的地址給用戶瀏覽器,瀏覽器收到重定向響應(yīng)后發(fā)送請(qǐng)求到新的應(yīng)用服務(wù)器從而實(shí)現(xiàn)負(fù)載均衡,如下圖所示
優(yōu)點(diǎn):
- 簡(jiǎn)單,如果是java開發(fā)工程師,只需要servlet中幾句代碼即可
缺點(diǎn):
加大請(qǐng)求的工作量。第一次請(qǐng)求給負(fù)載均衡服務(wù)器,第二次請(qǐng)求給應(yīng)用服務(wù)器
因?yàn)橐扔?jì)算到應(yīng)用服務(wù)器的IP地址,所以IP地址可能暴露在公網(wǎng),既然暴露在了公網(wǎng)還有什么安全可言
DNS負(fù)載均衡
了解計(jì)算機(jī)網(wǎng)絡(luò)的你應(yīng)該很清楚如何獲取IP地址,其中比較常見的就是DNS解析獲取IP地址。用戶通過瀏覽器發(fā)起HTTP請(qǐng)求的時(shí)候,DNS通過對(duì)域名進(jìn)行即系得到IP地址,用戶委托協(xié)議棧的IP地址簡(jiǎn)歷HTTP連接訪問真正的服務(wù)器。這樣不同的用戶進(jìn)行域名解析將會(huì)獲取不同的IP地址從而實(shí)現(xiàn)負(fù)載均衡
乍一看,和HTTP重定向的方案不是很相似嗎而且還有DNS解析這一步驟,也會(huì)解析出IP地址,不一樣的暴露?每次都需要解析嗎,當(dāng)然不,通常本機(jī)就會(huì)有緩存,在實(shí)際的工程項(xiàng)目中通常是怎么樣的呢
通過DNS解析獲取負(fù)載均衡集群某臺(tái)服務(wù)器的地址
負(fù)載均衡服務(wù)器再一次獲取某臺(tái)應(yīng)用服務(wù)器,這樣子就不會(huì)將應(yīng)用服務(wù)器的IP地址暴露在官網(wǎng)了
反向代理負(fù)載均衡
這里典型的就是Nginx提供的反向代理和負(fù)載均衡功能。用戶的請(qǐng)求直接叨叨反向代理服務(wù)器,服務(wù)器先看本地是緩存過,有直接返回,沒有則發(fā)送給后臺(tái)的應(yīng)用服務(wù)器處理。
IP負(fù)載均衡
上面一種方案是基于應(yīng)用層的,IP很明顯是從網(wǎng)絡(luò)層進(jìn)行負(fù)載均衡。TCP./IP協(xié)議棧是需要上下層結(jié)合的方式達(dá)到目標(biāo),當(dāng)請(qǐng)求到達(dá)網(wǎng)絡(luò)層的時(shí)候。負(fù)載均衡服務(wù)器對(duì)數(shù)據(jù)包中的IP地址進(jìn)行轉(zhuǎn)換,從而發(fā)送給應(yīng)用服務(wù)器
注意,這種方案通常屬于內(nèi)核級(jí)別,如果數(shù)據(jù)比較小還好,但是大部分情況是圖片等資源文件,這樣負(fù)載均衡服務(wù)器會(huì)出現(xiàn)響應(yīng)或者請(qǐng)求過大所帶來的瓶頸
數(shù)據(jù)鏈路負(fù)載均衡
它可以解決因?yàn)閿?shù)據(jù)量他打而導(dǎo)致負(fù)載均衡服務(wù)器帶寬不足這個(gè)問題。怎么實(shí)現(xiàn)的呢。它不修改數(shù)據(jù)包的IP地址,而是更改mac地址。應(yīng)用服務(wù)器和負(fù)載均衡服務(wù)器使用相同的虛擬IP
以上介紹了幾種負(fù)載均衡的方式,但是很重要的負(fù)載均衡算法卻沒有設(shè)計(jì),其中包含了輪詢,隨機(jī),最少連接,下面分別對(duì)此進(jìn)行介紹(假設(shè)以Nginx為例)
輪詢
輪詢是Nginx中默認(rèn)的處理負(fù)載的方式,從方式名稱應(yīng)該可以猜出輪詢即輪流的分配到后端的服務(wù)上。舉個(gè)例子來說,假設(shè)目前后端有4臺(tái)服務(wù)器,此時(shí)過來6個(gè)連接,如果采用輪詢的方式,他就是這樣工作A->1,B->2,C->3,D->4,A->5,B->6
upstream XXX{
server localhost:8081;
server localhost:8082;
server localhost:8083;
}
server {
listen 80;
server_name www.xiaolan.com;
location /{
proxy_pass http://xxx;
}
}
Hash方式處理公式:abs(客戶端ip.hash())%服務(wù)器數(shù)量****
因?yàn)榭蛻舳说膇p地址是唯一不變的,所以,通過hash算法計(jì)算出ip地址對(duì)應(yīng)的哈希碼值,通過哈希碼值對(duì)服務(wù)器的數(shù)量進(jìn)行一個(gè)求模運(yùn)算。這樣就可以保證每個(gè)客戶端訪問的服務(wù)器都是保持不變的,因?yàn)閔ash算法的散列特點(diǎn),也可以近似的當(dāng)作平均分配。
upstream H_xx{
ip_hash;
server localhost:8081;
server localhost:8082;
server localhost:8083;
}
server {
listen 80;
server_name www.xiaolan.com;
location /{
proxy_pass http://H_xx;
}
出現(xiàn)的問題
Hash算法中的散列特點(diǎn),會(huì)導(dǎo)致某臺(tái)服務(wù)器請(qǐng)求量過高,其他服務(wù)器請(qǐng)求卻很少的情況。比如A服務(wù)器處理請(qǐng)求1000,而B服務(wù)器請(qǐng)求只有80,C服務(wù)器請(qǐng)求為20。我們希望后面的請(qǐng)求盡量來C服務(wù)器,所以出現(xiàn)了下面的方案
最小連接方式
采用這種方式,Nginx會(huì)將請(qǐng)求發(fā)送給當(dāng)前處理請(qǐng)求數(shù)量最少的服務(wù)器從而緩解集群的壓力
upstream XXX{
leash_conn;
server localhost:8081;
server localhost:8082;
server localhost:8083;
}
server {
listen 80;
server_name www.xiaolan.com;
location /{
proxy_pass http://XXX;
}
}
既然是將請(qǐng)求分給目前連接數(shù)最少的服務(wù)器,那好,我們看看這種情況。A服務(wù)器買的比較早,承受的并發(fā)數(shù)為200,B服務(wù)器稍微能承受的服務(wù)器并發(fā)數(shù)高一點(diǎn)500,C服務(wù)器能承受的并發(fā)數(shù)為1000。目前各個(gè)服務(wù)器情況如何呢?此時(shí)A服務(wù)器已經(jīng)處理了199個(gè)連接,B服務(wù)器處理了499個(gè)連接,C服務(wù)器處理了500個(gè)連接,我們當(dāng)然希望接下來的請(qǐng)求交給C服務(wù)器處理,不然對(duì)于AB而言豈不是壓死了最后一根稻草,所以出現(xiàn)下面這種方式
基于權(quán)重的方式
通過設(shè)置權(quán)重的方式合理分配請(qǐng)求連接數(shù)
upstream XXX{
server localhost:8081 weight=6;
server localhost:8082 weight=2;
server localhost:8083 down;
}
server {
listen 80;
server_name www.xiaolan.com;
location /{
proxy_pass http://xxx;
}
}
此時(shí)通過weight權(quán)重進(jìn)行資源的分配。down表示當(dāng)前服務(wù)器不參加負(fù)載均衡。
嘮嗑
不知道大家看完是什么感受,寫完就感覺做了一次過山車,根據(jù)相應(yīng)的規(guī)則從下往上組裝頭部,然后從下往上拆分頭部,頭部信息的作用就類似我們的大腦,為了保證上下層的連貫性,需要不同的控制信息來運(yùn)轉(zhuǎn)從而完成使命。生活中也類似,處在什么階段做什么事兒,如果要請(qǐng)求幫助,不是一味地請(qǐng)求幫助,而是在請(qǐng)求幫助的同時(shí)思考自己是否能夠給予類似的籌碼,這就是社會(huì)。
TCP/IP網(wǎng)絡(luò)可說貫徹計(jì)算機(jī)體系的始終,也是非常的復(fù)雜,希望能看見這篇文章的童鞋真要花足功夫去了解計(jì)算機(jī)網(wǎng)絡(luò),當(dāng)然,有不恰當(dāng)?shù)牡胤揭蚕M軒椭姨岢霾⒏?/p>