Author: 文初 <?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
Blog: http://blog.csdn.net/cenwenchu79/
問題
小丹同學在旺旺上問我是否可以用 Memcached 實現簡易消息中間件類似的功能。覺得這個需求很奇怪,就問了一下具體的應用場景,然后小丹就上來和我具體的談了究竟需求是什么。其實小丹的應用場景是這樣的:客戶需要分析一些業務數據,但是業務數據又是很龐大的,在原有系統每天晚上都有一次日分析,將業務數據分析并且歸檔,但是如果要產生即時分析的效果,用原有系統無法實現,因為當天的數據內容沒有被分析,同時如果即時的去分析并且累加到歷史分析數據上,性能也不能滿足需求,因此考慮通過消息機制來實現異步分析,至于異步處理的時間容忍度,可以通過配置來實現,同時希望異步分析是可線性擴展的,支持集群,提高效率。為什么不直接使用中間件呢?高并發的穩定性,維護的成本,性能要求,使用成本,這些直接就排出了直接去使用中間件的想法。
起始方案的討論
在回到小丹最初提到是否可以通過 Memcached 來實現類似于簡易消息中間件的問題上來。首先是否將消息隊列作為一個對象保存在 Memcached 中,這種做法明顯不支持高并發的情況,因為 Cache 本身的 get,put 無法保證事務。在 Memcached 中只有計數器是支持高并發的操作,因此考慮是否使用計數器并且按照一定規則來生成 key ,通過對計數器的增減來讓不同消費者獲取到不同的消息,這種機制最大的問題在于: 1. 輪詢的壓力不小(小丹希望是訂閱者模式, Push 過去而不是 Pull )。 2. 計數器增減不論怎么做都實現的是棧而不是隊列。那么是否使用我擴展的 Memcached 的 KeySet ,這點我自己就反對了,這個功能效率很低,而且對于 Memcached 本身在高并發下操作是否有影響還不得而知。問題越繞越走向死胡同了。
方案的轉變
轉換思路,重新分析小丹的需求,究竟哪幾點是他真實需要的: 1. 通過消息方式解耦 Web 應用和業務分析處理。 2. 消息必須較為及時的傳遞到業務分析模塊。 3. 業務分析模塊需要支持集群方式線性擴展性能。實現這些需求真的需要簡單的消息中間件或者集中式存儲么?看看下圖的結構:
<?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>
從圖上可以看出這么幾個問題: 1. 消息中間件本身處于單點,如果需要擴展或者消息本地化增加了復雜度。 2. 對于消息的獲取是采用 push 還是 pull ,如果是 push 那么需要中間件支持訂閱者的維護,如果是 pull ,則需要考慮并發以及性能問題。 3. 消息的即時性,這個還是依賴于消息中間件的實現機制。總的來說,如果要通過集中式緩存方式實現消息中間件的簡單功能,還是有很多問題。那是否直接使用消息中間件的第三方支持呢,其實又回到了最初提出的不使用的緣由。這么設計是否太復雜呢?
回過頭來看看 Memcached 的使用情況,突然發現其實事情可以簡單來說,我記得寫過一些說明來解釋為什么我說 Memcached 是集中式緩存而不是分布式緩存,其實是客戶端的分發算法讓很多人覺得好像分布了數據和可無限擴展。其實這種技術結合 Hadoop 的 HDFS 的部分設計思路,可以給出一個比較好的解決方案。看看下圖的結構設計:
<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 的角色,但是此角色也可以去掉,更為簡化的實現需求,增加 Asyn Processor Manager 的功能僅僅是為了提供動態增減 Asyn Processor 的功能。具體說一下流程:
1. Web 應用啟動時,讀取本地配置獲取 Asyn Processor 列表載入內存,同時根據 Asyn Processor Manager 的配置去發起請求獲取 Asyn Processor 最新的可用列表(如果無法獲取,則以本地的為準)。
2. Web 應用根據本地實現的分發算法(最簡單就是采用 key hash ),來選擇 Asyn Processor ,發送請求處理的消息。
3. 如果 Asyn Processor Manager 不存在, Web 應用也可以實現定時發起 query status 請求來確認 Asyn Processor 的存活狀態,并且更新,保證消息的正常發送。如果 Asyn Processor Manager 存在,那么確認 Asyn Processor 狀態是否存活可以由 Asyn Processor Manager 來做( Push 或者 Pull ),而 Web 應用則可以使用對 Asyn Processor Manager 的定時查詢來獲得最新的 Asyn Processor 列表。
4. Asyn Processor Manager 可以提供增加和刪除 Asyn Processor 的接口,這樣就可以支持 Asyn Processor 的增加和刪除,但也正因為 Asyn Processor Manager 的單點易于注冊和管理 Asyn Processor ,也增加了單點的風險,因此每一臺 Web 應用需要對 Asyn Processor Manager 不可用作好本地化配置的后備策略。
5. 使用 Http 協議作為消息傳輸協議,這樣避免 SA 去維護端口的麻煩,同時也能夠充分利用 REST 的方式來完成業務邏輯( Options 方法可以用于心跳, Put 、 Delete 可以用于 Processor 的增減(設置 Http Head 認證方式即可解決安全問題), Get 方式獲取信息( xml,json 等等格式可以很容易處理))。
上面的方案可以看出,如果去掉 Asyn Processor Manager ,其實方案很簡化,就是每一個客戶端有一層類似于 Memcached 客戶端的分發機制,同時比 Memcached 免去了對于連接池維護的復雜性,僅僅只需要維護狀態標示即可。
最后還囑咐小丹對于 Asyn Processor 的設計需要合理化,這部分需要支持消息接受和處理的并行處理,提高 Asyn Processor 的處理能力,同時通過分頁批量處理消息的方式減少對于 DB 的壓力(當然需要根據具體的時效性設置消息頁的大小以及消息頁 Flush 的時間)。
后話
上面的方案可能不是最好或者最優的,這里僅僅只是分享一下自己解決這個問題的一些心得。這此的方案討論也走了一些彎路,有時候在做任何選擇以前首先需要考慮的是到底自己需求是什么,然后再去考慮選擇什么技術去實現。同時盡量還是那句老話 ”Make it Simple” ,做技術的人總是喜歡做的很復雜,功能很強大,但是最后迷失了最初的目標,忙于去完善那些 80% 沒有用的功能,卻沒有去做好那 20% 客戶最 Care 的功能。化繁為簡,見招拆招,才能四量撥千斤。
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

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