通過(guò)一個(gè)字符的傳輸來(lái)講解網(wǎng)絡(luò )通信
我們開(kāi)發(fā)的面向普通用戶(hù)的應用程序,目前看來(lái)幾乎都是互聯(lián)網(wǎng)應用程序,也就是說(shuō),用戶(hù)操作的應用程序,不管是瀏覽器還是移動(dòng)App,核心請求都會(huì )通過(guò)互聯(lián)網(wǎng)發(fā)送到后端的數據中心進(jìn)行處理。
本文引用地址:http://dyxdggzs.com/article/202310/451676.htm這個(gè)數據中心可能是像微信這樣的自己建設的、在多個(gè)地區部署的大規模機房,也可能是阿里云這樣的云服務(wù)商提供的一個(gè)虛擬主機。
但是不管這個(gè)數據中心的大小,應用程序都需要在運行期和數據中心交互。比如我們在淘寶的搜索框隨便輸入一個(gè)字符“a”,就會(huì )在屏幕上看到一大堆商品。那么我們的手機是如何通過(guò)互聯(lián)網(wǎng)完成這一操作的?
這個(gè)字符如何穿越遙遠的空間,從手機發(fā)送到淘寶的數據中心,在淘寶計算得到相關(guān)的結果,然后將結果再返回到我們的手機上,從而完成自己的互聯(lián)網(wǎng)之旅呢?
雖然我們在編程的時(shí)候,很少要自己直接開(kāi)發(fā)網(wǎng)絡(luò )通信代碼,服務(wù)器由Tomcat這樣的WEB容器管理網(wǎng)絡(luò )通信,服務(wù)間網(wǎng)絡(luò )通信通過(guò)Dubbo這樣的分布式服務(wù)框架完成網(wǎng)絡(luò )通信。
但是由于我們現在開(kāi)發(fā)的應用主要是互聯(lián)網(wǎng)應用,它們構建在網(wǎng)絡(luò )通信基礎上,網(wǎng)絡(luò )通信的問(wèn)題可能會(huì )出現在系統運行的任何時(shí)刻。
了解網(wǎng)絡(luò )通信原理,了解互聯(lián)網(wǎng)應用如何跨越龐大的網(wǎng)絡(luò )構建起來(lái),對我們開(kāi)發(fā)一個(gè)互聯(lián)網(wǎng)應用系統很有幫助,對我們解決系統運行過(guò)程中各種因為網(wǎng)絡(luò )通信而出現的各種問(wèn)題更有幫助。
DNS
我們先從DNS說(shuō)起。
構成互聯(lián)網(wǎng)Internet的最基本的網(wǎng)絡(luò )協(xié)議就是互聯(lián)網(wǎng)協(xié)議Internet Protocol,簡(jiǎn)稱(chēng)IP協(xié)議。IP協(xié)議里面最重要的部分是IP地址,各種計算機設備之間能夠互相通信,首先要能夠找到彼此,IP地址就是互聯(lián)網(wǎng)的地址標識。
手機上的淘寶App能夠訪(fǎng)問(wèn)淘寶的數據中心,就是知道了淘寶數據中心負責請求接入的服務(wù)器的IP地址,然后建立網(wǎng)絡(luò )連接,進(jìn)而處理請求數據。
那么手機上的淘寶App如何知道數據中心服務(wù)器的IP地址呢?當然淘寶的工程師可以在A(yíng)pp里寫(xiě)死這個(gè)IP地址,但是這樣做會(huì )帶來(lái)很多問(wèn)題,比如影響編程的靈活性以及程序的可用性等。
事實(shí)上這個(gè)IP地址是通過(guò)DNS域名解析服務(wù)器得到的。當我們打開(kāi)淘寶App的時(shí)候,淘寶要把App首頁(yè)加載進(jìn)來(lái),這時(shí)候就需要連接域名服務(wù)器進(jìn)行域名解析,將xxx.taobao.com這樣的域名解析為一個(gè)IP地址,然后連接目標服務(wù)器。
CDN
事實(shí)上DNS解析出來(lái)的IP地址,并不一定是淘寶數據中心的IP地址,也可能是淘寶CDN服務(wù)器的IP地址。
CDN是內容分發(fā)網(wǎng)絡(luò )Content Delivery Network的縮寫(xiě)。我們能夠用手機或者電腦上網(wǎng),是因為運營(yíng)服務(wù)商為我們提供了互聯(lián)網(wǎng)接入服務(wù),將我們的手機和電腦連接到互聯(lián)網(wǎng)上。App請求的數據最先到達的是運營(yíng)服務(wù)商的機房,然后運營(yíng)商通過(guò)自己建設的骨干網(wǎng)絡(luò )和交換節點(diǎn),將我們請求數據的目的地址發(fā)往互聯(lián)網(wǎng)的任何地方。
為了提高用戶(hù)請求訪(fǎng)問(wèn)的速度,也為了降低數據中心的負載壓力,淘寶會(huì )在全國各地各個(gè)主要的運營(yíng)服務(wù)商的接入機房中部署一些緩存服務(wù)器,緩存那些靜態(tài)的圖片、資源文件等,這些緩存服務(wù)器構成了淘寶的CDN。
如果用戶(hù)請求的數據數據是靜態(tài)的資源,這些資源的URL通常以image.taobao.com之類(lèi)的二級域名進(jìn)行標識,域名解析的時(shí)候就會(huì )解析為淘寶CDN的IP地址,請求先被CDN處理,如果CDN中有需要的靜態(tài)文件,就直接返回,如果沒(méi)有,CDN會(huì )將請求發(fā)送到淘寶的數據中心,CDN從淘寶數據中心獲得靜態(tài)文件后,一方面緩存在自己的服務(wù)器上,一方面將數據返回給用戶(hù)的App。
而如果請求的數據是動(dòng)態(tài)的,比如要搜索關(guān)鍵詞為“a”的商品列表,請求的域名可能會(huì )是search.taobao.com這樣的二級域名,就會(huì )直接被DNS解析為淘寶的數據中心的服務(wù)器IP地址,App請求發(fā)送到數據中心處理。
HTTP
不管發(fā)送到CDN還是數據中心,App請求都會(huì )以HTTP協(xié)議發(fā)送。
HTTP是一個(gè)應用層協(xié)議,當我們進(jìn)行網(wǎng)絡(luò )通信編程的時(shí)候,通常需要關(guān)注兩方面的內容,一方面是應用層的通信協(xié)議,主要是我們通信的數據如何編碼,既能使網(wǎng)絡(luò )傳輸過(guò)去的數據攜帶必要的信息,又使通信的兩方都能正確識別這些數據,即通信雙方應用程序需要約定一個(gè)數據編碼協(xié)議。另一方面就是網(wǎng)絡(luò )底層通信協(xié)議,即如何為網(wǎng)絡(luò )上需要通信的兩個(gè)節點(diǎn)建立連接完成數據傳輸,目前互聯(lián)網(wǎng)應用中最主要的就是TCP協(xié)議。
在TCP傳輸層協(xié)議層面,就是保證建立通信兩方的穩定通信連接,將一方的數據以bit流的方式源源不斷地發(fā)送到另一方,至于這些數據代表什么意思,哪里是兩次請求的分界點(diǎn),TCP協(xié)議統統不管,需要應用層面自己解決。如果我們基于TCP協(xié)議自己開(kāi)發(fā)應用程序,就必須解決這些問(wèn)題。而互聯(lián)網(wǎng)應用需要在全球范圍為用戶(hù)提供服務(wù),將全球的應用和全球的用戶(hù)聯(lián)系在一起,需要一個(gè)統一的應用層協(xié)議,這個(gè)協(xié)議就是HTTP協(xié)議。
這張圖是HTTP的請求頭的例子,包括請求方法和請求頭參數。請求方法主要有GET、POST,這是我們最常用的兩種,此外還有DELETE、PUT、HEAD、TRACE等幾種方法;請求頭參數包括緩存控制Cache-Control、響應過(guò)期時(shí)間Expires、Cookie等等。
HTTP請求如果是GET方法,那么就只有請求頭;如果是POST方法,在請求頭之后還有一個(gè)body部分,包含請求提交的內容,HTTP會(huì )在請求頭的Content-Length參數聲明body的長(cháng)度。
這是HTTP響應頭的例子,響應頭和請求頭一樣包含各種參數,而status狀態(tài)碼聲明響應狀態(tài),狀態(tài)碼是200,表示響應正常。
響應狀態(tài)碼是3XX,表示請求被重定向,常用的302,表示請求被臨時(shí)重定向到新的URL,響應頭中包含新的臨時(shí)URL,客戶(hù)端收到響應后,重新請求這個(gè)新的URL;狀態(tài)碼是4XX,表示客戶(hù)端錯誤,常見(jiàn)的403,表示請求未授權,被禁止訪(fǎng)問(wèn),404表示請求的頁(yè)面不存在;狀態(tài)碼是5XX,表示服務(wù)器異常,常見(jiàn)的500請求未完成,502請求處理超時(shí),503服務(wù)器過(guò)載。
如果響應正常,那么在響應頭之后就是響應body,瀏覽器的響應body通常是一個(gè)HTML頁(yè)面,App的響應body通常是個(gè)JSON字符串。
TCP
應用程序使用操作系統的socket接口進(jìn)行網(wǎng)絡(luò )編程,socket里封裝了TCP協(xié)議。應用程序通過(guò)socket接口使用TCP協(xié)議完成網(wǎng)絡(luò )編程,socket或者TCP在應用程序看就是一個(gè)底層通信協(xié)議,事實(shí)上,TCP僅僅是一個(gè)傳輸層協(xié)議,在傳輸層協(xié)議之下,還有網(wǎng)絡(luò )層協(xié)議,網(wǎng)絡(luò )層協(xié)議之下還有數據鏈路層協(xié)議,數據鏈路層協(xié)議之下還有物理層協(xié)議。
傳輸層協(xié)議TCP和網(wǎng)絡(luò )層協(xié)議IP共同構成TCP/IP協(xié)議棧,成為互聯(lián)網(wǎng)應用開(kāi)發(fā)最主要的通信協(xié)議。OSI開(kāi)放系統互聯(lián)模型將網(wǎng)絡(luò )協(xié)議定義了7層,TCP/IP協(xié)議棧將OSI頂部三層協(xié)議應用層、表示層、會(huì )話(huà)層合并為一個(gè)應用層,HTTP協(xié)議就是TCP/IP協(xié)議棧中的應用層協(xié)議。
物理層負責數據的物理傳輸,計算機輸入輸出的只能是0 1這樣的二進(jìn)制數據,但是在真正的通信線(xiàn)路里有光纖、電纜、無(wú)線(xiàn)各種設備。光信號和電信號,以及無(wú)線(xiàn)電磁信號在物理上是完全不同的,如何讓這些不同的設備能夠理解、處理相同的二進(jìn)制數據,這就是物理層要解決的問(wèn)題。
數據鏈路層就是將數據進(jìn)行封裝后交給物理層進(jìn)行傳輸,主要就是將數據封裝成數據幀,以幀為單位通過(guò)物理層進(jìn)行通信,有了幀,就可以在幀上進(jìn)行數據校驗,進(jìn)行流量控制。數據鏈路層會(huì )定義幀的大小,這個(gè)大小也被稱(chēng)為最大傳輸單元。
像HTTP要在傳輸的數據上添加一個(gè)HTTP頭一樣,數據鏈路層也會(huì )將封裝好的幀添加一個(gè)幀頭,幀頭里記錄的一個(gè)重要信息就是發(fā)送者和接受者的mac地址。mac地址是網(wǎng)卡的設備標識符,是唯一的,數據幀通過(guò)這個(gè)信息確保數據送達到正確的目標機器。
前面已經(jīng)提到,網(wǎng)絡(luò )層IP協(xié)議使得互聯(lián)網(wǎng)應用根據IP地址就能訪(fǎng)問(wèn)到淘寶的數據中心,請求離開(kāi)App后,到達運營(yíng)服務(wù)商的交換機,交換機會(huì )根據這個(gè)IP地址進(jìn)行路由轉發(fā),可能中間會(huì )經(jīng)過(guò)很多個(gè)轉發(fā)節點(diǎn),最后數據到達淘寶的服務(wù)器。
網(wǎng)絡(luò )層的數據需要交給鏈路層進(jìn)行處理,而鏈路層幀的大小定義了最大傳輸單元,網(wǎng)絡(luò )層的IP數據包必須要小于最大傳輸單元才能進(jìn)行網(wǎng)絡(luò )傳輸,這個(gè)數據包也有一個(gè)IP頭,主要包括的就是發(fā)送者和接受者的IP地址。
IP協(xié)議不是一個(gè)可靠的通信協(xié)議,并不會(huì )確保數據一定送達。要保證通信的穩定可靠,需要傳輸層協(xié)議TCP。TCP協(xié)議在傳輸正式數據前,會(huì )先建立連接,這就是著(zhù)名的TCP三次握手。
App和服務(wù)器之間發(fā)送三次報文才會(huì )建立一個(gè)TCP連接,報文中的SYN表示請求建立連接,ACK表示確認。App先發(fā)送 SYN=1,Seq=X的報文,表示請求建立連接,X是一個(gè)隨機數;淘寶服務(wù)器收到這個(gè)報文后,應答SYN=1,ACK=X+1,Seq=Y的報文,表示同意建立連接;App收到這個(gè)報文后,檢查ACK的值為自己發(fā)送的Seq值+1,確認建立連接,并發(fā)送ACK=Y+1的報文給服務(wù)器;服務(wù)器收到這個(gè)報文后檢查ACK值為自己發(fā)送的Seq值+1,確認建立連接。至此,App和服務(wù)器建立起TCP連接,就可以進(jìn)行數據傳輸了。
TCP也會(huì )在數據包上添加TCP頭,TCP頭除了包含一些用于校驗數據正確性和控制數據流量的信息外,還包含通信端口信息,一臺機器可能同時(shí)有很多進(jìn)程在進(jìn)行網(wǎng)絡(luò )通信。如何使數據到達服務(wù)器后能發(fā)送給正確的進(jìn)程去處理,就需要靠通信端口進(jìn)行標識了。HTTP默認端口是80,當然我們可以在啟動(dòng)HTTP應用服務(wù)器進(jìn)程的時(shí)候,隨便定義一個(gè)數字作為HTTP應用服務(wù)器進(jìn)程的監聽(tīng)端口,但是App在請求的時(shí)候,必須在URL中包含這個(gè)端口,才能在構建的TCP包中記錄這個(gè)端口,也才能在到達服務(wù)器后,被正確的HTTP服務(wù)器進(jìn)程處理。
如果我們以POST方法提交一個(gè)搜索請求給淘寶服務(wù)器,那么最終在數據鏈路層構建出來(lái)的數據幀大概是這個(gè)樣子,這里假設IP數據包的大小沒(méi)有超過(guò)鏈路層的最大傳輸單元。
App要發(fā)送的數據只是key="a"這樣一個(gè)JSON字符串,每一層協(xié)議都會(huì )在上一層協(xié)議基礎上添加一個(gè)頭部信息,最后封裝成一個(gè)鏈路層的數據幀在網(wǎng)絡(luò )上傳輸,發(fā)送給淘寶的服務(wù)器。淘寶的服務(wù)器在收到這個(gè)數據幀后,在通信協(xié)議的每一層進(jìn)行校驗檢查,確保數據準確后,將頭部信息刪除,再交給自己的上一層協(xié)議處理。HTTP應用服務(wù)器在最上層,負責HTTP協(xié)議的處理,最后將key="a"這個(gè)JSON字符串交給淘寶工程師開(kāi)發(fā)的應用程序處理。
LB(負載均衡)
HTTP請求到達淘寶數據中心的時(shí)候,事實(shí)上也并不是直接發(fā)送給搜索服務(wù)器處理。因為對于淘寶這樣日活用戶(hù)數億的互聯(lián)網(wǎng)應用而言,每時(shí)每刻都有大量的搜索請求到達數據中心,為了使這些海量的搜索請求都能得到及時(shí)處理,淘寶會(huì )部署一個(gè)由數千臺服務(wù)器組成的搜索服務(wù)器集群,共同為這些高并發(fā)的請求提供服務(wù)。
因此,搜索請求到達數據中心的時(shí)候,首先到達的是搜索服務(wù)器集群的負載均衡服務(wù)器,也就是說(shuō),DNS解析出來(lái)的是負載均衡服務(wù)器的IP地址。然后,由負載均衡服務(wù)器將請求分發(fā)到搜索服務(wù)器集群中的某臺服務(wù)器上。
負載均衡服務(wù)器的實(shí)現手段有很多種,淘寶這樣規模的應用,通常使用Linux內核支持的鏈路層負載均衡。
這種負載均衡模式也叫直接路由模式,在負載均衡服務(wù)器的Linux操作系統內核拿到數據包后,直接修改數據幀中的mac地址,將其修改為搜索服務(wù)器集群中某個(gè)服務(wù)器的mac地址,然后將數據重新發(fā)送回服務(wù)器集群所在的局域網(wǎng),這個(gè)數據幀就會(huì )被某個(gè)真實(shí)的搜索服務(wù)器接收到。
負載均衡服務(wù)器和集群內的搜索服務(wù)器配置相同的虛擬IP地址,也就是說(shuō),在網(wǎng)絡(luò )通信的IP層面,負載均衡服務(wù)器變更mac地址的操作是透明的,不影響TCP/IP的通信連接。所以真實(shí)的搜索服務(wù)器處理完搜索請求,發(fā)送應答響應的時(shí)候,就會(huì )直接發(fā)送回請求的App手機,不會(huì )再經(jīng)過(guò)負載均衡服務(wù)器。
總結
事實(shí)上,這個(gè)搜索字符“a”的互聯(lián)網(wǎng)之旅到這里還沒(méi)有結束。淘寶搜索服務(wù)器程序在收到這個(gè)搜索請求的時(shí)候,首先在本地緩存中查找是否有對應的搜索結果。如果沒(méi)有,會(huì )將這個(gè)搜索請求,也就是這個(gè)字符發(fā)送給一個(gè)分布式緩存集群查找是否有對應的搜索結果。如果還沒(méi)有,才會(huì )將這個(gè)請求發(fā)送給一個(gè)更大規模的搜索引擎集群去查找。
這些分布式緩存集群或者搜索引擎集群都需要通過(guò)RPC遠程過(guò)程調用的方式進(jìn)行調用請求,也就是需要通過(guò)網(wǎng)絡(luò )進(jìn)行服務(wù)調用,這些網(wǎng)絡(luò )服務(wù)也都是基于TCP協(xié)議進(jìn)行編程的。
對于互聯(lián)網(wǎng)應用,用戶(hù)請求數據離開(kāi)手機通過(guò)各種網(wǎng)絡(luò )通信,最后到達數據中心的應用服務(wù)器進(jìn)行最后的計算、處理,中間會(huì )經(jīng)過(guò)許多環(huán)節,事實(shí)上,這些環(huán)節就構成了互聯(lián)網(wǎng)系統的整體架構,所以通過(guò)網(wǎng)絡(luò )通信,可以將整個(gè)互聯(lián)網(wǎng)應用系統串起來(lái),對理解互聯(lián)網(wǎng)系統的技術(shù)架構很有幫助,在程序開(kāi)發(fā)、運行過(guò)程中遇到各種網(wǎng)絡(luò )相關(guān)問(wèn)題,也可以快速分析問(wèn)題原因,快速解決問(wèn)題。
評論