在前一回中提到佇列是「平衡服務品質及成本」的重要機制,這是因為提升服務品質和降低服務成本這二者的目標時常是相衝突的。例如,透過增加伺服器的數量來提升服務品質,就得增加服務成本。透過規畫系統中佇列的運用方式,就有機會控制品質和成本的平衡點,達成你的應用中理想的配置。

接下來讓我舉一個實際的例子,說明如何運用佇列來達成這個目標。

事件記錄系統的基本架構
有些系統會需要收集大量的事件記錄(Event Log),像是智慧型電視的雲端服務系統,需要不斷的收集電視上使用者操作的行為,以便提供更符合使用者需求的服務,像是推薦電視上觀看的內容。而像廣告分析的系統,也會不斷收集各網頁上使用者和系統互動的記錄,以便分析每個使用者的需求,做為日後投放廣告給該使用者的計算依據。

此類的系統,都會需要不斷從大量的客戶端頻繁的送出事件記錄到伺服器端,而伺服器端除了記錄原始的事件記錄內容之外,也會需要「整理」這些事件記錄,甚至做進階的計算、匯整及分析,以利其他系統,例如推薦系統或分析系統加以運用。

如果用Java的技術來實作,最早,你的設計可能會想要像圖1這樣。在這樣的架構裡,透過EvetLogServlet這個servlet程式,來接收來自於客戶端的事件記錄回報,並且將其內容寫至Log Datastore裡,以供之後另一個獨立的程式LogAnalyzer,讀取Log Datastore中的內容,之後進行分析。

就邏輯來說,上述的架構看起來沒有什麼問題,但是你可以想見,當每秒鐘進來的事件回報數目大過一個門檻之後,因為通常Log Datastore可能是個關聯式資料庫,所以寫至Log Datastore的動作是很緩慢的,這會使得系統可能來不及處理這些事件回報的記錄。只要在系統中等待被處理的客戶端請求被消化的速度,小於進到系統的速度,那麼就會在EvetLogServlet端累積愈來愈多無法被處理的請求,也會佔用愈來愈多的資源,例如連線的socket數,最後導致資源耗盡,或是客戶端請求逾時。

改良的系統架構:加入分散式處理概念
所以,你可能打算擴展一下規模,所以你加了更多的機器,像是圖2這樣。

你用了多個httpd及Java Servlet container來試圖提供更多的服務能力,並且在最前面加上了一個負載平衡器,以便將負載平均分散到每個httpd及後面的Java Servlet container之上。

但是,問題的關鍵並不在CPU不夠多,或是網路不夠快,而是在於Log Datastore本身消化寫入動作的能力不夠快,所以即使你增加了httpd和Servlet container的數目,對Log Datastore的寫入動作仍然還是系統效能的瓶頸。

當然,你也可以增加更多的Log Datastore,但是有些時候,儲存資料的部份基本上都是集中化的,分散式的規畫則是另一個議題了。

搭配工作佇列的系統架構
即使你不使用關聯式資料庫,而採用像是NoSQL之類的儲存方案,但即使是如此,寫入時間也很有可能無法滿足系統的需求。這個時候,很多人便會採用所謂「工作佇列(Job Queue)」的方式。在引入工作佇列之後,你的架構或許會像圖3這樣。

當EvetLogServlet收到來自於客戶端的請求之後,便逕將要記錄的內容送至Job Queue去,之後便可返回。因此,客戶端的請求便不會持續的在系統中佔用資源。另外,會有若干個獨立的Worker程式,數量依系統需求及資源限制而定,持續從Job Queue中取出待處理的事件記錄資訊,將其寫至Datastore中。

利用多重的緩衝搭配工作佇列的系統架構
由於寫至Datastore的動作還是一樣的慢,所以,可能還是存在類似的問題。Job Queue本身是個緩衝,而你可能會想到利用多重的緩衝,來解決這樣的問題,所以有了如圖4的架構。

在這樣的架構中,先利用第一層的Worker寫到存取速度較快的Raw Datastore,以便快速消化Job Queue中的內容,避免Job Queue因為Worker處理不及而爆量。接著再利用第二級的Worker,自Raw Datastore取出資料,再經過整理計算後存進Report Datastore,此時,就得到了可供其他系統運用、經過計算或分析之後的進階資料了。

上述的架構若套用一些實際的軟體組成,可能會是如圖5這樣。

其中,beanstalkd是一個高效的、將工作儲存在主記憶體中的工作佇列,因此,工作被置入佇列的速度可以是非常快。一般來說,每秒置入數萬個工作是不成問題的。接著,再利用Java寫成的Worker程式,將原始的事件記錄資訊儲存在Cassandra裡。Cassandra是目前普遍運用的NoSQL系統,它的寫入速度不錯,但是不能和以主記憶體為主的工作佇列相比。這麼一來,就有了分層的緩衝意義。第三層是MySQL,它是關聯式資料庫,寫入速度最慢。

每秒要處理幾萬個事件的回報,如果不使用工作佇列而想要把它們都記錄起來,可能需要動用到不少的資源,但是,透過高效的工作佇列,以及分層緩衝的概念,就可以完成這個目標。這說明了佇列對於資源配置的作用。而妥善利用佇列,的確可以為我們的應用系統開發提供很多幫助。

 


圖一,以Java開發事件紀錄系統的基本架構

圖二,增加分散式處理機制的事件紀錄系統架構

圖三,搭配工作佇列的事件紀錄系統架構

圖四,同時搭配工作佇列與多重緩衝的事件紀錄系統架構

 

圖五,搭配工作佇列與多重緩衝的事件紀錄系統架構,以實際的應用軟體所建構出的樣貌

想掌握最新IT動態,歡迎按贊加入iThome粉絲團

專欄作者

熱門新聞

Advertisement