Author: 文初 <?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
Blog: http://blog.csdn.net/cenwenchu79/
問(wèn)題
小丹同學(xué)在旺旺上問(wèn)我是否可以用 Memcached 實(shí)現(xiàn)簡(jiǎn)易消息中間件類似的功能。覺得這個(gè)需求很奇怪,就問(wèn)了一下具體的應(yīng)用場(chǎng)景,然后小丹就上來(lái)和我具體的談了究竟需求是什么。其實(shí)小丹的應(yīng)用場(chǎng)景是這樣的:客戶需要分析一些業(yè)務(wù)數(shù)據(jù),但是業(yè)務(wù)數(shù)據(jù)又是很龐大的,在原有系統(tǒng)每天晚上都有一次日分析,將業(yè)務(wù)數(shù)據(jù)分析并且歸檔,但是如果要產(chǎn)生即時(shí)分析的效果,用原有系統(tǒng)無(wú)法實(shí)現(xiàn),因?yàn)楫?dāng)天的數(shù)據(jù)內(nèi)容沒(méi)有被分析,同時(shí)如果即時(shí)的去分析并且累加到歷史分析數(shù)據(jù)上,性能也不能滿足需求,因此考慮通過(guò)消息機(jī)制來(lái)實(shí)現(xiàn)異步分析,至于異步處理的時(shí)間容忍度,可以通過(guò)配置來(lái)實(shí)現(xiàn),同時(shí)希望異步分析是可線性擴(kuò)展的,支持集群,提高效率。為什么不直接使用中間件呢?高并發(fā)的穩(wěn)定性,維護(hù)的成本,性能要求,使用成本,這些直接就排出了直接去使用中間件的想法。
起始方案的討論
在回到小丹最初提到是否可以通過(guò) Memcached 來(lái)實(shí)現(xiàn)類似于簡(jiǎn)易消息中間件的問(wèn)題上來(lái)。首先是否將消息隊(duì)列作為一個(gè)對(duì)象保存在 Memcached 中,這種做法明顯不支持高并發(fā)的情況,因?yàn)? Cache 本身的 get,put 無(wú)法保證事務(wù)。在 Memcached 中只有計(jì)數(shù)器是支持高并發(fā)的操作,因此考慮是否使用計(jì)數(shù)器并且按照一定規(guī)則來(lái)生成 key ,通過(guò)對(duì)計(jì)數(shù)器的增減來(lái)讓不同消費(fèi)者獲取到不同的消息,這種機(jī)制最大的問(wèn)題在于: 1. 輪詢的壓力不小(小丹希望是訂閱者模式, Push 過(guò)去而不是 Pull )。 2. 計(jì)數(shù)器增減不論怎么做都實(shí)現(xiàn)的是棧而不是隊(duì)列。那么是否使用我擴(kuò)展的 Memcached 的 KeySet ,這點(diǎn)我自己就反對(duì)了,這個(gè)功能效率很低,而且對(duì)于 Memcached 本身在高并發(fā)下操作是否有影響還不得而知。問(wèn)題越繞越走向死胡同了。
方案的轉(zhuǎn)變
轉(zhuǎn)換思路,重新分析小丹的需求,究竟哪幾點(diǎn)是他真實(shí)需要的: 1. 通過(guò)消息方式解耦 Web 應(yīng)用和業(yè)務(wù)分析處理。 2. 消息必須較為及時(shí)的傳遞到業(yè)務(wù)分析模塊。 3. 業(yè)務(wù)分析模塊需要支持集群方式線性擴(kuò)展性能。實(shí)現(xiàn)這些需求真的需要簡(jiǎn)單的消息中間件或者集中式存儲(chǔ)么?看看下圖的結(jié)構(gòu):
<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" /><shapetype id="_x0000_t75" stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600"><stroke joinstyle="miter"></stroke><formulas><f eqn="if lineDrawn pixelLineWidth 0"></f><f eqn="sum @0 1 0"></f><f eqn="sum 0 0 @1"></f><f eqn="prod @2 1 2"></f><f eqn="prod @3 21600 pixelWidth"></f><f eqn="prod @3 21600 pixelHeight"></f><f eqn="sum @0 0 1"></f><f eqn="prod @6 1 2"></f><f eqn="prod @7 21600 pixelWidth"></f><f eqn="sum @8 21600 0"></f><f eqn="prod @7 21600 pixelHeight"></f><f eqn="sum @10 21600 0"></f></formulas><path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f"></path><lock aspectratio="t" v:ext="edit"></lock></shapetype><shape id="圖片_x0020_1" style="VISIBILITY: visible; WIDTH: 277.5pt; HEIGHT: 286.5pt; mso-wrap-style: square" type="#_x0000_t75" o:spid="_x0000_i1026"><imagedata o:title="" src="file:///C:/DOCUME~1/WENCHU~1.CEN/LOCALS~1/Temp/msohtmlclip1/01/clip_image001.emz"></imagedata></shape>
從圖上可以看出這么幾個(gè)問(wèn)題: 1. 消息中間件本身處于單點(diǎn),如果需要擴(kuò)展或者消息本地化增加了復(fù)雜度。 2. 對(duì)于消息的獲取是采用 push 還是 pull ,如果是 push 那么需要中間件支持訂閱者的維護(hù),如果是 pull ,則需要考慮并發(fā)以及性能問(wèn)題。 3. 消息的即時(shí)性,這個(gè)還是依賴于消息中間件的實(shí)現(xiàn)機(jī)制。總的來(lái)說(shuō),如果要通過(guò)集中式緩存方式實(shí)現(xiàn)消息中間件的簡(jiǎn)單功能,還是有很多問(wèn)題。那是否直接使用消息中間件的第三方支持呢,其實(shí)又回到了最初提出的不使用的緣由。這么設(shè)計(jì)是否太復(fù)雜呢?
回過(guò)頭來(lái)看看 Memcached 的使用情況,突然發(fā)現(xiàn)其實(shí)事情可以簡(jiǎn)單來(lái)說(shuō),我記得寫過(guò)一些說(shuō)明來(lái)解釋為什么我說(shuō) Memcached 是集中式緩存而不是分布式緩存,其實(shí)是客戶端的分發(fā)算法讓很多人覺得好像分布了數(shù)據(jù)和可無(wú)限擴(kuò)展。其實(shí)這種技術(shù)結(jié)合 Hadoop 的 HDFS 的部分設(shè)計(jì)思路,可以給出一個(gè)比較好的解決方案。看看下圖的結(jié)構(gòu)設(shè)計(jì):
<shape id="圖片_x0020_3" style="VISIBILITY: visible; WIDTH: 415.5pt; HEIGHT: 302.25pt; mso-wrap-style: square" type="#_x0000_t75" o:spid="_x0000_i1025"><imagedata o:title="" src="file:///C:/DOCUME~1/WENCHU~1.CEN/LOCALS~1/Temp/msohtmlclip1/01/clip_image002.emz"></imagedata></shape>
上圖去掉了消息中間件的角色,增加了 Asyn Processor Manager 的角色,但是此角色也可以去掉,更為簡(jiǎn)化的實(shí)現(xiàn)需求,增加 Asyn Processor Manager 的功能僅僅是為了提供動(dòng)態(tài)增減 Asyn Processor 的功能。具體說(shuō)一下流程:
1. Web 應(yīng)用啟動(dòng)時(shí),讀取本地配置獲取 Asyn Processor 列表載入內(nèi)存,同時(shí)根據(jù) Asyn Processor Manager 的配置去發(fā)起請(qǐng)求獲取 Asyn Processor 最新的可用列表(如果無(wú)法獲取,則以本地的為準(zhǔn))。
2. Web 應(yīng)用根據(jù)本地實(shí)現(xiàn)的分發(fā)算法(最簡(jiǎn)單就是采用 key hash ),來(lái)選擇 Asyn Processor ,發(fā)送請(qǐng)求處理的消息。
3. 如果 Asyn Processor Manager 不存在, Web 應(yīng)用也可以實(shí)現(xiàn)定時(shí)發(fā)起 query status 請(qǐng)求來(lái)確認(rèn) Asyn Processor 的存活狀態(tài),并且更新,保證消息的正常發(fā)送。如果 Asyn Processor Manager 存在,那么確認(rèn) Asyn Processor 狀態(tài)是否存活可以由 Asyn Processor Manager 來(lái)做( Push 或者 Pull ),而 Web 應(yīng)用則可以使用對(duì) Asyn Processor Manager 的定時(shí)查詢來(lái)獲得最新的 Asyn Processor 列表。
4. Asyn Processor Manager 可以提供增加和刪除 Asyn Processor 的接口,這樣就可以支持 Asyn Processor 的增加和刪除,但也正因?yàn)? Asyn Processor Manager 的單點(diǎn)易于注冊(cè)和管理 Asyn Processor ,也增加了單點(diǎn)的風(fēng)險(xiǎn),因此每一臺(tái) Web 應(yīng)用需要對(duì) Asyn Processor Manager 不可用作好本地化配置的后備策略。
5. 使用 Http 協(xié)議作為消息傳輸協(xié)議,這樣避免 SA 去維護(hù)端口的麻煩,同時(shí)也能夠充分利用 REST 的方式來(lái)完成業(yè)務(wù)邏輯( Options 方法可以用于心跳, Put 、 Delete 可以用于 Processor 的增減(設(shè)置 Http Head 認(rèn)證方式即可解決安全問(wèn)題), Get 方式獲取信息( xml,json 等等格式可以很容易處理))。
上面的方案可以看出,如果去掉 Asyn Processor Manager ,其實(shí)方案很簡(jiǎn)化,就是每一個(gè)客戶端有一層類似于 Memcached 客戶端的分發(fā)機(jī)制,同時(shí)比 Memcached 免去了對(duì)于連接池維護(hù)的復(fù)雜性,僅僅只需要維護(hù)狀態(tài)標(biāo)示即可。
最后還囑咐小丹對(duì)于 Asyn Processor 的設(shè)計(jì)需要合理化,這部分需要支持消息接受和處理的并行處理,提高 Asyn Processor 的處理能力,同時(shí)通過(guò)分頁(yè)批量處理消息的方式減少對(duì)于 DB 的壓力(當(dāng)然需要根據(jù)具體的時(shí)效性設(shè)置消息頁(yè)的大小以及消息頁(yè) Flush 的時(shí)間)。
后話
上面的方案可能不是最好或者最優(yōu)的,這里僅僅只是分享一下自己解決這個(gè)問(wèn)題的一些心得。這此的方案討論也走了一些彎路,有時(shí)候在做任何選擇以前首先需要考慮的是到底自己需求是什么,然后再去考慮選擇什么技術(shù)去實(shí)現(xiàn)。同時(shí)盡量還是那句老話 ”Make it Simple” ,做技術(shù)的人總是喜歡做的很復(fù)雜,功能很強(qiáng)大,但是最后迷失了最初的目標(biāo),忙于去完善那些 80% 沒(méi)有用的功能,卻沒(méi)有去做好那 20% 客戶最 Care 的功能。化繁為簡(jiǎn),見招拆招,才能四量撥千斤。
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
