只有程序員才能讀懂的西游記
這是一個(gè)有關(guān)計(jì)算機(jī)網(wǎng)絡(luò)協(xié)議的故事
一、我佛造經(jīng)傳極樂(lè)

話說(shuō)我佛如來(lái)為度化天下蒼生,有三藏真經(jīng),可勸人為善。
就如圖中所示,真經(jīng)所藏之處,在于云端。佛祖所管轄之下,有四個(gè)區(qū)域Region,稱(chēng)為四大部洲, 一是東勝神洲,二是南贍部洲,三是西牛賀洲,四是北俱盧洲。
我佛所在西牛賀洲,是主站點(diǎn)。

在每個(gè)區(qū)域Region,為保證真經(jīng)永固,設(shè)置多個(gè)藏經(jīng)樓,稱(chēng)為可用區(qū)(Available Zone)。
每個(gè)藏經(jīng)樓里面是一排一排的柜子,稱(chēng)為機(jī)柜,里面有一排一排的格子,稱(chēng)為服務(wù)器,經(jīng)文就擺放在格子中。



在藏經(jīng)樓中,柜子根據(jù)經(jīng)文分門(mén)別類(lèi)的組織起來(lái),由不同的神仙進(jìn)行管理,管理一個(gè)柜子的經(jīng)文的神仙,訪問(wèn)這里面經(jīng)文的鑰匙就在他手里,稱(chēng)為接入層神仙(接入層交換機(jī))。
多個(gè)接入層神仙被一組匯聚層神仙(匯聚層交換機(jī))管著,多個(gè)匯聚層的神仙被一組核心層神仙(核心交換機(jī))管著。
神仙體系組織嚴(yán)格,層次分明,不同的接入層神仙交換經(jīng)文,要通過(guò)匯聚層神仙同意,不同的匯聚層神仙交換經(jīng)文,需要核心層神仙同意。

經(jīng)文的看守要萬(wàn)無(wú)一失,因而每一層都是分組看護(hù),互相監(jiān)督,互相備份,稱(chēng)為堆疊。
雖說(shuō)每個(gè)柜子里面放滿(mǎn)了經(jīng)文,為了防止經(jīng)文被偷聽(tīng)偷看,經(jīng)文的內(nèi)容是被仙術(shù)封裝在一個(gè)虛擬的私密空間里面,雖然有人可能會(huì)偷到物質(zhì)的經(jīng)文,但是沒(méi)有仙術(shù)打開(kāi)這個(gè)私密空間,看到的經(jīng)文如同空白的一樣。這個(gè)虛擬的私密空間稱(chēng)為VPC。
要解讀經(jīng)文,需要使用每一格中一個(gè)不起眼的法寶,就是稱(chēng)為Openvswitch的虛擬交換機(jī),顧名思義就是起到經(jīng)文在虛擬私密空間和物理空間之間的轉(zhuǎn)換作用。

Openvswitch如何轉(zhuǎn)換呢?使用的是一種稱(chēng)為VXLAN的封裝技術(shù),但是必須要事先知道芝麻開(kāi)門(mén)的ID,也即VXLAN ID,才能看到經(jīng)文的真正內(nèi)容。
在虛擬的空間中,放著真正可以解讀的真經(jīng)。


真經(jīng)有法一藏,談天;論一藏,說(shuō)地;經(jīng)一藏,度鬼;三藏共計(jì)三十五部,該一萬(wàn)五千一百四十四卷,乃是修真之徑,正善之門(mén)。
看來(lái)已經(jīng)前中后臺(tái)分離,分為基礎(chǔ)服務(wù)層,組合服務(wù)層,Controller層,共三十五個(gè)模塊,一萬(wàn)五千多個(gè)服務(wù),真是微服務(wù)架構(gòu)啊。
如何能夠不要迷失在這個(gè)一萬(wàn)五千卷經(jīng)文中,也是很有挑戰(zhàn)的事情,需要一個(gè)索引和指南,這就是常說(shuō)的RPC框架和服務(wù)注冊(cè)與發(fā)現(xiàn)中心。
為了方便諸多僧侶前來(lái)取經(jīng),靈山腳下會(huì)有一個(gè)統(tǒng)一的入口地址,這里有一個(gè)神仙,稱(chēng)為金頂大仙,專(zhuān)門(mén)來(lái)接應(yīng)取經(jīng)人的。

由于前來(lái)取經(jīng)的人很多,同時(shí)經(jīng)文也很多,所以金頂大仙多起到負(fù)載均衡的作用,將不同的取經(jīng)人引領(lǐng)到不同的藏經(jīng)樓,訪問(wèn)不同的經(jīng)文。
金頂大仙所在的靈山腳下,是一個(gè)世界知名的地址,稱(chēng)為外網(wǎng)IP地址,這個(gè)地址是全球可定位的,所有的取經(jīng)人都先到這個(gè)地方,金頂大仙通過(guò)NAT規(guī)則,將外網(wǎng)IP地址,變成藏經(jīng)樓的私有IP地址,例如2號(hào)藏經(jīng)樓三樓,4號(hào)藏經(jīng)樓五樓等。在靈山藏經(jīng)樓里面,是通過(guò)私有IP地址定位的。
真經(jīng)已經(jīng)準(zhǔn)備好,就差東土取經(jīng)人了。
二、觀音奉旨上長(zhǎng)安
可是佛祖愁啊,是這樣說(shuō)的:我待要送上東土,叵耐那方眾生愚蠢,毀謗真言,不識(shí)我法門(mén)之要旨,怠慢了瑜迦之正宗。怎么得一個(gè)有法力的,去東土尋一個(gè)善信.教他苦歷千山,遠(yuǎn)經(jīng)萬(wàn)水,到我處求取真經(jīng),永傳東土,勸他眾生,卻乃是個(gè)山大的福緣,海深的善慶、誰(shuí)肯去走一遭來(lái)?
真經(jīng)就在靈山,可以東土之人愚鈍,不知道靈山咋辦呢?要一個(gè)法力無(wú)邊的人告訴他們呀。而且最好能夠告訴全世界,靈山這里有真經(jīng)。
好在有觀音菩薩,道:“弟子不才,愿上東土尋一個(gè)取經(jīng)人來(lái)也。”,觀音菩薩有什么法力呢?當(dāng)然是BGP協(xié)議了。
剛才那張圖畫(huà)的是一個(gè)可用區(qū)的情況,對(duì)于多個(gè)可用區(qū)的情況,我們可以隱去計(jì)算節(jié)點(diǎn)的情況,將外網(wǎng)訪問(wèn)區(qū)域放大。

外網(wǎng)IP是放在虛擬網(wǎng)關(guān)的外網(wǎng)網(wǎng)口上的,這個(gè)IP如何讓全世界知道呢?在核心交換外面是安全設(shè)備,然后就是邊界路由器。邊界路由器會(huì)和多個(gè)運(yùn)營(yíng)商連接,從而每個(gè)運(yùn)營(yíng)商都能夠訪問(wèn)到這個(gè)網(wǎng)站。邊界路由器可以通過(guò)BGP協(xié)議,將自己數(shù)據(jù)中心里面的外網(wǎng)IP向外廣播,也就是告訴全世界,如果要訪問(wèn)這些外網(wǎng)IP,都來(lái)我這里。
每個(gè)運(yùn)營(yíng)商也有很多的路由器、很多的點(diǎn),于是就可以將如何到達(dá)這些IP地址的路由信息,廣播到全國(guó)乃至全世界。
厲害吧,這是我佛如來(lái)告訴觀音菩薩的:“這一去。要踏看路道,不許在霄漢中行,須是要半云半霧;目過(guò)山水,謹(jǐn)記程途遠(yuǎn)近之?dāng)?shù),叮嚀那取經(jīng)人。“
就是說(shuō)你去東土的路上,經(jīng)過(guò)了哪些道路,要記住路徑,要記住遠(yuǎn)近,才能告訴取經(jīng)人這一路應(yīng)該怎么走。
三、玄奘秉誠(chéng)建大會(huì)
當(dāng)觀音菩薩來(lái)到東土大唐,正看到玄奘法師正坐在高臺(tái)上,帶領(lǐng)眾人誦經(jīng),念一會(huì)《受生度亡經(jīng)》,談一會(huì)《安邦天寶篆》,又宣一會(huì)《勸修功卷》。
菩薩近前來(lái),叫道:“那和尚,你只會(huì)談小乘教法,可會(huì)談大乘么?”玄奘聞言,心中大喜,翻身跳下臺(tái)來(lái),對(duì)菩薩起手道:“老師父,弟子失瞻,多罪。見(jiàn)前的蓋眾僧人,都講的是小乘教法,卻不知大乘教法如何。”菩薩道:“你這小乘教法,度不得亡者超升,只可渾俗和光而已。我有大乘佛法三藏,能超亡者升天,能度難人脫苦,能修無(wú)量壽身,能作無(wú)來(lái)無(wú)去。”



你看,在西方極樂(lè)凈土,我佛已經(jīng)有了更牛的佛經(jīng),遙遠(yuǎn)的東方,還在讀本土的僧人早期從西方傳過(guò)來(lái)的經(jīng)。
這種模式,稱(chēng)為CDN。

我們部署應(yīng)用的時(shí)候,一般會(huì)把靜態(tài)資源保存在兩個(gè)地方,一個(gè)是nginx后面的varnish緩存里面,一般是靜態(tài)頁(yè)面;對(duì)于比較大的、不經(jīng)常更新的靜態(tài)圖片,會(huì)保存在對(duì)象存儲(chǔ)里面。這兩個(gè)地方的靜態(tài)資源都會(huì)配置CDN,將資源下發(fā)到邊緣節(jié)點(diǎn)。
最初佛祖?zhèn)鹘?jīng),都是口口相傳,經(jīng)文都會(huì)記在高僧大德的心里,隨著高僧云游天下,隨著廟宇遍布天下,佛經(jīng)從而遍布天下。這就相當(dāng)于將佛經(jīng)緩存在邊緣節(jié)點(diǎn)。
配置了CDN之后,權(quán)威DNS服務(wù)器上,會(huì)為靜態(tài)資源設(shè)置一個(gè)CNAME別名,指向另外一個(gè)域名cdn.com,返回給本地DNS服務(wù)器。
當(dāng)本地DNS服務(wù)器拿到這個(gè)新的域名時(shí),需要繼續(xù)解析這個(gè)新的域名。這個(gè)時(shí)候,再訪問(wèn)的時(shí)候就不是原來(lái)的權(quán)威DNS服務(wù)器了,而是 cdn.com 的權(quán)威DNS服務(wù)器。這是CDN自己的權(quán)威DNS服務(wù)器。
在這個(gè)服務(wù)器上,還是會(huì)設(shè)置一個(gè)CNAME,指向另外一個(gè)域名,也即CDN網(wǎng)絡(luò)的全局負(fù)載均衡器。
本地DNS服務(wù)器去請(qǐng)求CDN的全局負(fù)載均衡器解析域名,全局負(fù)載均衡器會(huì)為用戶(hù)選擇一臺(tái)合適的緩存服務(wù)器提供服務(wù),將IP返回給客戶(hù)端,客戶(hù)端去訪問(wèn)這個(gè)邊緣節(jié)點(diǎn),下載資源。緩存服務(wù)器響應(yīng)用戶(hù)請(qǐng)求,將用戶(hù)所需內(nèi)容傳送到用戶(hù)終端。
如果這臺(tái)緩存服務(wù)器上并沒(méi)有用戶(hù)想要的內(nèi)容,那么這臺(tái)服務(wù)器就要向它的上一級(jí)緩存服務(wù)器請(qǐng)求內(nèi)容,直至追溯到網(wǎng)站的源服務(wù)器,將內(nèi)容拉到本地。
CDN的全局負(fù)載均衡策略,就相當(dāng)于當(dāng)僧人們想讀佛經(jīng)的時(shí)候,不必要都去西天,而是可以就近去問(wèn),周?chē)袥](méi)有廟宇,然后向廟宇的師傅去請(qǐng)教佛經(jīng)。
然而緩存的佛經(jīng)當(dāng)然是比不上西天取到的經(jīng)文更新,所以東土由于離西天較遠(yuǎn),緩存的還是小乘佛教,要讀大乘佛教,就要去西天取經(jīng),稱(chēng)為回源。
四、觀音顯像化金蟬
觀音菩薩打算度化玄奘法師,回源去西天取經(jīng)。
可是怎么去呢,地址在哪里呢?玄奘法師只聽(tīng)說(shuō)西天,不知道具體的地址,這就要問(wèn)觀音菩薩了。


這個(gè)時(shí)候,大家才知道,西天在靈山大雷音寺,距此十萬(wàn)八千里。
這個(gè)過(guò)程稱(chēng)為DNS解析。
當(dāng)在手機(jī)上面打開(kāi)一個(gè)App的時(shí)候,首先要做的事情就是解析這個(gè)網(wǎng)站的域名。
在手機(jī)運(yùn)營(yíng)商所在的互聯(lián)網(wǎng)區(qū)域里,有一個(gè)本地的DNS,手機(jī)會(huì)向這個(gè)DNS請(qǐng)求解析DNS。當(dāng)這個(gè)DNS本地有緩存,則直接返回;如果沒(méi)有緩存,本地DNS才需要遞歸地從根DNS服務(wù)器,查到.com的頂級(jí)域名服務(wù)器,最終查到權(quán)威DNS服務(wù)器。
如果你使用云平臺(tái)的時(shí)候,配置了智能DNS和全局負(fù)載均衡,在權(quán)威DNS服務(wù)中,一般是通過(guò)配置CNAME的方式,我們可以起一個(gè)別名,例如 vip.yourcomany.com ,然后告訴本地DNS服務(wù)器,讓它請(qǐng)求GSLB解析這個(gè)域名,GSLB就可以在解析這個(gè)域名的過(guò)程中,通過(guò)自己的策略實(shí)現(xiàn)負(fù)載均衡。
GSLB通過(guò)查看請(qǐng)求它的本地DNS服務(wù)器所在的運(yùn)營(yíng)商和地址,就知道用戶(hù)所在的運(yùn)營(yíng)商和地址,然后將距離用戶(hù)位置比較近的Region里面,將三個(gè)本地負(fù)載均衡的公網(wǎng)IP地址,返回給本地DNS服務(wù)器。本地DNS解析器將結(jié)果緩存后,返回給客戶(hù)端。
對(duì)于手機(jī)APP來(lái)說(shuō),可以繞過(guò)剛才的傳統(tǒng)DNS解析機(jī)制,直接只要HTTPDNS服務(wù),通過(guò)直接調(diào)用HTTPDNS服務(wù)器,得到這三個(gè)本地負(fù)載均衡的公網(wǎng)IP地址。
這個(gè)公網(wǎng)IP地址,就是金頂大仙所在的位置。其實(shí)這個(gè)時(shí)候,金頂大仙已經(jīng)在等待了。
這個(gè)時(shí)候,李世民突然開(kāi)始說(shuō)話了,曰:“誰(shuí)肯領(lǐng)朕旨意,上西天拜佛求經(jīng)?“ 并愿意買(mǎi)下觀音手中的兩件寶物,“錦瀾?hù)卖?rdquo;一領(lǐng),“九環(huán)錫杖”一根,佛祖說(shuō)過(guò):”若有取經(jīng)人堅(jiān)心來(lái)此,穿我的袈裟,免墮輪回;持我的錫枚,不遭毒害。“

玄奘法師回答:“貧僧不才,愿效犬馬之勞,與陛下求取真經(jīng),祈保我王江山永固。”


這個(gè)時(shí)候,菩薩說(shuō)了:“西天路遠(yuǎn),更多虎豹妖魔。只怕有去無(wú)回,難保身命。”
玄奘道:“我已發(fā)了弘誓大愿,不取真經(jīng),永墮沉淪地獄。“


其實(shí)這里的對(duì)話是很有意思的,玄奘法師回復(fù)李世民的和回復(fù)觀音菩薩的不同。
這個(gè)時(shí)候,李世民作為世俗的君王,已經(jīng)想求取真經(jīng)了,也就是東土大唐作為客戶(hù)端,要發(fā)起對(duì)于服務(wù)端的請(qǐng)求了。但是玄奘法師知道,唐王李世民去取經(jīng),求的是江山永固。所以李世民的請(qǐng)求是應(yīng)用層的,發(fā)起的是HTTP的協(xié)議,在HTTP的請(qǐng)求正文中,怕是寫(xiě)的“江山永固”四個(gè)字。
而玄奘法師回復(fù)觀音菩薩的時(shí)候,說(shuō)的就不同了,是一種對(duì)于真經(jīng)和佛法本身的堅(jiān)持。所以玄奘法師是TCP層的,TCP是面向連接的,TCP 是靠譜的協(xié)議,但是這不能說(shuō)明它面臨的網(wǎng)絡(luò)環(huán)境好。從 IP 層面來(lái)講,如果網(wǎng)絡(luò)狀況的確那么差,是沒(méi)有任何可靠性保證的,而作為 IP 的上一層 TCP 也無(wú)能為力,唯一能做的就是更加努力,不斷重傳,通過(guò)各種算法保證。也就是說(shuō),對(duì)于 TCP 來(lái)講,IP 層你丟不丟包,我管不著,但是我在我的層面上,會(huì)努力保證可靠性。
這一點(diǎn)在流沙河有了驗(yàn)證。觀音菩薩度化沙悟凈的時(shí)候,沙悟凈說(shuō):“菩薩,我在此間吃人無(wú)數(shù),向來(lái)有幾次取經(jīng)人來(lái),都被我吃了。凡吃的人頭,拋落流沙,竟沉水底(這個(gè)水,鵝毛也不能浮),惟有九個(gè)取經(jīng)人的骷髏,浮在水面,再不能沉。我以為異物,將索兒穿在一處,閑時(shí)拿來(lái)頑耍,這去,但恐取經(jīng)人不得到此,卻不是反誤了我的前程也?”菩薩日:“豈有不到之理?你可將骷髏地掛在頭頂下,等候取經(jīng)入,自有用處。”


所以沙悟凈脖子上這九個(gè)骷髏,是唐三藏的前九輩子,一旦吃了,就不斷的重試。
為了能夠?qū)崿F(xiàn)重試,實(shí)現(xiàn)TCP的可靠性,客戶(hù)端和服務(wù)器需要建立連接。

HTTPS協(xié)議是基于TCP協(xié)議的,因而要先建立TCP的連接。在這個(gè)例子中,TCP的連接是從手機(jī)上的App和負(fù)載均衡器SLB之間的。也就是唐僧和金頂大仙之間,到了金頂大仙,就不怕了,會(huì)指引到佛祖那里的。
盡管中間要經(jīng)過(guò)很多的路由器和交換機(jī),但是TCP的連接是端到端的。
TCP這一層和更上層的HTTPS無(wú)法看到中間的包的過(guò)程。盡管建立連接的時(shí)候,所有的包都逃不過(guò)在這些路由器和交換機(jī)之間的轉(zhuǎn)發(fā),轉(zhuǎn)發(fā)的細(xì)節(jié)我們放到那個(gè)下單請(qǐng)求的發(fā)送過(guò)程中詳細(xì)解讀,這里只看端到端的行為。
對(duì)于TCP連接來(lái)講,需要通過(guò)三次握手建立連接,為了維護(hù)這個(gè)連接,雙方都需要在TCP層維護(hù)一個(gè)連接的狀態(tài)機(jī)。
一開(kāi)始,客戶(hù)端和服務(wù)端都處于CLOSED狀態(tài)。服務(wù)端先是主動(dòng)監(jiān)聽(tīng)某個(gè)端口,處于LISTEN狀態(tài)。然后客戶(hù)端主動(dòng)發(fā)起連接SYN,之后處于SYN-SENT狀態(tài)。服務(wù)端收到發(fā)起的連接,返回SYN,并且ACK客戶(hù)端的SYN,之后處于SYN-RCVD狀態(tài)。
客戶(hù)端收到服務(wù)端發(fā)送的SYN和ACK之后,發(fā)送ACK的ACK,之后處于ESTABLISHED狀態(tài)。這是因?yàn)椋话l(fā)一收成功了。服務(wù)端收到ACK的ACK之后,處于ESTABLISHED狀態(tài),因?yàn)樗囊话l(fā)一收也成功了。
當(dāng)TCP層的連接建立完畢之后,接下來(lái)輪到HTTPS層建立連接了,在HTTPS的交換過(guò)程中,TCP層始終處于ESTABLISHED。
對(duì)于HTTPS,客戶(hù)端會(huì)發(fā)送Client Hello消息到服務(wù)器,用明文傳輸TLS版本信息、加密套件候選列表、壓縮算法候選列表等信息。另外,還會(huì)有一個(gè)隨機(jī)數(shù),在協(xié)商對(duì)稱(chēng)密鑰的時(shí)候使用。
然后,服務(wù)器會(huì)返回Server Hello消息,告訴客戶(hù)端,服務(wù)器選擇使用的協(xié)議版本、加密套件、壓縮算法等。這也有一個(gè)隨機(jī)數(shù),用于后續(xù)的密鑰協(xié)商。
然后,服務(wù)器會(huì)給你一個(gè)服務(wù)器端的證書(shū),然后說(shuō):“Server Hello Done,我這里就這些信息了。”
客戶(hù)端當(dāng)然不相信這個(gè)證書(shū),于是你從自己信任的CA倉(cāng)庫(kù)中,拿CA的證書(shū)里面的公鑰去解密電商網(wǎng)站的證書(shū)。如果能夠成功,則說(shuō)明電商網(wǎng)站是可信的。這個(gè)過(guò)程中,你可能會(huì)不斷往上追溯CA、CA的CA、CA的CA的CA,反正直到一個(gè)授信的CA,就可以了。
其實(shí)觀音菩薩手里的錫杖和袈裟,就相當(dāng)于佛祖辦法的證書(shū),保證西行路上的安全,玄奘法師這個(gè)網(wǎng)絡(luò)包別被別人吃了,或者篡改。


就像誤入小雷音一集中,白眉老佛想吃了唐僧肉,自己披上袈裟,西天取經(jīng),求得正果。
當(dāng)然,一開(kāi)始觀音菩薩拿出錫杖和袈這個(gè)證書(shū)的時(shí)候,大家也不相信,所以需要觀音菩薩現(xiàn)出真身,作為CA,證明給客戶(hù)端,唐王李世民和玄奘法師才下拜。

證書(shū)驗(yàn)證完畢之后,覺(jué)得這個(gè)服務(wù)端是可信的,于是客戶(hù)端計(jì)算產(chǎn)生隨機(jī)數(shù)字Pre-master,發(fā)送Client Key Exchange,用證書(shū)中的公鑰加密,再發(fā)送給服務(wù)器,服務(wù)器可以通過(guò)私鑰解密出來(lái)。
接下來(lái),無(wú)論是客戶(hù)端還是服務(wù)器,都有了三個(gè)隨機(jī)數(shù),分別是:自己的、對(duì)端的,以及剛生成的Pre-Master隨機(jī)數(shù)。通過(guò)這三個(gè)隨機(jī)數(shù),可以在客戶(hù)端和服務(wù)器產(chǎn)生相同的對(duì)稱(chēng)密鑰。
有了對(duì)稱(chēng)密鑰,客戶(hù)端就可以說(shuō):“Change Cipher Spec,咱們以后都采用協(xié)商的通信密鑰和加密算法進(jìn)行加密通信了。”
然后客戶(hù)端發(fā)送一個(gè)Encrypted Handshake Message,將已經(jīng)商定好的參數(shù)等,采用協(xié)商密鑰進(jìn)行加密,發(fā)送給服務(wù)器用于數(shù)據(jù)與握手驗(yàn)證。
同樣,服務(wù)器也可以發(fā)送Change Cipher Spec,說(shuō):“沒(méi)問(wèn)題,咱們以后都采用協(xié)商的通信密鑰和加密算法進(jìn)行加密通信了”,并且也發(fā)送Encrypted Handshake Message的消息試試。
當(dāng)雙方握手結(jié)束之后,就可以通過(guò)對(duì)稱(chēng)密鑰進(jìn)行加密傳輸了。
五、唐王素酒送三藏
玄奘這個(gè)網(wǎng)絡(luò)包要發(fā)出了。
太宗設(shè)朝,聚集文武,要去送行。李世民送給玄奘三個(gè)東西。
上一節(jié)說(shuō)了太宗是應(yīng)用層,關(guān)注保大唐江山永固,玄奘是TCP層,要通過(guò)堅(jiān)定的意志到達(dá)西天。
李世民給的第一個(gè)東西是通關(guān)文牒,這個(gè)是IP層的,將來(lái)要通過(guò)這個(gè)文牒通過(guò)一個(gè)個(gè)城關(guān)。
第二個(gè)東西是紫金缽盂,這個(gè)用于玄奘法師到了某個(gè)城市里面化齋,同時(shí)打聽(tīng)路的時(shí)候使用,這個(gè)是一個(gè)MAC層的。
第三個(gè)東西是白馬一匹,作為遠(yuǎn)程腳力,這個(gè)是物理層的。
最后,太宗敬了玄奘一杯素酒,言道:寧戀本鄉(xiāng)一捻土,莫愛(ài)他鄉(xiāng)萬(wàn)兩金。三藏方悟捻土之意,復(fù)謝恩飲盡,辭謝出關(guān)而去。
當(dāng)客戶(hù)端和服務(wù)端之間建立了連接后,接下來(lái)就要發(fā)送下單請(qǐng)求的網(wǎng)絡(luò)包了。
在用戶(hù)層發(fā)送的是HTTP的網(wǎng)絡(luò)包,因?yàn)榉?wù)端提供的是RESTful API,因而HTTP層發(fā)送的就是一個(gè)請(qǐng)求。
- POST /purchaseOrder HTTP/1.1
- Host: www.geektime.com
- Content-Type: application/json; charset=utf-8
- Content-Length: nnn
- {
- "order": {
- "date": "2018-07-01",
- "className": "趣談網(wǎng)絡(luò)協(xié)議",
- "Author": "劉超",
- "price": "68"
- }
- }
HTTP的報(bào)文大概分為三大部分。第一部分是請(qǐng)求行,第二部分是請(qǐng)求的首部,第三部分才是請(qǐng)求的正文實(shí)體。
在請(qǐng)求行中,URL就是 www.geektime.com/purchaseOrder ,版本為HTTP 1.1。
請(qǐng)求的類(lèi)型叫作POST,它需要主動(dòng)告訴服務(wù)端一些信息,而非獲取。需要告訴服務(wù)端什么呢?一般會(huì)放在正文里面。正文可以有各種各樣的格式,常見(jiàn)的格式是JSON。
請(qǐng)求行下面就是我們的首部字段。首部是key value,通過(guò)冒號(hào)分隔。
Content-Type是指正文的格式。例如,我們進(jìn)行POST的請(qǐng)求,如果正文是JSON,那么我們就應(yīng)該將這個(gè)值設(shè)置為JSON。
接下來(lái)是正文,這里是一個(gè)JSON字符串,里面通過(guò)文本的形式描述了,要買(mǎi)一個(gè)課程,作者是誰(shuí),多少錢(qián)。
這樣,HTTP請(qǐng)求的報(bào)文格式就拼湊好了。接下來(lái)瀏覽器或者移動(dòng)App會(huì)把它交給下一層傳輸層。
怎么交給傳輸層呢?也是用Socket進(jìn)行程序設(shè)計(jì)。如果用的是瀏覽器,這些程序不需要你自己寫(xiě),有人已經(jīng)幫你寫(xiě)好了;如果在移動(dòng)APP里面,一般會(huì)用一個(gè)HTTP的客戶(hù)端工具來(lái)發(fā)送,并且?guī)湍惴庋b好。
HTTP協(xié)議是基于TCP協(xié)議的,所以它使用面向連接的方式發(fā)送請(qǐng)求,通過(guò)Stream二進(jìn)制流的方式傳給對(duì)方。當(dāng)然,到了TCP層,它會(huì)把二進(jìn)制流變成一個(gè)的報(bào)文段發(fā)送給服務(wù)器。
在TCP頭里面,會(huì)有源端口號(hào)和目標(biāo)端口號(hào),目標(biāo)端口號(hào)一般是服務(wù)端監(jiān)聽(tīng)的端口號(hào),源端口號(hào)在手機(jī)端,往往是隨機(jī)分配一個(gè)端口號(hào)。這個(gè)端口號(hào)在客戶(hù)端和服務(wù)端用于區(qū)分請(qǐng)求和返回,發(fā)給那個(gè)應(yīng)用。
在IP頭里面,都需要加上自己的地址(即源地址)和它想要去的地方(即目標(biāo)地址)。當(dāng)一個(gè)手機(jī)上線的時(shí)候,PGW會(huì)給這個(gè)手機(jī)分配一個(gè)IP地址,這就是源地址,而目標(biāo)地址則是云平臺(tái)的負(fù)載均衡器的外網(wǎng)IP地址。
在IP層,客戶(hù)端需要查看目標(biāo)地址和自己是否是在同一個(gè)局域網(wǎng),計(jì)算是否是同一個(gè)網(wǎng)段,往往需要通過(guò)CIDR子網(wǎng)掩碼來(lái)計(jì)算。
對(duì)于這個(gè)下單場(chǎng)景,目標(biāo)IP和源IP不會(huì)在同一個(gè)網(wǎng)段,因而需要發(fā)送到默認(rèn)的網(wǎng)關(guān)。一般通過(guò)DHCP分配IP地址的時(shí)候,也會(huì)同時(shí)配置默認(rèn)網(wǎng)關(guān)的IP地址。
但是客戶(hù)端不會(huì)直接使用默認(rèn)網(wǎng)關(guān)的IP地址,而是發(fā)送ARP協(xié)議,來(lái)獲取網(wǎng)關(guān)的MAC地址,然后將網(wǎng)關(guān)MAC作為目標(biāo)MAC,自己的MAC作為源MAC,放入MAC頭,發(fā)送出去。

一個(gè)完整的網(wǎng)絡(luò)包的格式是這樣的。

接下來(lái),網(wǎng)絡(luò)包就正式發(fā)出了。
如果你是用手機(jī)打開(kāi)APP,下單購(gòu)物發(fā)送網(wǎng)絡(luò)包,一般通過(guò)手機(jī)運(yùn)營(yíng)商的網(wǎng)絡(luò)。

客戶(hù)的手機(jī)開(kāi)機(jī)以后,在附近尋找基站eNodeB,發(fā)送請(qǐng)求,申請(qǐng)上網(wǎng)?;緦⒄?qǐng)求發(fā)給MME,MME對(duì)手機(jī)進(jìn)行認(rèn)證和鑒權(quán),還會(huì)請(qǐng)求HSS看有沒(méi)有錢(qián),看看是在哪里上網(wǎng)。
當(dāng)MME通過(guò)了手機(jī)的認(rèn)證之后,開(kāi)始建立隧道,建設(shè)的數(shù)據(jù)通路分兩段路,其實(shí)是兩個(gè)隧道。一段是從eNodeB到SGW,第二段是從SGW到PGW,在PGW之外,就是互聯(lián)網(wǎng)。
PGW會(huì)為手機(jī)分配一個(gè)IP地址,手機(jī)上網(wǎng)都是帶著這個(gè)IP地址的。
對(duì)于手機(jī)來(lái)講,默認(rèn)的網(wǎng)關(guān)在PGW上。在移動(dòng)網(wǎng)絡(luò)里面,從手機(jī)到SGW,到PGW是有一條隧道的。在這條隧道里面,會(huì)將上面的這個(gè)包作為隧道的乘客協(xié)議放在里面,外面SGW和PGW在核心網(wǎng)機(jī)房的IP地址。網(wǎng)絡(luò)包直到PGW(PGW是隧道的另一端)才將里面的包解出來(lái),轉(zhuǎn)發(fā)到外部網(wǎng)絡(luò)。
所以,從手機(jī)發(fā)送出來(lái)的時(shí)候,網(wǎng)絡(luò)包的結(jié)構(gòu)為:
- 源MAC:手機(jī)也即UE的MAC;
- 目標(biāo)MAC:網(wǎng)關(guān)PGW上面的隧道端點(diǎn)的MAC;
- 源IP:UE的IP地址;
- 目標(biāo)IP:SLB的公網(wǎng)IP地址。
進(jìn)入隧道之后,要封裝外層的網(wǎng)絡(luò)地址,因而網(wǎng)絡(luò)包的格式為:
- 外層源MAC:E-NodeB的MAC;
- 外層目標(biāo)MAC:SGW的MAC;
- 外層源IP:E-NodeB的IP;
- 外層目標(biāo)IP:SGW的IP;
- 內(nèi)層源MAC:手機(jī)也即UE的MAC;
- 內(nèi)層目標(biāo)MAC:網(wǎng)關(guān)PGW上面的隧道端點(diǎn)的MAC;
- 內(nèi)層源IP:UE的IP地址;
- 內(nèi)層目標(biāo)IP:SLB的公網(wǎng)IP地址。
當(dāng)隧道在SGW的時(shí)候,切換了一個(gè)隧道,為從SGW到PGW的隧道,因而網(wǎng)絡(luò)包的格式為:
- 外層源MAC:SGW的MAC;
- 外層目標(biāo)MAC:PGW的MAC;
- 外層源IP:SGW的IP;
- 外層目標(biāo)IP:PGW的IP;
- 內(nèi)層源MAC:手機(jī)也即UE的MAC;
- 內(nèi)層目標(biāo)MAC:網(wǎng)關(guān)PGW上面的隧道端點(diǎn)的MAC;
- 內(nèi)層源IP:UE的IP地址;
- 內(nèi)層目標(biāo)IP:SLB的公網(wǎng)IP地址。
在PGW的隧道端點(diǎn)將包解出來(lái),轉(zhuǎn)發(fā)出去的時(shí)候,一般在PGW出外部網(wǎng)絡(luò)的路由器上,會(huì)部署NAT服務(wù),將手機(jī)的IP地址轉(zhuǎn)換為公網(wǎng)IP地址,當(dāng)請(qǐng)求返回的時(shí)候,再NAT回來(lái)。
因而在PGW之后,相當(dāng)于做了一次歐洲十國(guó)游型的轉(zhuǎn)發(fā),網(wǎng)絡(luò)包的格式為:
- 源MAC:PGW出口的MAC;
- 目標(biāo)MAC:NAT網(wǎng)關(guān)的MAC;
- 源IP:UE的IP地址;
- 目標(biāo)IP:SLB的公網(wǎng)IP地址。
在NAT網(wǎng)關(guān),相當(dāng)于做了一次玄奘西游型的轉(zhuǎn)發(fā),網(wǎng)絡(luò)包的格式變成:
- 源MAC:NAT網(wǎng)關(guān)的MAC;
- 目標(biāo)MAC:A2路由器的MAC;
- 源IP:UE的公網(wǎng)IP地址;
- 目標(biāo)IP:SLB的公網(wǎng)IP地址。
在手機(jī)運(yùn)營(yíng)商的網(wǎng)絡(luò)里面,網(wǎng)絡(luò)狀況是比較好的。
對(duì)于玄奘法師,在大唐國(guó)境之內(nèi),還是比較平安的。原文說(shuō):們行了數(shù)日,到了鞏州城。早有鞏州合屬官吏人等,迎接入城中。安歇一夜,次早出城前去。一路饑餐渴飲,夜住曉行,兩三日,又至河州衛(wèi)。早有鎮(zhèn)邊的總兵與本處僧道,聞得是欽差御弟法師上西方見(jiàn)佛,無(wú)不恭敬,接至里面供給了,著僧綱請(qǐng)往福原寺安歇。本寺僧人,一一參見(jiàn),安排晚齋。齋畢,吩咐二從者飽喂馬匹,天不明就行。
真的是有接有送。
行經(jīng)半日,只見(jiàn)對(duì)面處,有一座大山,真?zhèn)€是高接青霄,崔巍險(xiǎn)峻。此山喚做兩界山,東半邊屬我大唐所管,西半邊乃是韃靼的地界。過(guò)了這座山,就不是大唐的土地了。



六、歷經(jīng)千山與萬(wàn)險(xiǎn)
離開(kāi)大唐的國(guó)土,接下來(lái)的路應(yīng)該怎么走呢?
好在此去西天,要經(jīng)過(guò)一個(gè)個(gè)國(guó)家,每個(gè)國(guó)家有一個(gè)個(gè)城關(guān),玄奘法師只要到處問(wèn)路,只要這些城關(guān)的守門(mén)人知道大概路怎么走,就能一個(gè)個(gè)國(guó)家的走下去,如果遇到國(guó)家,還有通關(guān)文牒,還能保護(hù)玄奘法師在國(guó)內(nèi)的安全。


這里有兩個(gè)問(wèn)題要解決,第一個(gè)是每個(gè)城關(guān)的守門(mén)人和每個(gè)國(guó)家,是怎么知道去西天怎么走的。第二個(gè)問(wèn)題是玄奘如何問(wèn)路,如何走。
我們先第一個(gè)問(wèn)題,這個(gè)觀音菩薩從西天來(lái)東土的時(shí)候,已經(jīng)通過(guò)一種法術(shù)告訴這些國(guó)家和城關(guān)了。
菩薩的法術(shù)主要分兩種情況,一種情況是在一個(gè)國(guó)家內(nèi)部如何走,另一種情況在國(guó)家之間,在野外如何走的問(wèn)題。
在一個(gè)國(guó)家內(nèi)部,菩薩主要遵循最短路徑原則,就是走得路越少越好,道路越短越好。
但是國(guó)家之間,菩薩不但要考慮遠(yuǎn)近的問(wèn)題,還要考慮政策的問(wèn)題。例如有的國(guó)家路近,但是路過(guò)的國(guó)家看不慣僧人,見(jiàn)了僧人就抓。例如滅法國(guó),連光頭都要抓。這樣的情況即便路近,也最好繞遠(yuǎn)點(diǎn)走。
菩薩的法術(shù)是什么呢?咱們?cè)诖髮W(xué)里面學(xué)習(xí)計(jì)算機(jī)網(wǎng)絡(luò)與數(shù)據(jù)結(jié)構(gòu)的時(shí)候,知道求最短路徑常用的有兩種方法,一種是 Bellman-Ford 算法,一種是 Dijkstra 算法。在計(jì)算機(jī)網(wǎng)絡(luò)中基本也是用這兩種方法計(jì)算的。
- 距離矢量路由(distance vector routing),它是基于 Bellman-Ford 算法的。
- 鏈路狀態(tài)路由(link state routing),基于 Dijkstra 算法。
最常用的兩種路由協(xié)議:
- OSPF(Open Shortest Path First,開(kāi)放式最短路徑優(yōu)先)就是這樣一個(gè)基于鏈路狀態(tài)路由協(xié)議,廣泛應(yīng)用在數(shù)據(jù)中心中的協(xié)議,稱(chēng)為內(nèi)部網(wǎng)關(guān)協(xié)議(Interior Gateway Protocol,簡(jiǎn)稱(chēng)IGP)
- BGP 協(xié)議使用的算法是路徑矢量路由協(xié)議(path-vector protocol)。它是距離矢量路由協(xié)議的升級(jí)版,稱(chēng)為外網(wǎng)路由協(xié)議(Border Gateway Protocol,簡(jiǎn)稱(chēng)BGP)
路由協(xié)議是城關(guān)之間相互溝通到哪里應(yīng)該怎么走的協(xié)議。

第二個(gè)問(wèn)題,也就是玄奘如何問(wèn)路,如何走。這就是IP協(xié)議。
這就要靠通關(guān)文牒了,里面寫(xiě)著貧僧來(lái)自東土大唐(就是源IP地址),欲往西天拜佛求經(jīng)(指的是目標(biāo)IP地址)。路過(guò)寶地,借宿一晚,明日啟行,請(qǐng)問(wèn)接下來(lái)該怎么走啊?



在解決第一個(gè)問(wèn)題的時(shí)候,每個(gè)城關(guān)已經(jīng)通過(guò)菩薩的法術(shù),和鄰近的城關(guān)進(jìn)行溝通,知道了下面的信息。
這個(gè)叫路由表,根據(jù)這個(gè)表格,可以告訴唐僧怎么走。
接下來(lái)我們看完整故事。

出了NAT網(wǎng)關(guān),就從核心網(wǎng)到達(dá)了互聯(lián)網(wǎng)。在網(wǎng)絡(luò)世界,每一個(gè)運(yùn)營(yíng)商的網(wǎng)絡(luò)成為自治系統(tǒng)AS。每個(gè)自治系統(tǒng)都有邊界路由器,通過(guò)它和外面的世界建立聯(lián)系。
對(duì)于云平臺(tái)來(lái)講,它可以被稱(chēng)為Multihomed AS,有多個(gè)連接連到其他的AS,但是大多拒絕幫其他的AS傳輸包。例如一些大公司的網(wǎng)絡(luò)。對(duì)于運(yùn)營(yíng)商來(lái)說(shuō),它可以被稱(chēng)為T(mén)ransit AS,有多個(gè)連接連到其他的AS,并且可以幫助其他的AS傳輸包,比如主干網(wǎng)。
如何從出口的運(yùn)營(yíng)商到達(dá)云平臺(tái)的邊界路由器?在路由器之間需要通過(guò)BGP協(xié)議實(shí)現(xiàn),BGP又分為兩類(lèi),eBGP和iBGP。自治系統(tǒng)間,邊界路由器之間使用eBGP廣播路由。內(nèi)部網(wǎng)絡(luò)也需要訪問(wèn)其他的自治系統(tǒng)。
邊界路由器如何將BGP學(xué)習(xí)到的路由導(dǎo)入到內(nèi)部網(wǎng)絡(luò)呢?通過(guò)運(yùn)行iBGP,使內(nèi)部的路由器能夠找到到達(dá)外網(wǎng)目的地最好的邊界路由器。
網(wǎng)站的SLB的公網(wǎng)IP地址早已經(jīng)通過(guò)云平臺(tái)的邊界路由器,讓全網(wǎng)都知道了。于是這個(gè)下單的網(wǎng)絡(luò)包選擇了下一跳是A2,也即將A2的MAC地址放在目標(biāo)MAC地址中。
到達(dá)A2之后,從路由表中找到下一跳是路由器C1,于是將目標(biāo)MAC換成C1的MAC地址。到達(dá)C1之后,找到下一跳是C2,將目標(biāo)MAC地址設(shè)置為C2的MAC。到達(dá)C2后,找到下一跳是云平臺(tái)的邊界路由器,于是將目標(biāo)MAC設(shè)置為邊界路由器的MAC地址。
你會(huì)發(fā)現(xiàn),這一路,都是只換MAC,不換目標(biāo)IP地址。這就是所謂下一跳的概念。
在云平臺(tái)的邊界路由器,會(huì)將下單的包轉(zhuǎn)發(fā)進(jìn)來(lái),經(jīng)過(guò)核心交換,匯聚交換,到達(dá)外網(wǎng)網(wǎng)關(guān)節(jié)點(diǎn)上的SLB的公網(wǎng)IP地址。
我們可以看到,手機(jī)到SLB的公網(wǎng)IP,是一個(gè)端到端的連接,連接的過(guò)程發(fā)送了很多包。所有這些包,無(wú)論是TCP三次握手,還是HTTPS的密鑰交換,都是要走如此復(fù)雜的過(guò)程到達(dá)SLB的,當(dāng)然每個(gè)包走的路徑不一定一致。
當(dāng)網(wǎng)絡(luò)包走在這個(gè)復(fù)雜的道路上,很可能一不小心就丟了,怎么辦?這就需要借助TCP的機(jī)制重新發(fā)送。
既然TCP要對(duì)包進(jìn)行重傳,就需要維護(hù)一個(gè)Sequence Number,看哪些包到了,哪些沒(méi)到,哪些需要重傳,傳輸?shù)乃俣葢?yīng)該控制到多少,這就是TCP的滑動(dòng)窗口協(xié)議。

整個(gè)TCP的發(fā)送,一開(kāi)始會(huì)協(xié)商一個(gè)Sequence Number,從這個(gè)Sequence Number開(kāi)始,每個(gè)包都有編號(hào)。滑動(dòng)窗口將接收方的網(wǎng)絡(luò)包分成四個(gè)部分:
- 已經(jīng)接收,已經(jīng)ACK,已經(jīng)交給應(yīng)用層的包;
- 已經(jīng)接收,已經(jīng)ACK,未發(fā)送給應(yīng)用層;
- 已經(jīng)接收,尚未發(fā)送ACK;
- 未接收,尚有空閑的緩存區(qū)域。
對(duì)于TCP層來(lái)講,每一個(gè)包都有ACK。ACK需要從SLB回復(fù)到手機(jī)端,將上面的那個(gè)過(guò)程反向來(lái)一遍,當(dāng)然路徑不一定一致,可見(jiàn)ACK也不是那么輕松的事情。
如果發(fā)送方超過(guò)一定的時(shí)間沒(méi)有收到ACK,就會(huì)重新發(fā)送。只有TCP層ACK過(guò)的包,才會(huì)發(fā)給應(yīng)用層,并且只會(huì)發(fā)送一份,對(duì)于下單的場(chǎng)景,應(yīng)用層是HTTP層。
你可能會(huì)問(wèn)了,TCP老是重復(fù)發(fā)送,會(huì)不會(huì)導(dǎo)致一個(gè)單下了兩遍?是否要求服務(wù)端實(shí)現(xiàn)冪?從TCP的機(jī)制來(lái)看,是不會(huì)的。只有收不到ACK的包才會(huì)重復(fù)發(fā),發(fā)到接收端,在窗口里面只保存一份,所以在同一個(gè)TCP連接中,不用擔(dān)心重傳導(dǎo)致二次下單。
但是TCP連接會(huì)因?yàn)槟撤N原因斷了,例如手機(jī)信號(hào)不好,這個(gè)時(shí)候手機(jī)把所有的動(dòng)作重新做一遍,建立一個(gè)新的TCP連接,在HTTP層調(diào)用兩次RESTful API。這個(gè)時(shí)候可能會(huì)導(dǎo)致兩遍下單的情況,因而RESTful API需要實(shí)現(xiàn)冪等。
當(dāng)ACK過(guò)的包發(fā)給應(yīng)用層之后,TCP層的緩存就空了出來(lái),這會(huì)導(dǎo)致上面圖中的大三角,也即接收方能夠容納的總緩存,整體順時(shí)針滑動(dòng)。小的三角形,也即接收方告知發(fā)送方的窗口總大小,也即還沒(méi)有完全確認(rèn)收到的緩存大小,如果把這些填滿(mǎn)了,就不能再發(fā)了,因?yàn)闆](méi)確認(rèn)收到,所以一個(gè)都不能扔。
七、功成行滿(mǎn)見(jiàn)真如
唐僧經(jīng)歷九九八十一難,終于到達(dá)了西天。發(fā)現(xiàn)金頂大仙已經(jīng)在等他們了。

網(wǎng)絡(luò)包從手機(jī)端經(jīng)歷千難萬(wàn)險(xiǎn),終于到了SLB的公網(wǎng)IP所在的公網(wǎng)網(wǎng)口。由于匹配上了MAC地址和IP地址,因而將網(wǎng)絡(luò)包收了進(jìn)來(lái)。
到了西天,唐僧度過(guò)最后一條河凌云仙渡的時(shí)候,發(fā)現(xiàn)滾浪飛流,約有八九里寬闊,四無(wú)人跡。好不容易盼來(lái)一條船,還沒(méi)有底。原來(lái)駕船的是接引佛祖,玄奘法師的肉體隨著河水飄走,從而脫胎換骨,成就金身。

在虛擬網(wǎng)關(guān)節(jié)點(diǎn)的外網(wǎng)網(wǎng)口上,會(huì)有一個(gè)NAT規(guī)則,將公網(wǎng)IP地址轉(zhuǎn)換為VPC里面的私網(wǎng)IP地址,這個(gè)私網(wǎng)IP地址就是SLB的HAProxy所在的虛擬機(jī)的私網(wǎng)IP地址。
從而網(wǎng)絡(luò)包也脫胎換骨,實(shí)現(xiàn)公網(wǎng)IP到私有網(wǎng)絡(luò)IP的轉(zhuǎn)換。

當(dāng)然為了承載比較大的吞吐量,虛擬網(wǎng)關(guān)節(jié)點(diǎn)會(huì)有多個(gè),物理網(wǎng)絡(luò)會(huì)將流量分發(fā)到不同的虛擬網(wǎng)關(guān)節(jié)點(diǎn)。同樣HAProxy也會(huì)是一個(gè)大的集群,虛擬網(wǎng)關(guān)會(huì)選擇某個(gè)負(fù)載均衡節(jié)點(diǎn),將某個(gè)請(qǐng)求分發(fā)給它,負(fù)載均衡之后是Controller層,也是部署在虛擬機(jī)里面的。
當(dāng)網(wǎng)絡(luò)包里面的目標(biāo)IP變成私有IP地址地址之后,虛擬路由會(huì)查找路由規(guī)則,將網(wǎng)絡(luò)包從下方的私網(wǎng)網(wǎng)口發(fā)出來(lái)。這個(gè)時(shí)候包的格式為:
- 源MAC:網(wǎng)關(guān)MAC;
- 目標(biāo)MAC:HAProxy虛擬機(jī)的MAC;
- 源IP:UE的公網(wǎng)IP;
- 目標(biāo)IP:HAProxy虛擬機(jī)的私網(wǎng)IP。
在第一部分,我們 說(shuō)佛經(jīng)是存放在一個(gè)虛擬空間里面的,要打開(kāi)這個(gè)虛擬空間,解讀經(jīng)文,需要一個(gè)芝麻開(kāi)門(mén)的ID。接引佛祖會(huì)給玄奘法師一個(gè)ID。
在虛擬路由節(jié)點(diǎn)上,也會(huì)有OVS,將網(wǎng)絡(luò)包封裝在VXLAN隧道里面,VXLAN ID就是給你的租戶(hù)創(chuàng)建VPC的時(shí)候分配的。VXLAN ID就是VPC虛擬空間的ID,OVS就是那個(gè)能夠封裝和解開(kāi)私密空間的法寶。
包的格式為:
- 外層源MAC:網(wǎng)關(guān)物理機(jī)MAC;
- 外層目標(biāo)MAC:物理機(jī)A的MAC;
- 外層源IP:網(wǎng)關(guān)物理機(jī)IP;
- 外層目標(biāo)IP:物理機(jī)A的IP;
- 內(nèi)層源MAC:網(wǎng)關(guān)MAC;
- 內(nèi)層目標(biāo)MAC:HAProxy虛擬機(jī)的MAC;
- 內(nèi)層源IP:UE的公網(wǎng)IP;
- 內(nèi)層目標(biāo)IP:HAProxy虛擬機(jī)的私網(wǎng)IP。
在物理機(jī)A上,OVS會(huì)將包從VXLAN隧道里面解出來(lái),發(fā)給HAProxy所在的虛擬機(jī)。HAProxy所在的虛擬機(jī)發(fā)現(xiàn)MAC地址匹配,目標(biāo)IP地址匹配,就根據(jù)TCP端口,將包發(fā)給HAProxy進(jìn)程,因?yàn)镠AProxy是在監(jiān)聽(tīng)這個(gè)TCP端口的。因而HAProxy就是這個(gè)TCP連接的服務(wù)端,客戶(hù)端是手機(jī)。對(duì)于TCP的連接狀態(tài),滑動(dòng)窗口等,都是在HAProxy上維護(hù)的。
在這里HAProxy是一個(gè)四層負(fù)載均衡,也即他只解析到TCP層,里面的HTTP協(xié)議他不關(guān)心,就將請(qǐng)求轉(zhuǎn)發(fā)給后端的多個(gè)Controller層的一個(gè)。
HAProxy發(fā)出去的網(wǎng)絡(luò)包就認(rèn)為HAProxy是客戶(hù)端了,看不到手機(jī)端了。網(wǎng)絡(luò)包格式如下:
- 源MAC:HAProxy所在虛擬機(jī)的MAC;
- 目標(biāo)MAC:Controller層所在虛擬機(jī)的MAC;
- 源IP:HAProxy所在虛擬機(jī)的私網(wǎng)IP;
- 目標(biāo)IP:Controller層所在虛擬機(jī)的私網(wǎng)IP。
當(dāng)然這個(gè)包發(fā)出去之后,還是會(huì)被物理機(jī)上的OVS放入VXLAN隧道里面,網(wǎng)絡(luò)包格式為:
- 外層源MAC:物理機(jī)A的MAC;
- 外層目標(biāo)MAC:物理機(jī)B的MAC;
- 外層源IP:物理機(jī)A的IP;
- 外層目標(biāo)IP:物理機(jī)B的IP;
- 內(nèi)層源MAC:HAProxy所在虛擬機(jī)的MAC;
- 內(nèi)層目標(biāo)MAC:Controller層所在虛擬機(jī)的MAC;
- 內(nèi)層源IP:HAProxy所在虛擬機(jī)的私網(wǎng)IP;
- 內(nèi)層目標(biāo)IP:Controller層所在虛擬機(jī)的私網(wǎng)IP。
在物理機(jī)B上,OVS會(huì)將包從VXLAN隧道里面解出來(lái),發(fā)給Controller層所在的虛擬機(jī)。Controller層所在的虛擬機(jī)發(fā)現(xiàn)MAC地址匹配,目標(biāo)IP地址匹配,就根據(jù)TCP端口,將包發(fā)給Controller層的進(jìn)程,因?yàn)樗窃诒O(jiān)聽(tīng)這個(gè)TCP端口的。
在HAProxy和Controller層之間,維護(hù)一個(gè)TCP的連接。
Controller層收到包之后,他是關(guān)心HTTP里面是什么的,于是解開(kāi)HTTP的包,發(fā)現(xiàn)是一個(gè)POST請(qǐng)求,內(nèi)容是下單購(gòu)買(mǎi)一個(gè)課程。
八、取得真經(jīng)成金身
玄奘法師終于到達(dá)西天大雷音寺,見(jiàn)到了我佛如來(lái)。

佛祖愿意傳經(jīng)給玄奘,于是讓玄奘去藏經(jīng)樓取經(jīng)文,誰(shuí)知道西天也有西天的規(guī)矩,如果不懂這里的規(guī)矩,就很難和管理經(jīng)文的人溝通,取不到真經(jīng)。



同理,在電商服務(wù)里面,往往在組合服務(wù)層會(huì)有一個(gè)專(zhuān)門(mén)管理下單的服務(wù),Controller層雖然對(duì)外暴露的是標(biāo)準(zhǔn)的RESTful協(xié)議,但是對(duì)內(nèi)會(huì)通過(guò)RPC協(xié)議調(diào)用這個(gè)組合服務(wù)層。如果不懂這個(gè)協(xié)議,就沒(méi)法通信。
假設(shè)我們使用的是Dubbo,則Controller層需要讀取注冊(cè)中心,將下單服務(wù)的進(jìn)程列表拿出來(lái),選出一個(gè)來(lái)調(diào)用。

Dubbo中默認(rèn)的RPC協(xié)議是Hessian2。Hessian2將下單的遠(yuǎn)程調(diào)用序列化為二進(jìn)制進(jìn)行傳輸。
Netty是一個(gè)非阻塞的基于事件的網(wǎng)絡(luò)傳輸框架。Controller層和下單服務(wù)之間,使用了Netty的網(wǎng)絡(luò)傳輸框架。有了Netty,就不用自己編寫(xiě)復(fù)雜的異步Socket程序了。Netty使用的方式,就是咱們講Socket編程的時(shí)候,一個(gè)項(xiàng)目組支撐多個(gè)項(xiàng)目(IO多路復(fù)用,從派人盯著到有事通知)這種方式。
Netty還是工作在Socket這一層的,發(fā)送的網(wǎng)絡(luò)包還是基于TCP的。在TCP的下層,還是需要封裝上IP頭和MAC頭。如果跨物理機(jī)通信,還是需要封裝的外層的VXLAN隧道里面。當(dāng)然底層的這些封裝,Netty都不感知,它只要做好它的異步通信即可。
在Netty的服務(wù)端,也即下單服務(wù)中,收到請(qǐng)求后,先用Hessian2的格式進(jìn)行解壓縮。然后將請(qǐng)求分發(fā)到線程中進(jìn)行處理,在線程中,會(huì)調(diào)用下單的業(yè)務(wù)邏輯。
玄奘師徒好在后來(lái)碰到了懂得內(nèi)情的注冊(cè)中心——彌勒佛,從而會(huì)到靈山,還是按照人家的規(guī)矩辦了,才將無(wú)字經(jīng)文,換成有字經(jīng)文。



下單的業(yè)務(wù)邏輯比較復(fù)雜,往往要調(diào)用基礎(chǔ)服務(wù)層里面的庫(kù)存服務(wù)、優(yōu)惠券服務(wù)等,將多個(gè)服務(wù)調(diào)用完畢,才算下單成功。下單服務(wù)調(diào)用庫(kù)存服務(wù)和優(yōu)惠券服務(wù),也是通過(guò)Dubbo的框架,通過(guò)注冊(cè)中心拿到庫(kù)存服務(wù)和優(yōu)惠券服務(wù)的列表,然后選一個(gè)調(diào)用。
調(diào)用的時(shí)候,統(tǒng)一使用Hessian2進(jìn)行序列化,使用Netty進(jìn)行傳輸,底層如果跨物理機(jī),仍然需要通過(guò)VXLAN的封裝和解封裝。
咱們以庫(kù)存為例子的時(shí)候,講述過(guò)冪等的接口實(shí)現(xiàn)的問(wèn)題。因?yàn)槿绻蹨p庫(kù)存,僅僅是誰(shuí)調(diào)用誰(shuí)減一。這樣存在的問(wèn)題是,如果扣減庫(kù)存因?yàn)橐淮握{(diào)用失敗,而多次調(diào)用,這里指的不是TCP多次重試,而是應(yīng)用層調(diào)用的多次重試,就會(huì)存在庫(kù)存扣減多次的情況。
這里常用的方法是,使用樂(lè)觀鎖(Compare and Set,簡(jiǎn)稱(chēng)CAS)。CAS要考慮三個(gè)方面,當(dāng)前的庫(kù)存數(shù)、預(yù)期原來(lái)的庫(kù)存數(shù)和版本,以及新的庫(kù)存數(shù)。在操作之前,查詢(xún)出原來(lái)的庫(kù)存數(shù)和版本,真正扣減庫(kù)存的時(shí)候,判斷如果當(dāng)前庫(kù)存的值與預(yù)期原值和版本相匹配,則將庫(kù)存值更新為新值,否則不做任何操作。
這是一種基于狀態(tài)而非基于動(dòng)作的設(shè)計(jì),符合REST的架構(gòu)設(shè)計(jì)原則。這樣的設(shè)計(jì)有利于高并發(fā)場(chǎng)景。當(dāng)多個(gè)線程嘗試使用CAS同時(shí)更新同一個(gè)變量時(shí),只有其中一個(gè)線程能更新變量的值,而其它線程都失敗,失敗的線程并不會(huì)被掛起,而是被告知這次競(jìng)爭(zhēng)中失敗,并可以再次嘗試。
最終,當(dāng)下單更新到分布式數(shù)據(jù)庫(kù)中之后,整個(gè)下單過(guò)程才算真正告一段落。

當(dāng)然,這個(gè)下單調(diào)用要返回一個(gè)結(jié)果。
我們下單成功啦!!!!!!