ZMQ: 基本原理
FROM:http://www.07net01.com/program/546261.html
介紹
與其他的基于常規(guī)理論基礎(chǔ)的(集中)通信系統(tǒng)不同,幾乎沒有分布式通信系統(tǒng)的什么資料,?MQ(ZeroMQ)是感興趣的讀者少數(shù)能請(qǐng)舉出的一個(gè)。
本文的目的是解釋?MQ架構(gòu)的基本概念,它們是如何組合起來的,以及它們被如此設(shè)計(jì)的原因。
拓?fù)?
拓?fù)涫?MQ最主要的概念,除非你知道“拓?fù)洹贝硎裁?#xff0c;否則將與其他概念混淆更難理解,甚至理解不當(dāng)。
按照通俗定義,我們可以說“拓?fù)洹笔且唤M參與同一業(yè)務(wù)邏輯的應(yīng)用程序。
比如:假設(shè)有一個(gè)圖像轉(zhuǎn)換服務(wù),調(diào)整圖像到所需的尺寸和分辨率。所有提供轉(zhuǎn)換的服務(wù)、所有使用該服務(wù)的應(yīng)用程序以及所有的中間節(jié)點(diǎn),比如負(fù)載均衡等,共同組成了拓?fù)洹?
通常,拓?fù)渚哂幸韵聦傩?#xff1a;
第1點(diǎn)很明顯,故意使用單詞“通道”而不是使用“連接”這一點(diǎn)是為了描述模型工作的實(shí)際情況,即使IP多播或UDP等無連接的底層傳輸亦是如此。
第2點(diǎn)說明所有拓?fù)淅锏膽?yīng)用程序應(yīng)該就什么達(dá)成一致:正被傳送的消息(比如“這是一張需調(diào)整尺寸的圖片”或“這是調(diào)整后的圖片”)、消息序列(如應(yīng)用程序中狀態(tài)機(jī)的實(shí)現(xiàn))、實(shí)際數(shù)據(jù)的編碼(圖像如何被序列化,RGB?CMYK?)等等。
第3點(diǎn)表達(dá)了這樣一個(gè)事實(shí):即使存在兩個(gè)非常相同的(例如兩家公司里的)商務(wù)邏輯部署,它們?nèi)匀恍纬闪藘蓚€(gè)拓?fù)?#xff0c;除非它們相互通過數(shù)據(jù)通道連接。
為了直觀地掌握拓?fù)涞母拍?#xff0c;明白這個(gè)概念是含混不清的非常重要的。
它的含混不清與面向?qū)ο缶幊汤锏念惡觳磺逑嗤U降亩x解釋了類是數(shù)據(jù)成員和方法的集合,然而,沒有定義解釋商務(wù)邏輯的哪一部分應(yīng)當(dāng)形成類,哪一部分不能形成類。這完全由編程者決定可封裝哪個(gè)商務(wù)概念為類,哪個(gè)不能封裝為類。編程人員把所有的商務(wù)邏輯放在一個(gè)單獨(dú)的類里也許是錯(cuò)誤的-因此這實(shí)際上在回避面向?qū)ο蟮脑O(shè)計(jì)-另外劃分這個(gè)邏輯為無限多個(gè)小類也是錯(cuò)誤的-它把這個(gè)程序轉(zhuǎn)變?yōu)橐淮蠖央y以理解的相互依賴
同樣含混不清的是沒有一個(gè)單獨(dú)的正確方法去分割商務(wù)邏輯為多個(gè)拓?fù)洹Nㄒ坏慕?jīng)驗(yàn)規(guī)則是拓?fù)涫菙U(kuò)展的原子單元。你可以把拓?fù)渥鳛檎w進(jìn)行擴(kuò)展,然而你不能只擴(kuò)展拓?fù)涞哪骋环矫妗R虼?#xff0c;如果你期望將來有擴(kuò)展獨(dú)立于功能B的功能B的需求,那么你應(yīng)當(dāng)為A創(chuàng)建一個(gè)獨(dú)立的拓?fù)?#xff0c;為B創(chuàng)建一個(gè)獨(dú)立的拓?fù)洹?
讓我們舉個(gè)具體的例子來說明上面所述:
在我們的圖像轉(zhuǎn)換應(yīng)用里,有兩個(gè)基本功能:調(diào)整圖像大小和調(diào)整圖像亮度。我們可以選擇要么為這兩個(gè)功能創(chuàng)建一個(gè)單獨(dú)的拓?fù)?#xff0c;要么分割為“調(diào)整大小”的拓?fù)浜汀罢{(diào)整亮度”的拓?fù)洹?在前一種情形下,我們將定義線路傳輸協(xié)議,這樣就可以傳輸我們感興趣的功能。假如消息的第一個(gè)字節(jié)是“1”表示調(diào)整大小,或者為“2”表示調(diào)整亮度。我們還應(yīng)該意識(shí)到這種設(shè)計(jì)緊緊地耦合了兩個(gè)功能。如果我們將來要對(duì)這個(gè)拓?fù)湓黾痈嗟奶幚砉?jié)點(diǎn),那么它們中的每個(gè)節(jié)點(diǎn)都應(yīng)當(dāng)既能調(diào)整大小也能調(diào)整亮度。
在后一種情形下,兩個(gè)功能沒有關(guān)聯(lián)。線路傳輸格式里不需要特定的“類型”域,因?yàn)樗小罢{(diào)整大小”拓?fù)涞恼?qǐng)求都是要求調(diào)整圖像大小的,而所有傳遞給“調(diào)整亮度”拓?fù)涞恼?qǐng)求都是要求調(diào)整圖像亮度的。在這樣的設(shè)計(jì)里我們可以獨(dú)立于另一個(gè)拓?fù)涠鴶U(kuò)展一個(gè)拓?fù)洹R簿褪钦f,如果我們制造出特定的單目標(biāo)的FPGA來實(shí)現(xiàn)調(diào)整圖像大小,那么我們可以簡(jiǎn)單地把它們連接到“調(diào)整大小”的拓?fù)?#xff0c;而不會(huì)影響“調(diào)整亮度”的拓?fù)洹_@樣的布署如下圖所示:
注意:客戶端應(yīng)用既可以(通過拓?fù)銩)請(qǐng)求調(diào)整圖像 ,又可以(通過拓?fù)銪)調(diào)整亮度。工作者1僅僅做圖像大小調(diào)整,工作者3僅僅做亮度調(diào)整。而工作者2能夠提供兩種服務(wù) 。
最后應(yīng)該注意的是,應(yīng)當(dāng)說幸虧一個(gè)拓?fù)淝逦鬲?dú)立于其他任何拓?fù)?#xff0c;才使得拓?fù)淇捎成涞降讓觽鬏數(shù)囊粋€(gè)屬性,比如TCP端口。這就允許底層的網(wǎng)絡(luò)按照商務(wù)標(biāo)準(zhǔn)規(guī)范其行為。例如,它可以測(cè)量由特定拓?fù)湎牡木W(wǎng)絡(luò)帶寬(因此,特定的商務(wù)邏輯,比如調(diào)整大小的服務(wù)消耗的帶寬與調(diào)整亮度服務(wù)消耗的帶寬截然相反),這樣可以根據(jù)拓?fù)鋵?duì)流量進(jìn)行調(diào)整,比如通過增加調(diào)整亮度等來抑制調(diào)整圖像大小。
傳輸
通常,除TCP之外的其他傳輸機(jī)制之上要求運(yùn)行消息層,不管是無限寬帶(性能原因),IP組播(最小化帶寬使用)或者SCTP(多宿主,心跳等)。最初的方法以TCP傳輸開始的,也許增加了TCP缺乏的比如心跳等特性,后來試圖在其他底層傳輸之上提供完全相同的行為。
這種方法存在兩個(gè)問題:
- 一,在特定的傳輸之上建立類TCP的封裝實(shí)際上使得傳輸成為多余的了。如果這種方法的行為類似于TCP,那么為什么一開始就不用TCP呢?(性能特性排除在這個(gè)規(guī)則之外)
- 二,許多傳輸實(shí)際上不可能硬塞到TCP模型里。比如,定義的IP廣播發(fā)送數(shù)據(jù)給網(wǎng)絡(luò)上所有的機(jī)器,而不是像TCP那樣發(fā)送給特定的目標(biāo)。
基于以上問題,?MQ采用了不同的方法。底層的傳輸仍然保留它們本身的特性,向上不提供通用、所有都包含的接口。然而,提供最小化接口(尤其是:消息分割,消息分段和消息原子化),并且要求更高層能夠統(tǒng)一地處理不同的底層傳輸?shù)奶匦浴?
具體的來說,這意味著傳輸層上方的封包是相當(dāng)簡(jiǎn)單的封包,比如消息分割協(xié)議(當(dāng)封裝TCP時(shí)),消息分段協(xié)議(分割長(zhǎng)的消息為適宜于基于包傳輸?shù)膸讉€(gè)包)或者后續(xù)連接協(xié)議(當(dāng)連接PGM(實(shí)際通用組播協(xié)議的)組播流時(shí),丟棄你獲得的消息的結(jié)尾部分):
建立拓?fù)浜吐酚上?
網(wǎng)絡(luò)棧里的每一層都是抽象了互聯(lián)網(wǎng)絡(luò)復(fù)雜性的某一部分。IP層抽象了查找目的主機(jī)路由這個(gè)需求。TCP層抽象了網(wǎng)絡(luò)固有的可丟失這個(gè)事實(shí)而提供了可靠性保證。
?MQ抽象了指定發(fā)送數(shù)據(jù)到特定網(wǎng)絡(luò)位置這樣需求。消息是被發(fā)送到拓?fù)涞?#xff0c;而不是發(fā)送給特定的終端節(jié)點(diǎn)。重新調(diào)用哪個(gè)與特定商務(wù)邏輯緊密相連的拓?fù)湟馕吨?dāng)你發(fā)送消息給拓?fù)涞臅r(shí)候,你基本上已經(jīng)請(qǐng)求所提供的特定的服務(wù),比如調(diào)整圖像亮度大小。實(shí)際接收消息的終端節(jié)點(diǎn)是在?MQ的透明傳輸方式里選擇的。
為了強(qiáng)化這個(gè)原則,?MQ嚴(yán)格地分離拓?fù)涞慕?#xff08;zmq_bind,zmq_connect)和真實(shí)消息的傳遞(zmq_send,zmq_rev)。
前者同底層的傳輸?shù)刂穮f(xié)同工作,比如IP地址,而后者僅僅使用處理器(文件描述符)去定位具體的拓?fù)?#xff1a;
/* Topology establishment */ int s = zmq_socket (...); zmq_connect (s, "tcp://192.168.0.111:5555");/* Message routing */ const char data [] = "ABC"; zmq_send (s, data, sizeof (data), 0);區(qū)分拓?fù)浣⒑拖⒙酚蓢?yán)格地說不是不可缺少的。畢竟,混合這兩個(gè)為一個(gè)單獨(dú)的函數(shù)是很容易的:
zmq_send (s, "tcp://192.168.0.111:5555", data, sizeof (data), 0); 分離的理論基礎(chǔ)即是技術(shù)的又是學(xué)術(shù)的。技術(shù)方面的爭(zhēng)論包括:- 當(dāng)我們打算以異步的方式接收來自拓?fù)涞南⒌臅r(shí)候,我們無論如何都要連接到這個(gè)拓?fù)洹M瑫r(shí)沒有理由不重復(fù)使用這個(gè)通道傳送消息。
- 拓?fù)浣⒑拖⒙酚傻姆蛛x很好地映射到BSD套接字API上(bind/connect和send/recv)。
現(xiàn)在,學(xué)術(shù)方面的爭(zhēng)論甚至更加重要。使用?MQ該做什么,不該做什么。
底層的協(xié)議,比如TCP,允許你發(fā)送數(shù)據(jù)給特定的終端節(jié)點(diǎn)。?MQ構(gòu)建在底層協(xié)議之上,它允許你發(fā)送數(shù)據(jù)給拓?fù)涠皇墙o特定的終端節(jié)點(diǎn)。因此,如果你打算發(fā)送數(shù)據(jù)給特定的終端節(jié)點(diǎn),那么你應(yīng)當(dāng)使用TCP或者類似的協(xié)議。如果你打算發(fā)送數(shù)據(jù)給拓?fù)?#xff0c;并且讓拓?fù)錄Q定目標(biāo),那么你應(yīng)當(dāng)使用?MQ。
不幸的是,這個(gè)概念似乎相當(dāng)難以掌握。結(jié)果是:要使人們相信?MQ不能用來定位具體的終端節(jié)點(diǎn)以及這一點(diǎn)不是漏洞而是特性幾乎是不可能的。
把拓?fù)浣⒑拖⒙酚煞蛛x沒有解決問題,不過使得真正的功能更加顯明。未來給這個(gè)組合添加名字解析(參閱下面同名的章節(jié))希望使得這個(gè)事實(shí)完全顯明:
zmq_connect (s, "Brightness-Adjustment-Service"); zmq_send (s, data, sizeof (data), 0);消息模式
當(dāng)把拓?fù)洚?dāng)作路由消息的方式考慮的時(shí)候,對(duì)不同的拓?fù)涫褂貌煌穆酚伤惴▽⒆兊们逦饋怼.?dāng)"納斯達(dá)克股票報(bào)價(jià)“拓?fù)浒l(fā)布報(bào)價(jià)給這個(gè)拓?fù)淅锏乃锌蛻魰r(shí),"亮度調(diào)整“拓?fù)鋫鬏斠粋€(gè)客戶的圖像到工作者之一,然后回傳調(diào)整好的圖像給起始客戶。
?MQ通過定義幾個(gè)所謂的“消息模式”來展示這樣事實(shí)。前者即股票報(bào)價(jià)拓?fù)涫骋粋€(gè)發(fā)布/訂閱模式的例子,而后者,亮度調(diào)整拓?fù)涫钦?qǐng)求/應(yīng)答模式的例子。消息模式既定義了節(jié)點(diǎn)間通信使用的協(xié)議,還定義了單個(gè)節(jié)點(diǎn)的功能,比如它用來路由消息的的算法。因此不同模式的行為類似于不同的協(xié)議。你不能連接發(fā)布/訂閱節(jié)點(diǎn)到請(qǐng)求/應(yīng)答節(jié)點(diǎn),就像你不能連接TCP終端節(jié)點(diǎn)到SCTP終端節(jié)點(diǎn)一樣。因此每個(gè)拓?fù)鋬H僅實(shí)現(xiàn)了一個(gè)單獨(dú)的消息模式-沒有方法把兩個(gè)不同的消息模式連接為一個(gè)單獨(dú)的拓?fù)洹?
這么嚴(yán)格的分離要求拓?fù)渥鳛橐粋€(gè)整體的行為提供保證。只要你知道拓?fù)淅锏拿總€(gè)節(jié)點(diǎn)都遵循發(fā)布/訂閱語義,那么你就能夠提供諸如“消息將分發(fā)到這個(gè)拓?fù)淅锏乃泄?jié)點(diǎn)”這樣的保證。如果這個(gè)拓?fù)涞囊徊糠衷试S以負(fù)載均衡方式而不是廣播方式發(fā)布,那么你將不能夠做這樣的保證。還有更糟糕的,由于消息模式是開放的,你將不得不希望節(jié)點(diǎn)以完全任意的方式行動(dòng),因此你根本不能提供任何保證。下面是網(wǎng)絡(luò)棧圖。注意各個(gè)消息模式位于棧的同一層而且相互之間沒有關(guān)聯(lián):
考慮到一些傳統(tǒng)的消息系統(tǒng)選擇提供通用的路由基礎(chǔ)框架,這個(gè)框架實(shí)際上允許用戶在其上構(gòu)建任何路由算法(例如AMQP模型的交換中心,路由綁定和用戶)而不是分發(fā)預(yù)打包的消息模式(例如 JMS的主題和隊(duì)列),因此說明?MQ選擇后一選項(xiàng)的基本原理是很重要的。
首先,設(shè)計(jì)功能完整而且無漏洞的消息模式是一項(xiàng)艱巨的任務(wù)。即便把創(chuàng)建模式的責(zé)任推卸給用戶,我們?nèi)钥梢源_定構(gòu)建在消息系統(tǒng)之上的大多數(shù)應(yīng)用在某種程度上說是錯(cuò)誤的。即使這兒模式得到正確地實(shí)現(xiàn),學(xué)習(xí)和開發(fā)的費(fèi)用還是超過了多次使用預(yù)打包模式所花的費(fèi)用。終究正如DNS設(shè)計(jì)一篇早期的文章所說:“[用戶]打算使用而不是理解提供給他們的系統(tǒng)。”
其次,正式定義的模式允許增強(qiáng)兩種模式不能共存在同一個(gè)拓?fù)淅锏囊蟆O⑾到y(tǒng)可核查雙方是否實(shí)現(xiàn)了同樣的消息模式,如果沒有實(shí)現(xiàn)就拒絕連接。如果所實(shí)現(xiàn)的模式是用戶任務(wù),那么這樣的檢查就不做了。
第三、常用的路由框架不能自動(dòng)發(fā)布(也稱為自動(dòng)聯(lián)合)。這意味著只能采用簡(jiǎn)單的星形結(jié)構(gòu)運(yùn)行了,一旦你打算跨越這個(gè)模型的話,你不得不提供其他信息,也即是回答“什么是消息模式?”這個(gè)問題。看看由AMQP上的各種產(chǎn)品構(gòu)建的聯(lián)合機(jī)制。這兒“模式”位總是存在,不管是僅僅顯式地或者是隱含地(支持一種模式)。
最后,我們對(duì)AMQP的經(jīng)驗(yàn)是:即便它提供了豐富的各種可能的消息模式,人們?nèi)匀灰欢僭俣卦谄渖蠘?gòu)建同樣的一對(duì)模式,而且完全忽略了其中的其他模式。
互聯(lián)網(wǎng)棧最具有獨(dú)創(chuàng)性的特征之一就是對(duì)逐跳功能(IP)和端對(duì)端功能(TCP,UDP,SCP等等)的清晰劃分。正是這種劃分允許互聯(lián)網(wǎng)生態(tài)系統(tǒng)得以發(fā)展。如果沒有這樣的劃分,每個(gè)隊(duì)端對(duì)端協(xié)議的微小更改都將如IPv4到IPv6轉(zhuǎn)換一般痛苦。
理念是網(wǎng)絡(luò)上的每個(gè)節(jié)點(diǎn)都實(shí)現(xiàn)了IP,然而,只有使用特定端對(duì)端協(xié)議比如TCP的終端節(jié)點(diǎn)可以意識(shí)到它。換句話說,中間節(jié)點(diǎn)比如路由器不需要理解位于IP上方的端對(duì)端協(xié)議層就可以以所希望的方式工作:
劃分IP和TCP層的經(jīng)驗(yàn)后來一“端對(duì)端論點(diǎn)”的形式得到了普及。端對(duì)端論點(diǎn)是這樣描述的:如果功能不能由較低層正確地提供(我們例子中的逐跳層),也就是說這個(gè)時(shí)候它需要更高層的幫助才能按照所期望的運(yùn)行,所以首先在較低層實(shí)現(xiàn)這個(gè)功能沒有什么價(jià)值。
?MQ遵循端對(duì)端原理,而且劃分自身?xiàng)橹鹛鴮?#xff08;以"X"開頭的套接字類型笨拙地表示)和端對(duì)端層(不以“X”開頭的套接字類型)。注意這與上面的TCP/IP圖類似:
類似于TCP/IP,逐跳層負(fù)責(zé)路由,而端對(duì)端層可以提供其他服務(wù),比如可靠性,加密等。
不過,我們不應(yīng)當(dāng)繼續(xù)太深入的比如為TCP/IP。不像互聯(lián)網(wǎng)棧那樣具有一個(gè)單獨(dú)的逐跳協(xié)議(IP)和多個(gè)端對(duì)端協(xié)議(TCP,UDP,SCTP等),在?MQ里每個(gè)端對(duì)端協(xié)議都擁有自己的逐跳協(xié)議。因此這個(gè)棧看起來如下:
具有這樣結(jié)構(gòu)的原因是(由逐跳層提供的)路由功能針對(duì)特定的消息模式,因此不能由多個(gè)模式共享。如果魔門仍然遇到了共享路由同一路由算法的兩個(gè)消息模式,而且將來只有通過端對(duì)端功能才能區(qū)分,那么我們將能夠模仿出一個(gè)單獨(dú)的逐跳協(xié)議上幾個(gè)端對(duì)端協(xié)義層的互聯(lián)網(wǎng)棧模型。
最后,讓我們看一看逐跳與端對(duì)端劃分的一個(gè)具體的例子。
請(qǐng)求應(yīng)答模式意味著客戶端應(yīng)用傳遞一割請(qǐng)求給一個(gè)工作者應(yīng)用(在這條道路上運(yùn)行負(fù)載均衡的),工作者應(yīng)用然后處理這個(gè)請(qǐng)求,接著生成應(yīng)答。然后回傳應(yīng)答給源客戶端:
逐跳層不得不做的事情是發(fā)送每個(gè)請(qǐng)求給一個(gè)上游節(jié)點(diǎn)(執(zhí)行負(fù)載均衡),然后發(fā)送應(yīng)答給接收到的與其相關(guān)的請(qǐng)求發(fā)送的下游節(jié)點(diǎn)。
一切運(yùn)行良好,直到處理請(qǐng)求的工作者失敗或者可能整體拓?fù)溆捎诰W(wǎng)絡(luò)失效而離線 。這種情況下,客戶端將永遠(yuǎn)卡在這兒,來等待從來不會(huì)出現(xiàn)的應(yīng)答。
為了解決這個(gè)問題,客戶端可以等待特定數(shù)量的時(shí)間,如果到那時(shí)應(yīng)答還沒有到達(dá),那么重新發(fā)送這個(gè)請(qǐng)求。這還不得不過濾掉延遲的重復(fù)的應(yīng)答。
現(xiàn)在重新回想一下端對(duì)端的論點(diǎn)。如果沒有終端節(jié)點(diǎn)的幫助,重發(fā)功能不可能實(shí)現(xiàn),因此在逐跳層實(shí)現(xiàn)重發(fā)功能(保存各種可能的優(yōu)化,比如在磁盤上保存這個(gè)請(qǐng)求,然后網(wǎng)失效的節(jié)點(diǎn)重新啟動(dòng)的時(shí)候重新發(fā)送這個(gè)請(qǐng)求)沒有什么意義。
我們得到的最終結(jié)果是路由在逐跳層實(shí)現(xiàn),可靠性在逐跳層上的端對(duì)端層里實(shí)現(xiàn)。
名字解析
現(xiàn)在,?MQ不能為自己提供名字。為了加入到拓?fù)淅?#xff0c;你不得不使用底層傳輸定義的地址,比如IP地址和TCP端口。
雖然現(xiàn)在是這樣,但將來值得提供把拓?fù)涿?#xff08;”?MQ名字“)轉(zhuǎn)換為底層傳輸?shù)刂返拿纸馕龇?wù) 。例如,字符串"Brightness-Adjustment-Service"可解析為"tcp://192.168.1.111:5555"。
關(guān)于這個(gè)問題還有許多要思考,不過主要問題似乎是拓?fù)涫怯啥鄠€(gè)節(jié)點(diǎn)組成的,而且名字解析服務(wù)選擇這些節(jié)點(diǎn)之一。決定應(yīng)當(dāng)可能是基于管理標(biāo)準(zhǔn)的。例如,當(dāng)連接到“納斯達(dá)克股票報(bào)價(jià)"拓?fù)涞臅r(shí)候,你需要名字服務(wù)連接你到本地的股票報(bào)價(jià)中心而不是連接到納斯達(dá)克自身的報(bào)價(jià)中心,或者甚至最糟糕的情形,連接你到競(jìng)爭(zhēng)者的股票報(bào)價(jià)中心。
技術(shù)上來說,名字解析服務(wù)應(yīng)當(dāng)使用DNS實(shí)現(xiàn),因?yàn)镈NS是唯一一個(gè)廣泛可用的分布式數(shù)據(jù)庫。而且這兒的名字解析服務(wù)的需求似乎完美的匹配DNS所提供的特性。
像DNS這樣以松散地一致性分布式數(shù)據(jù)庫方式存儲(chǔ)名字的設(shè)計(jì)結(jié)果應(yīng)當(dāng)引起注意,比如拓?fù)鋺?yīng)該是長(zhǎng)期存活并且很少更改條目,以確保DNS緩沖機(jī)制不能損壞名字的解析等等。
附錄:設(shè)計(jì)原則
附錄總結(jié)了用來評(píng)估某個(gè)特定的消息模式是否是良好設(shè)計(jì)的原則。
統(tǒng)一性原則
統(tǒng)一性原則描述的是你連接應(yīng)用到拓?fù)涞哪囊粋€(gè)節(jié)點(diǎn)應(yīng)該是無關(guān)緊要的。提供的服務(wù)應(yīng)當(dāng)是相同的。
統(tǒng)一性原則聽起來很明顯,不過破壞它卻非常容易。考慮一下?MQ里目前已經(jīng)實(shí)現(xiàn)的發(fā)布/訂閱模式。 它允許一個(gè)拓?fù)淅镉卸鄠€(gè)發(fā)布者,這引入了非統(tǒng)一性:
在上圖中,客戶端C將看到不同的數(shù)據(jù)反饋,這取決于它連接到中間者1還是中間者2 。中間者1既提供發(fā)布者A的消息也提供發(fā)布者B的消息,而中間者2只提供來自發(fā)布者B的消息。
注意統(tǒng)一性原則是怎樣成為互聯(lián)網(wǎng)設(shè)計(jì)里的重要原則之一的:不管你把你筆記本插入到那個(gè)插頭里,你使用的是哪種wi-fi或者給你提供互聯(lián)網(wǎng)訪問的是哪個(gè)ISP,你看到的世界總是相同的。
可擴(kuò)展性原則
可擴(kuò)展性原則描述的是當(dāng)拓?fù)湟匆驗(yàn)楣?jié)點(diǎn)超負(fù)荷要么因?yàn)檫B接擁擠而不能處理負(fù)載時(shí),通過給這個(gè)拓?fù)湓黾有碌墓?jié)點(diǎn)應(yīng)當(dāng)可能解決這個(gè)問題。而且增加的節(jié)點(diǎn)數(shù)是隨著負(fù)載線性增長(zhǎng)的。
讓我們看一看違反可擴(kuò)展性原則的模式。最簡(jiǎn)單的非可擴(kuò)展性模式是分割一個(gè)應(yīng)用為固定數(shù)目的功能塊。想象一個(gè)由賬務(wù)和人力資源功能組合的大應(yīng)用。這兒,一個(gè)單獨(dú)的盒子不能處理這樣的負(fù)載,編程人員也許決定分割為賬務(wù)功能和人力資源功能為獨(dú)立執(zhí)行部分,這樣它們運(yùn)行在兩個(gè)盒子上:
這樣的設(shè)計(jì)無法滿足可擴(kuò)展性測(cè)試。當(dāng)兩個(gè)盒子不能處理負(fù)載時(shí),在不重寫應(yīng)用的情況下,沒有辦法增加第三個(gè)盒子。
注意:?MQ里的模式是由一對(duì)套接字來表示的。
非可擴(kuò)展性模式的一個(gè)更復(fù)雜的例子是分布式日志記錄:
隨著記錄日志的應(yīng)用數(shù)目的增長(zhǎng),日志記錄器的負(fù)載就增加,直到它不能處理負(fù)載為止。在應(yīng)用與日志記錄器之間增加中間節(jié)點(diǎn)不能真正地解決這個(gè)問題。無論是否有中間節(jié)點(diǎn),所有的信息都不得不到達(dá)日志記錄器,因此無論如何在某一刻日志記錄器就會(huì)爆。
為了使這種“數(shù)據(jù)收集”的模式可擴(kuò)展,中間節(jié)點(diǎn)不得不聚集信息,即發(fā)送固定數(shù)量的信息到下游,并且與上游應(yīng)用的數(shù)目無關(guān)。這種聚集采用了計(jì)算總數(shù)、傳遞統(tǒng)計(jì)而不是像以上所說傳遞消息等。這種聚集模式在發(fā)布/訂閱模式里用來前傳訂閱的。通過控制訂閱請(qǐng)求的絕對(duì)數(shù)量使得發(fā)布者不會(huì)超負(fù)荷運(yùn)行,請(qǐng)求會(huì)聚集到中間節(jié)點(diǎn),并且只有增量的那部分才進(jìn)一步發(fā)送給上游(這個(gè)算法的詳細(xì)討論請(qǐng)參考這兒)。
再次提醒,注意互聯(lián)網(wǎng)是怎樣遵循可擴(kuò)展性原則的。可在任何時(shí)候增加新節(jié)點(diǎn),不管是最終用戶的盒子還是中間框架,并且不會(huì)損害整體互聯(lián)網(wǎng)的功能和性能。
插入原則
插入原則描述的是向拓?fù)淅锊迦胫虚g節(jié)點(diǎn)應(yīng)當(dāng)不會(huì)更改終端節(jié)點(diǎn)的行為。(注意插入中間節(jié)點(diǎn)可用來擴(kuò)展這個(gè)拓?fù)洹>唧w的例子可以看看這兒)
讓我們看一個(gè)經(jīng)常請(qǐng)求確定連接到一個(gè)特定終端節(jié)點(diǎn)的對(duì)等節(jié)點(diǎn)數(shù)的特性的例子。我們看一看下面的轉(zhuǎn)換,這兒中間節(jié)點(diǎn)I是插入到這個(gè)拓?fù)涞?#xff1a;
正如所看到的,終端節(jié)點(diǎn)A的行為在中間節(jié)點(diǎn)插入到這個(gè)拓?fù)涞臅r(shí)候更改了。不是匯報(bào)三個(gè)對(duì)等節(jié)點(diǎn),現(xiàn)在它匯報(bào)了兩個(gè)對(duì)等節(jié)點(diǎn)。因此展示連接的對(duì)等節(jié)點(diǎn)數(shù)破壞了插入原則。
再次說明,插入原則對(duì)互聯(lián)網(wǎng)運(yùn)行的方式來說十分重要。如果在中間更改了拓?fù)?即當(dāng)骨干網(wǎng)操作員增加了新的路由器- 將破環(huán)終端節(jié)點(diǎn)上的應(yīng)用,那么互聯(lián)網(wǎng)將以非常快的速度陷入到崩塌的狀態(tài)之中。
結(jié)論
這篇文章里所描述的結(jié)構(gòu)展示的是包含兩個(gè)意外的?MQ的當(dāng)前設(shè)計(jì),這兒的兩個(gè)意外指的是正在開發(fā)的特性。希望這篇文章提供了分布式消息的簡(jiǎn)短介紹,并為這個(gè)領(lǐng)域里的將做的工作打好基礎(chǔ)。
總結(jié)