這是一個有關計算機網絡協定的故事,原文來自公号劉超的通俗雲計算。
一、我佛造經傳極樂
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiAjM2EzLcd3LcJzLcJzdllmVldWYtl2PnVGcq5SbpB3cyN2a5J2avwlN5kzN2ETMtUGall3LcVmdhNXLwRHdo9CXt92YucWbpRWdvx2Yx5yazF2Lc9CX6MHc0RHaiojIsJye.jpeg)
話說我佛如來為度化天下蒼生,有三藏真經,可勸人為善。
就如圖中所示,真經所藏之處,在于雲端。佛祖所管轄之下,有四個區域Region,稱為四大部洲, 一是東勝神洲,二是南贍部洲,三是西牛賀洲,四是北俱盧洲。
我佛所在西牛賀洲,是主站點。
在每個區域Region,為保證真經永固,設定多個藏經樓,稱為可用區(Available Zone)。
每個藏經樓裡面是一排一排的櫃子,稱為機櫃,裡面有一排一排的格子,稱為伺服器,經文就擺放在格子中。
在藏經樓中,櫃子根據經文分門别類的組織起來,由不同的神仙進行管理,管理一個櫃子的經文的神仙,通路這裡面經文的鑰匙就在他手裡,稱為接入層神仙(接入層交換機)。
多個接入層神仙被一組彙聚層神仙(彙聚層交換機)管着,多個彙聚層的神仙被一組核心層神仙(核心交換機)管着。
神仙體系組織嚴格,層次分明,不同的接入層神仙交換經文,要通過彙聚層神仙同意,不同的彙聚層神仙交換經文,需要核心層神仙同意。
經文的看守要萬無一失,因而每一層都是分組看護,互相監督,互相備份,稱為堆疊。
雖說每個櫃子裡面放滿了經文,為了防止經文被偷聽偷看,經文的内容是被仙術封裝在一個虛拟的私密空間裡面,雖然有人可能會偷到物質的經文,但是沒有仙術打開這個私密空間,看到的經文如同空白的一樣。這個虛拟的私密空間稱為VPC。
要解讀經文,需要使用每一格中一個不起眼的法寶,就是稱為Openvswitch的虛拟交換機,顧名思義就是起到經文在虛拟私密空間和實體空間之間的轉換作用。
Openvswitch如何轉換呢?使用的是一種稱為VXLAN的封裝技術,但是必須要事先知道芝麻開門的ID,也即VXLAN ID,才能看到經文的真正内容。
在虛拟的空間中,放着真正可以解讀的真經。
真經有法一藏,談天;論一藏,說地;經一藏,度鬼;三藏共計三十五部,該一萬五千一百四十四卷,乃是修真之徑,正善之門。
看來已經前中背景分離,分為基礎服務層,組合服務層,Controller層,共三十五個子產品,一萬五千多個服務,真是微服務架構啊。
如何能夠不要迷失在這個一萬五千卷經文中,也是很有挑戰的事情,需要一個索引和指南,這就是常說的RPC架構和服務注冊與發現中心。
為了友善諸多僧侶前來取經,靈山腳下會有一個統一的入口位址,這裡有一個神仙,稱為金頂大仙,專門來接應取經人的。
由于前來取經的人很多,同時經文也很多,是以金頂大仙多起到負載均衡的作用,将不同的取經人引領到不同的藏經樓,通路不同的經文。
金頂大仙所在的靈山腳下,是一個世界知名的位址,稱為外網IP位址,這個位址是全球可定位的,所有的取經人都先到這個地方,金頂大仙通過NAT規則,将外網IP位址,變成藏經樓的私有IP位址,例如2号藏經樓三樓,4号藏經樓五樓等。在靈山藏經樓裡面,是通過私有IP位址定位的。
真經已經準備好,就差東土取經人了。
二、觀音奉旨上長安
可是佛祖愁啊,是這樣說的:我待要送上東土,叵耐那方衆生愚蠢,毀謗真言,不識我法門之要旨,怠慢了瑜迦之正宗。怎麼得一個有法力的,去東土尋一個善信.教他苦曆千山,遠經萬水,到我處求取真經,永傳東土,勸他衆生,卻乃是個山大的福緣,海深的善慶、誰肯去走一遭來?
真經就在靈山,可以東土之人愚鈍,不知道靈山咋辦呢?要一個法力無邊的人告訴他們呀。而且最好能夠告訴全世界,靈山這裡有真經。
好在有觀音菩薩,道:“弟子不才,願上東土尋一個取經人來也。”,觀音菩薩有什麼法力呢?當然是BGP協定了。
剛才那張圖畫的是一個可用區的情況,對于多個可用區的情況,我們可以隐去計算節點的情況,将外網通路區域放大。
外網IP是放在虛拟網關的外網網口上的,這個IP如何讓全世界知道呢?在核心交換外面是安全裝置,然後就是邊界路由器。邊界路由器會和多個營運商連接配接,進而每個營運商都能夠通路到這個網站。邊界路由器可以通過BGP協定,将自己資料中心裡面的外網IP向外廣播,也就是告訴全世界,如果要通路這些外網IP,都來我這裡。
每個營運商也有很多的路由器、很多的點,于是就可以将如何到達這些IP位址的路由資訊,廣播到全國乃至全世界。
厲害吧,這是我佛如來告訴觀音菩薩的:“這一去。要踏看路道,不許在霄漢中行,須是要半雲半霧;目過山水,謹記程途遠近之數,叮咛那取經人。“
就是說你去東土的路上,經過了哪些道路,要記住路徑,要記住遠近,才能告訴取經人這一路應該怎麼走。
三、玄奘秉誠建大會
當觀音菩薩來到東土大唐,正看到玄奘法師正坐在高台上,帶領衆人誦經,念一會《受生度亡經》,談一會《安邦天寶篆》,又宣一會《勸修功卷》。
菩薩近前來,叫道:“那和尚,你隻會談小乘教法,可會談大乘麼?”玄奘聞言,心中大喜,翻身跳下台來,對菩薩起手道:“老師父,弟子失瞻,多罪。見前的蓋衆僧人,都講的是小乘教法,卻不知大乘教法如何。”菩薩道:“你這小乘教法,度不得亡者超升,隻可渾俗和光而已。我有大乘佛法三藏,能超亡者升天,能度難人脫苦,能修無量壽身,能作無來無去。”
你看,在西方極樂淨土,我佛已經有了更牛的佛經,遙遠的東方,還在讀本土的僧人早期從西方傳過來的經。
這種模式,稱為CDN。
我們部署應用的時候,一般會把靜态資源儲存在兩個地方,一個是nginx後面的varnish緩存裡面,一般是靜态頁面;對于比較大的、不經常更新的靜态圖檔,會儲存在對象存儲裡面。這兩個地方的靜态資源都會配置CDN,将資源下發到邊緣節點。
最初佛祖傳經,都是口口相傳,經文都會記在高僧大德的心裡,随着高僧雲遊天下,随着廟宇遍布天下,佛經進而遍布天下。這就相當于将佛經緩存在邊緣節點。
配置了CDN之後,權威DNS伺服器上,會為靜态資源設定一個CNAME别名,指向另外一個域名cdn.com,傳回給本地DNS伺服器。
當本地DNS伺服器拿到這個新的域名時,需要繼續解析這個新的域名。這個時候,再通路的時候就不是原來的權威DNS伺服器了,而是 cdn.com 的權威DNS伺服器。這是CDN自己的權威DNS伺服器。
在這個伺服器上,還是會設定一個CNAME,指向另外一個域名,也即CDN網絡的全局負載均衡器。
本地DNS伺服器去請求CDN的全局負載均衡器解析域名,全局負載均衡器會為使用者選擇一台合适的緩存伺服器提供服務,将IP傳回給用戶端,用戶端去通路這個邊緣節點,下載下傳資源。緩存伺服器響應使用者請求,将使用者所需内容傳送到使用者終端。
如果這台緩存伺服器上并沒有使用者想要的内容,那麼這台伺服器就要向它的上一級緩存伺服器請求内容,直至追溯到網站的源伺服器,将内容拉到本地。
CDN的全局負載均衡政策,就相當于當僧人們想讀佛經的時候,不必要都去西天,而是可以就近去問,周圍有沒有廟宇,然後向廟宇的師傅去請教佛經。
然而緩存的佛經當然是比不上西天取到的經文更新,是以東土由于離西天較遠,緩存的還是小乘佛教,要讀大乘佛教,就要去西天取經,稱為回源。
四、觀音顯像化金蟬
觀音菩薩打算度化玄奘法師,回源去西天取經。
可是怎麼去呢,位址在哪裡呢?玄奘法師隻聽說西天,不知道具體的位址,這就要問觀音菩薩了。
這個時候,大家才知道,西天在靈山大雷音寺,距此十萬八千裡。
這個過程稱為DNS解析。
當在手機上面打開一個App的時候,首先要做的事情就是解析這個網站的域名。
在手機營運商所在的網際網路區域裡,有一個本地的DNS,手機會向這個DNS請求解析DNS。當這個DNS本地有緩存,則直接傳回;如果沒有緩存,本地DNS才需要遞歸地從根DNS伺服器,查到.com的頂級域名伺服器,最終查到權威DNS伺服器。
如果你使用雲平台的時候,配置了智能DNS和全局負載均衡,在權威DNS服務中,一般是通過配置CNAME的方式,我們可以起一個别名,例如 vip.yourcomany.com ,然後告訴本地DNS伺服器,讓它請求GSLB解析這個域名,GSLB就可以在解析這個域名的過程中,通過自己的政策實作負載均衡。
GSLB通過檢視請求它的本地DNS伺服器所在的營運商和位址,就知道使用者所在的營運商和位址,然後将距離使用者位置比較近的Region裡面,将三個本地負載均衡的公網IP位址,傳回給本地DNS伺服器。本地DNS解析器将結果緩存後,傳回給用戶端。
對于手機APP來說,可以繞過剛才的傳統DNS解析機制,直接隻要HTTPDNS服務,通過直接調用HTTPDNS伺服器,得到這三個本地負載均衡的公網IP位址。
這個公網IP位址,就是金頂大仙所在的位置。其實這個時候,金頂大仙已經在等待了。
這個時候,李世民突然開始說話了,曰:“誰肯領朕旨意,上西天拜佛求經?“ 并願意買下觀音手中的兩件寶物,“錦瀾袈裟”一領,“九環錫杖”一根,佛祖說過:”若有取經人堅心來此,穿我的袈裟,免堕輪回;持我的錫枚,不遭毒害。“
玄奘法師回答:“貧僧不才,願效犬馬之勞,與陛下求取真經,祈保我王江山永固。”
這個時候,菩薩說了:“西天路遠,更多虎豹妖魔。隻怕有去無回,難保身命。”
玄奘道:“我已發了弘誓大願,不取真經,永堕沉淪地獄。“
其實這裡的對話是很有意思的,玄奘法師回複李世民的和回複觀音菩薩的不同。
這個時候,李世民作為世俗的君王,已經想求取真經了,也就是東土大唐作為用戶端,要發起對于服務端的請求了。但是玄奘法師知道,唐王李世民去取經,求的是江山永固。是以李世民的請求是應用層的,發起的是HTTP的協定,在HTTP的請求正文中,怕是寫的“江山永固”四個字。
而玄奘法師回複觀音菩薩的時候,說的就不同了,是一種對于真經和佛法本身的堅持。是以玄奘法師是TCP層的,TCP是面向連接配接的,TCP 是靠譜的協定,但是這不能說明它面臨的網絡環境好。從 IP 層面來講,如果網絡狀況的确那麼差,是沒有任何可靠性保證的,而作為 IP 的上一層 TCP 也無能為力,唯一能做的就是更加努力,不斷重傳,通過各種算法保證。也就是說,對于 TCP 來講,IP 層你丢不丢包,我管不着,但是我在我的層面上,會努力保證可靠性。
這一點在流沙河有了驗證。觀音菩薩度化沙悟淨的時候,沙悟淨說:“菩薩,我在此間吃人無數,向來有幾次取經人來,都被我吃了。凡吃的人頭,抛落流沙,竟沉水底(這個水,鵝毛也不能浮),惟有九個取經人的骷髅,浮在水面,再不能沉。我以為異物,将索兒穿在一處,閑時拿來頑耍,這去,但恐取經人不得到此,卻不是反誤了我的前程也?”菩薩日:“豈有不到之理?你可将骷髅地挂在頭頂下,等候取經入,自有用處。”
是以沙悟淨脖子上這九個骷髅,是唐三藏的前九輩子,一旦吃了,就不斷的重試。
為了能夠實作重試,實作TCP的可靠性,用戶端和伺服器需要建立連接配接。
HTTPS協定是基于TCP協定的,因而要先建立TCP的連接配接。在這個例子中,TCP的連接配接是從手機上的App和負載均衡器SLB之間的。也就是唐僧和金頂大仙之間,到了金頂大仙,就不怕了,會指引到佛祖那裡的。
盡管中間要經過很多的路由器和交換機,但是TCP的連接配接是端到端的。
TCP這一層和更上層的HTTPS無法看到中間的包的過程。盡管建立連接配接的時候,所有的包都逃不過在這些路由器和交換機之間的轉發,轉發的細節我們放到那個下單請求的發送過程中詳細解讀,這裡隻看端到端的行為。
對于TCP連接配接來講,需要通過三次握手建立連接配接,為了維護這個連接配接,雙方都需要在TCP層維護一個連接配接的狀态機。
一開始,用戶端和服務端都處于CLOSED狀态。服務端先是主動監聽某個端口,處于LISTEN狀态。然後用戶端主動發起連接配接SYN,之後處于SYN-SENT狀态。服務端收到發起的連接配接,傳回SYN,并且ACK用戶端的SYN,之後處于SYN-RCVD狀态。
用戶端收到服務端發送的SYN和ACK之後,發送ACK的ACK,之後處于ESTABLISHED狀态。這是因為,它一發一收成功了。服務端收到ACK的ACK之後,處于ESTABLISHED狀态,因為它的一發一收也成功了。
當TCP層的連接配接建立完畢之後,接下來輪到HTTPS層建立連接配接了,在HTTPS的交換過程中,TCP層始終處于ESTABLISHED。
對于HTTPS,用戶端會發送Client Hello消息到伺服器,用明文傳輸TLS版本資訊、加密套件候選清單、壓縮算法候選清單等資訊。另外,還會有一個随機數,在協商對稱密鑰的時候使用。
然後,伺服器會傳回Server Hello消息,告訴用戶端,伺服器選擇使用的協定版本、加密套件、壓縮算法等。這也有一個随機數,用于後續的密鑰協商。
然後,伺服器會給你一個伺服器端的證書,然後說:“Server Hello Done,我這裡就這些資訊了。”
用戶端當然不相信這個證書,于是你從自己信任的CA倉庫中,拿CA的證書裡面的公鑰去解密電商網站的證書。如果能夠成功,則說明電商網站是可信的。這個過程中,你可能會不斷往上追溯CA、CA的CA、CA的CA的CA,反正直到一個授信的CA,就可以了。
其實觀音菩薩手裡的錫杖和袈裟,就相當于佛祖辦法的證書,保證西行路上的安全,玄奘法師這個網絡包别被别人吃了,或者篡改。
就像誤入小雷音一集中,白眉老佛想吃了唐僧肉,自己披上袈裟,西天取經,求得正果。
當然,一開始觀音菩薩拿出錫杖和袈這個證書的時候,大家也不相信,是以需要觀音菩薩現出真身,作為CA,證明給用戶端,唐王李世民和玄奘法師才下拜。
證書驗證完畢之後,覺得這個服務端是可信的,于是用戶端計算産生随機數字Pre-master,發送Client Key Exchange,用證書中的公鑰加密,再發送給伺服器,伺服器可以通過私鑰解密出來。
接下來,無論是用戶端還是伺服器,都有了三個随機數,分别是:自己的、對端的,以及剛生成的Pre-Master随機數。通過這三個随機數,可以在用戶端和伺服器産生相同的對稱密鑰。
有了對稱密鑰,用戶端就可以說:“Change Cipher Spec,咱們以後都采用協商的通信密鑰和加密算法進行加密通信了。”
然後用戶端發送一個Encrypted Handshake Message,将已經商定好的參數等,采用協商密鑰進行加密,發送給伺服器用于資料與握手驗證。
同樣,伺服器也可以發送Change Cipher Spec,說:“沒問題,咱們以後都采用協商的通信密鑰和加密算法進行加密通信了”,并且也發送Encrypted Handshake Message的消息試試。
當雙方握手結束之後,就可以通過對稱密鑰進行加密傳輸了。
五、唐王素酒送三藏
玄奘這個網絡包要發出了。
太宗設朝,聚集文武,要去送行。李世民送給玄奘三個東西。
上一節說了太宗是應用層,關注保大唐江山永固,玄奘是TCP層,要通過堅定的意志到達西天。
李世民給的第一個東西是通關文牒,這個是IP層的,将來要通過這個文牒通過一個個城關。
第二個東西是紫金缽盂,這個用于玄奘法師到了某個城市裡面化齋,同時打聽路的時候使用,這個是一個MAC層的。
第三個東西是白馬一匹,作為遠端腳力,這個是實體層的。
最後,太宗敬了玄奘一杯素酒,言道:甯戀本鄉一撚土,莫愛他鄉萬兩金。三藏方悟撚土之意,複謝恩飲盡,辭謝出關而去。
當用戶端和服務端之間建立了連接配接後,接下來就要發送下單請求的網絡包了。
在使用者層發送的是HTTP的網絡包,因為服務端提供的是RESTful API,因而HTTP層發送的就是一個請求。
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": "趣談網絡協定",
"Author": "劉超",
"price": "68"
}
}
複制
HTTP的封包大概分為三大部分。第一部分是請求行,第二部分是請求的首部,第三部分才是請求的正文實體。
在請求行中,URL就是 www.geektime.com/purchaseOrder ,版本為HTTP 1.1。
請求的類型叫作POST,它需要主動告訴服務端一些資訊,而非擷取。需要告訴服務端什麼呢?一般會放在正文裡面。正文可以有各種各樣的格式,常見的格式是JSON。
請求行下面就是我們的首部字段。首部是key value,通過冒号分隔。
Content-Type是指正文的格式。例如,我們進行POST的請求,如果正文是JSON,那麼我們就應該将這個值設定為JSON。
接下來是正文,這裡是一個JSON字元串,裡面通過文本的形式描述了,要買一個課程,作者是誰,多少錢。
這樣,HTTP請求的封包格式就拼湊好了。接下來浏覽器或者移動App會把它交給下一層傳輸層。
怎麼交給傳輸層呢?也是用Socket進行程式設計。如果用的是浏覽器,這些程式不需要你自己寫,有人已經幫你寫好了;如果在移動APP裡面,一般會用一個HTTP的用戶端工具來發送,并且幫你封裝好。
HTTP協定是基于TCP協定的,是以它使用面向連接配接的方式發送請求,通過Stream二進制流的方式傳給對方。當然,到了TCP層,它會把二進制流變成一個的封包段發送給伺服器。
在TCP頭裡面,會有源端口号和目标端口号,目标端口号一般是服務端監聽的端口号,源端口号在手機端,往往是随機配置設定一個端口号。這個端口号在用戶端和服務端用于區分請求和傳回,發給那個應用。
在IP頭裡面,都需要加上自己的位址(即源位址)和它想要去的地方(即目标位址)。當一個手機上線的時候,PGW會給這個手機配置設定一個IP位址,這就是源位址,而目标位址則是雲平台的負載均衡器的外網IP位址。
在IP層,用戶端需要檢視目标位址和自己是否是在同一個區域網路,計算是否是同一個網段,往往需要通過CIDR子網路遮罩來計算。
對于這個下單場景,目标IP和源IP不會在同一個網段,因而需要發送到預設的網關。一般通過DHCP配置設定IP位址的時候,也會同時配置預設網關的IP位址。
但是用戶端不會直接使用預設網關的IP位址,而是發送ARP協定,來擷取網關的MAC位址,然後将網關MAC作為目标MAC,自己的MAC作為源MAC,放入MAC頭,發送出去。
一個完整的網絡包的格式是這樣的。
接下來,網絡包就正式發出了。
如果你是用手機打開APP,下單購物發送網絡包,一般通過手機營運商的網絡。
客戶的手機開機以後,在附近尋找基站eNodeB,發送請求,申請上網。基站将請求發給MME,MME對手機進行認證和鑒權,還會請求HSS看有沒有錢,看看是在哪裡上網。
當MME通過了手機的認證之後,開始建立隧道,建設的資料通路分兩段路,其實是兩個隧道。一段是從eNodeB到SGW,第二段是從SGW到PGW,在PGW之外,就是網際網路。
PGW會為手機配置設定一個IP位址,手機上網都是帶着這個IP位址的。
對于手機來講,預設的網關在PGW上。在移動網絡裡面,從手機到SGW,到PGW是有一條隧道的。在這條隧道裡面,會将上面的這個包作為隧道的乘客協定放在裡面,外面SGW和PGW在核心網機房的IP位址。網絡包直到PGW(PGW是隧道的另一端)才将裡面的包解出來,轉發到外部網絡。
是以,從手機發送出來的時候,網絡包的結構為:
- 源MAC:手機也即UE的MAC;
- 目标MAC:網關PGW上面的隧道端點的MAC;
- 源IP:UE的IP位址;
- 目标IP:SLB的公網IP位址。
進入隧道之後,要封裝外層的網絡位址,因而網絡包的格式為:
- 外層源MAC:E-NodeB的MAC;
- 外層目标MAC:SGW的MAC;
- 外層源IP:E-NodeB的IP;
- 外層目标IP:SGW的IP;
- 内層源MAC:手機也即UE的MAC;
- 内層目标MAC:網關PGW上面的隧道端點的MAC;
- 内層源IP:UE的IP位址;
- 内層目标IP:SLB的公網IP位址。
當隧道在SGW的時候,切換了一個隧道,為從SGW到PGW的隧道,因而網絡包的格式為:
- 外層源MAC:SGW的MAC;
- 外層目标MAC:PGW的MAC;
- 外層源IP:SGW的IP;
- 外層目标IP:PGW的IP;
- 内層源MAC:手機也即UE的MAC;
- 内層目标MAC:網關PGW上面的隧道端點的MAC;
- 内層源IP:UE的IP位址;
- 内層目标IP:SLB的公網IP位址。
在PGW的隧道端點将包解出來,轉發出去的時候,一般在PGW出外部網絡的路由器上,會部署NAT服務,将手機的IP位址轉換為公網IP位址,當請求傳回的時候,再NAT回來。
因而在PGW之後,相當于做了一次歐洲十國遊型的轉發,網絡包的格式為:
- 源MAC:PGW出口的MAC;
- 目标MAC:NAT網關的MAC;
- 源IP:UE的IP位址;
- 目标IP:SLB的公網IP位址。
在NAT網關,相當于做了一次玄奘西遊型的轉發,網絡包的格式變成:
- 源MAC:NAT網關的MAC;
- 目标MAC:A2路由器的MAC;
- 源IP:UE的公網IP位址;
- 目标IP:SLB的公網IP位址。
在手機營運商的網絡裡面,網絡狀況是比較好的。
對于玄奘法師,在大唐國境之内,還是比較平安的。原文說:們行了數日,到了鞏州城。早有鞏州合屬官吏人等,迎接入城中。安歇一夜,次早出城前去。一路饑餐渴飲,夜住曉行,兩三日,又至河州衛。早有鎮邊的總兵與本處僧道,聞得是欽差禦弟法師上西方見佛,無不恭敬,接至裡面供給了,着僧綱請往福原寺安歇。本寺僧人,一一參見,安排晚齋。齋畢,吩咐二從者飽喂馬匹,天不明就行。
真的是有接有送。
行經半日,隻見對面處,有一座大山,真個是高接青霄,崔巍險峻。此山喚做兩界山,東半邊屬我大唐所管,西半邊乃是鞑靼的地界。過了這座山,就不是大唐的土地了。
六、曆經千山與萬險
離開大唐的國土,接下來的路應該怎麼走呢?
好在此去西天,要經過一個個國家,每個國家有一個個城關,玄奘法師隻要到處問路,隻要這些城關的守門人知道大概路怎麼走,就能一個個國家的走下去,如果遇到國家,還有通關文牒,還能保護玄奘法師在國内的安全。
這裡有兩個問題要解決,第一個是每個城關的守門人和每個國家,是怎麼知道去西天怎麼走的。第二個問題是玄奘如何問路,如何走。
我們先第一個問題,這個觀音菩薩從西天來東土的時候,已經通過一種法術告訴這些國家和城關了。
菩薩的法術主要分兩種情況,一種情況是在一個國家内部如何走,另一種情況在國家之間,在野外如何走的問題。
在一個國家内部,菩薩主要遵循最短路徑原則,就是走得路越少越好,道路越短越好。
但是國家之間,菩薩不但要考慮遠近的問題,還要考慮政策的問題。例如有的國家路近,但是路過的國家看不慣僧人,見了僧人就抓。例如滅法國,連光頭都要抓。這樣的情況即便路近,也最好繞遠點走。
菩薩的法術是什麼呢?咱們在大學裡面學習計算機網絡與資料結構的時候,知道求最短路徑常用的有兩種方法,一種是 Bellman-Ford 算法,一種是 Dijkstra 算法。在計算機網絡中基本也是用這兩種方法計算的。
距離矢量路由(distance vector routing),它是基于 Bellman-Ford 算法的。
鍊路狀态路由(link state routing),基于 Dijkstra 算法。
最常用的兩種路由協定:
OSPF(Open Shortest Path First,開放式最短路徑優先)就是這樣一個基于鍊路狀态路由協定,廣泛應用在資料中心中的協定,稱為内部網關協定(Interior Gateway Protocol,簡稱IGP)
BGP 協定使用的算法是路徑矢量路由協定(path-vector protocol)。它是距離矢量路由協定的更新版,稱為外網路由協定(Border Gateway Protocol,簡稱BGP)
路由協定是城關之間互相溝通到哪裡應該怎麼走的協定。
第二個問題,也就是玄奘如何問路,如何走。這就是IP協定。
這就要靠通關文牒了,裡面寫着貧僧來自東土大唐(就是源IP位址),欲往西天拜佛求經(指的是目标IP位址)。路過寶地,借宿一晚,明日啟行,請問接下來該怎麼走啊?
在解決第一個問題的時候,每個城關已經通過菩薩的法術,和鄰近的城關進行溝通,知道了下面的資訊。
這個叫路由表,根據這個表格,可以告訴唐僧怎麼走。
接下來我們看完整故事。
出了NAT網關,就從核心網到達了網際網路。在網絡世界,每一個營運商的網絡成為自治系統AS。每個自治系統都有邊界路由器,通過它和外面的世界建立聯系。
對于雲平台來講,它可以被稱為Multihomed AS,有多個連接配接連到其他的AS,但是大多拒絕幫其他的AS傳輸包。例如一些大公司的網絡。對于營運商來說,它可以被稱為Transit AS,有多個連接配接連到其他的AS,并且可以幫助其他的AS傳輸包,比如主幹網。
如何從出口的營運商到達雲平台的邊界路由器?在路由器之間需要通過BGP協定實作,BGP又分為兩類,eBGP和iBGP。自治系統間,邊界路由器之間使用eBGP廣播路由。内部網絡也需要通路其他的自治系統。
邊界路由器如何将BGP學習到的路由導入到内部網絡呢?通過運作iBGP,使内部的路由器能夠找到到達外網目的地最好的邊界路由器。
網站的SLB的公網IP位址早已經通過雲平台的邊界路由器,讓全網都知道了。于是這個下單的網絡包選擇了下一跳是A2,也即将A2的MAC位址放在目标MAC位址中。
到達A2之後,從路由表中找到下一跳是路由器C1,于是将目标MAC換成C1的MAC位址。到達C1之後,找到下一跳是C2,将目标MAC位址設定為C2的MAC。到達C2後,找到下一跳是雲平台的邊界路由器,于是将目标MAC設定為邊界路由器的MAC位址。
你會發現,這一路,都是隻換MAC,不換目标IP位址。這就是所謂下一跳的概念。
在雲平台的邊界路由器,會将下單的包轉發進來,經過核心交換,彙聚交換,到達外網網關節點上的SLB的公網IP位址。
我們可以看到,手機到SLB的公網IP,是一個端到端的連接配接,連接配接的過程發送了很多包。所有這些包,無論是TCP三向交握,還是HTTPS的密鑰交換,都是要走如此複雜的過程到達SLB的,當然每個包走的路徑不一定一緻。
當網絡包走在這個複雜的道路上,很可能一不小心就丢了,怎麼辦?這就需要借助TCP的機制重新發送。
既然TCP要對包進行重傳,就需要維護一個Sequence Number,看哪些包到了,哪些沒到,哪些需要重傳,傳輸的速度應該控制到多少,這就是TCP的滑動視窗協定。
整個TCP的發送,一開始會協商一個Sequence Number,從這個Sequence Number開始,每個包都有編号。滑動視窗将接收方的網絡包分成四個部分:
- 已經接收,已經ACK,已經交給應用層的包;
- 已經接收,已經ACK,未發送給應用層;
- 已經接收,尚未發送ACK;
- 未接收,尚有空閑的緩存區域。
對于TCP層來講,每一個包都有ACK。ACK需要從SLB回複到手機端,将上面的那個過程反向來一遍,當然路徑不一定一緻,可見ACK也不是那麼輕松的事情。
如果發送方超過一定的時間沒有收到ACK,就會重新發送。隻有TCP層ACK過的包,才會發給應用層,并且隻會發送一份,對于下單的場景,應用層是HTTP層。
你可能會問了,TCP老是重複發送,會不會導緻一個單下了兩遍?是否要求服務端實作幂?從TCP的機制來看,是不會的。隻有收不到ACK的包才會重複發,發到接收端,在視窗裡面隻儲存一份,是以在同一個TCP連接配接中,不用擔心重傳導緻二次下單。
但是TCP連接配接會因為某種原因斷了,例如手機信号不好,這個時候手機把所有的動作重新做一遍,建立一個新的TCP連接配接,在HTTP層調用兩次RESTful API。這個時候可能會導緻兩遍下單的情況,因而RESTful API需要實作幂等。
當ACK過的包發給應用層之後,TCP層的緩存就空了出來,這會導緻上面圖中的大三角,也即接收方能夠容納的總緩存,整體順時針滑動。小的三角形,也即接收方告知發送方的視窗總大小,也即還沒有完全确認收到的緩存大小,如果把這些填滿了,就不能再發了,因為沒确認收到,是以一個都不能扔。
七、功成行滿見真如
唐僧經曆九九八十一難,終于到達了西天。發現金頂大仙已經在等他們了。
網絡包從手機端經曆千難萬險,終于到了SLB的公網IP所在的公網網口。由于比對上了MAC位址和IP位址,因而将網絡包收了進來。
到了西天,唐僧度過最後一條河淩雲仙渡的時候,發現滾浪飛流,約有八九裡寬闊,四無人迹。好不容易盼來一條船,還沒有底。原來駕船的是接引佛祖,玄奘法師的肉體随着河水飄走,進而脫胎換骨,成就金身。
在虛拟網關節點的外網網口上,會有一個NAT規則,将公網IP位址轉換為VPC裡面的私網IP位址,這個私網IP位址就是SLB的HAProxy所在的虛拟機的私網IP位址。
進而網絡包也脫胎換骨,實作公網IP到私有網絡IP的轉換。
當然為了承載比較大的吞吐量,虛拟網關節點會有多個,實體網絡會将流量分發到不同的虛拟網關節點。同樣HAProxy也會是一個大的叢集,虛拟網關會選擇某個負載均衡節點,将某個請求分發給它,負載均衡之後是Controller層,也是部署在虛拟機裡面的。
當網絡包裡面的目标IP變成私有IP位址位址之後,虛拟路由會查找路由規則,将網絡包從下方的私網網口發出來。這個時候包的格式為:
- 源MAC:網關MAC;
- 目标MAC:HAProxy虛拟機的MAC;
- 源IP:UE的公網IP;
- 目标IP:HAProxy虛拟機的私網IP。
在第一部分,我們 說佛經是存放在一個虛拟空間裡面的,要打開這個虛拟空間,解讀經文,需要一個芝麻開門的ID。接引佛祖會給玄奘法師一個ID。
在虛拟路由節點上,也會有OVS,将網絡包封裝在VXLAN隧道裡面,VXLAN ID就是給你的租戶建立VPC的時候配置設定的。VXLAN ID就是VPC虛拟空間的ID,OVS就是那個能夠封裝和解開私密空間的法寶。
包的格式為:
- 外層源MAC:網關實體機MAC;
- 外層目标MAC:實體機A的MAC;
- 外層源IP:網關實體機IP;
- 外層目标IP:實體機A的IP;
- 内層源MAC:網關MAC;
- 内層目标MAC:HAProxy虛拟機的MAC;
- 内層源IP:UE的公網IP;
- 内層目标IP:HAProxy虛拟機的私網IP。
在實體機A上,OVS會将包從VXLAN隧道裡面解出來,發給HAProxy所在的虛拟機。HAProxy所在的虛拟機發現MAC位址比對,目标IP位址比對,就根據TCP端口,将包發給HAProxy程序,因為HAProxy是在監聽這個TCP端口的。因而HAProxy就是這個TCP連接配接的服務端,用戶端是手機。對于TCP的連接配接狀态,滑動視窗等,都是在HAProxy上維護的。
在這裡HAProxy是一個四層負載均衡,也即他隻解析到TCP層,裡面的HTTP協定他不關心,就将請求轉發給後端的多個Controller層的一個。
HAProxy發出去的網絡包就認為HAProxy是用戶端了,看不到手機端了。網絡包格式如下:
- 源MAC:HAProxy所在虛拟機的MAC;
- 目标MAC:Controller層所在虛拟機的MAC;
- 源IP:HAProxy所在虛拟機的私網IP;
- 目标IP:Controller層所在虛拟機的私網IP。
當然這個包發出去之後,還是會被實體機上的OVS放入VXLAN隧道裡面,網絡包格式為:
- 外層源MAC:實體機A的MAC;
- 外層目标MAC:實體機B的MAC;
- 外層源IP:實體機A的IP;
- 外層目标IP:實體機B的IP;
- 内層源MAC:HAProxy所在虛拟機的MAC;
- 内層目标MAC:Controller層所在虛拟機的MAC;
- 内層源IP:HAProxy所在虛拟機的私網IP;
- 内層目标IP:Controller層所在虛拟機的私網IP。
在實體機B上,OVS會将包從VXLAN隧道裡面解出來,發給Controller層所在的虛拟機。Controller層所在的虛拟機發現MAC位址比對,目标IP位址比對,就根據TCP端口,将包發給Controller層的程序,因為他是在監聽這個TCP端口的。
在HAProxy和Controller層之間,維護一個TCP的連接配接。
Controller層收到包之後,他是關心HTTP裡面是什麼的,于是解開HTTP的包,發現是一個POST請求,内容是下單購買一個課程。
八、取得真經成金身
玄奘法師終于到達西天大雷音寺,見到了我佛如來。
佛祖願意傳經給玄奘,于是讓玄奘去藏經樓取經文,誰知道西天也有西天的規矩,如果不懂這裡的規矩,就很難和管理經文的人溝通,取不到真經。
同理,在電商服務裡面,往往在組合服務層會有一個專門管理下單的服務,Controller層雖然對外暴露的是标準的RESTful協定,但是對内會通過RPC協定調用這個組合服務層。如果不懂這個協定,就沒法通信。
假設我們使用的是Dubbo,則Controller層需要讀取注冊中心,将下單服務的程序清單拿出來,選出一個來調用。
Dubbo中預設的RPC協定是Hessian2。Hessian2将下單的遠端調用序列化為二進制進行傳輸。
Netty是一個非阻塞的基于事件的網絡傳輸架構。Controller層和下單服務之間,使用了Netty的網絡傳輸架構。有了Netty,就不用自己編寫複雜的異步Socket程式了。Netty使用的方式,就是咱們講Socket程式設計的時候,一個項目組支撐多個項目(IO多路複用,從派人盯着到有事通知)這種方式。
Netty還是工作在Socket這一層的,發送的網絡包還是基于TCP的。在TCP的下層,還是需要封裝上IP頭和MAC頭。如果跨實體機通信,還是需要封裝的外層的VXLAN隧道裡面。當然底層的這些封裝,Netty都不感覺,它隻要做好它的異步通信即可。
在Netty的服務端,也即下單服務中,收到請求後,先用Hessian2的格式進行解壓縮。然後将請求分發到線程中進行處理,線上程中,會調用下單的業務邏輯。
玄奘師徒好在後來碰到了懂得内情的注冊中心——彌勒佛,進而會到靈山,還是按照人家的規矩辦了,才将無字經文,換成有字經文。
下單的業務邏輯比較複雜,往往要調用基礎服務層裡面的庫存服務、優惠券服務等,将多個服務調用完畢,才算下單成功。下單服務調用庫存服務和優惠券服務,也是通過Dubbo的架構,通過注冊中心拿到庫存服務和優惠券服務的清單,然後選一個調用。
調用的時候,統一使用Hessian2進行序列化,使用Netty進行傳輸,底層如果跨實體機,仍然需要通過VXLAN的封裝和解封裝。
咱們以庫存為例子的時候,講述過幂等的接口實作的問題。因為如果扣減庫存,僅僅是誰調用誰減一。這樣存在的問題是,如果扣減庫存因為一次調用失敗,而多次調用,這裡指的不是TCP多次重試,而是應用層調用的多次重試,就會存在庫存扣減多次的情況。
這裡常用的方法是,使用樂觀鎖(Compare and Set,簡稱CAS)。CAS要考慮三個方面,目前的庫存數、預期原來的庫存數和版本,以及新的庫存數。在操作之前,查詢出原來的庫存數和版本,真正扣減庫存的時候,判斷如果目前庫存的值與預期原值和版本相比對,則将庫存值更新為新值,否則不做任何操作。
這是一種基于狀态而非基于動作的設計,符合REST的架構設計原則。這樣的設計有利于高并發場景。當多個線程嘗試使用CAS同時更新同一個變量時,隻有其中一個線程能更新變量的值,而其它線程都失敗,失敗的線程并不會被挂起,而是被告知這次競争中失敗,并可以再次嘗試。
最終,當下單更新到分布式資料庫中之後,整個下單過程才算真正告一段落。
當然,這個下單調用要傳回一個結果。
我們下單成功啦!!!!!!
-END-