• 沒有找到結果。

第三章 系統設計與架構

3.5 實作推特資料搜集之服務群

3.5.2 管家(Butler)

立 政 治 大 學

N a tio na

l C h engchi U ni ve rs it y

57

容許之容量時,生產者線程會被阻塞(Block)起來,直到消費者線程消費掉在佇列 的物件後,才可以再繼續運作並生產新的物件。而對於消費者線程而言,當它詴 圖從一個空的佇列中取出物件時,該線程亦會被阻塞住,直到有新的物件被放到 佇列裡為止。

圖 3. 23 BlockingQueue 的觀念。(引用自

http://tutorials.jenkov.com/java-util-concurrent/blockingqueue.html)

阻塞佇列的例子很容易在我們日常生活看到,比方說一個進行激烈運動(消費 者線程)的人,會先消耗體內儲存的肝糖(BlockingQueue),當肝糖完全耗盡後,人 體會出現四肢無力的現象(即線程出現阻塞的情形),直到過了一陣子後,體內的 脂肪慢慢的轉化為肝糖(生產者線程)後,才會有力氣繼續激烈的運動。

阻塞佇列非常適合於生產者與消費者的模型,同時也十分便於線程間的訊息 交換(不再需要撰寫煩雜的 while 迴圈以及使用線程的 sleep 來周期性地檢核是否 有新的訊息出現),因此我們將阻塞佇列運用在服務群的 Lobby 中(RabbitMQ 的客 戶端程式庫也是採用類似的方式,從佇列中取得訊息)。

3.5.2 管家(Butler)

在豪宅的服務群裡,管家是實際執行推文搜集任務的線程,如 3.5.1 節所述,各 個線程與管家間的訊息交換都是透過一個具阻塞功能的佇列,以下稱其為 Lobby。

在沒有任何訊息進來的時候,由於 Lobby 具有阻塞的特性,管家這個線程會被阻 塞住,直到有新的訊息進來為止,在這裡我們並非是很粗糙地使用線程的 Sleep 方法來達成這個目的,而是仰賴 Java 原生的 SynchronousQueue 來實作管家這個 線程,簡單來說,管家並不是一直不斷地確認是否有新的工作需要執行,反之,

‧ 國

立 政 治 大 學

N a tio na

l C h engchi U ni ve rs it y

58

當有工作需要他做時,他才會開始工作了。

當有新到訊息送到 Lobby 時,對於管家而言就是要開始工作了,首先,它會 按訊息的類別(如執行推文搜集、暫停推文搜集或停止推文搜集工作等),分別執 行相對應的工作邏輯,其中,實際工作的執行乃委由 Quartz 進行,更明確的說 管家線程在完成所有必要的程式邏輯,並將執行、停止或刪除工作所需的資料準 備好後,即會將實際推文的搜集委由 Quartz 工作處理,並由 Quartz 掌控資料搜 集工作的排程管控,然而為了讓說明更為淺顯易懂,以下我們仍概括性的宣稱工 作主要是由管家線程處理。

圖 3. 24 管家執行推文搜集的流程。

圖 3. 24 管家執行推文搜集的流程。管家在執行工作時,會先判斷使用的 API 為何,使用 Streaming API 的工作不需要考慮到 Rate Limiting 的問題,只要確認能 通過推特的 OAuth 認證即可開始執行工作。使用 Search API 的工作,需先確認系 統上是否有可用的 Access Token,若沒有則表示沒有足夠的資源來執行該工作,

‧ 國

立 政 治 大 學

N a tio na

l C h engchi U ni ve rs it y

59

則我們會將該項工作放置到櫃台等候區的佇列中(在此我們使用

ConcurrentQueue 來實現該佇列,因為在多線程的環境下,除了管家線程外,尚 有後面章節會介紹的房務員線程會存取這個佇列),若有足夠的 Token,則可以直 接執行推文搜集的工作。其中,在豪宅裡會有一個對應表(HashMap)儲存著目前 在此待執行、執行中的工作狀態,以下稱這個對應表為工作簿,由於多個線程有 可能會同步地存取這個工作簿,故在此我們使用訊號機(Semaphore)機制以確保 在多執行序下的執行序安全性。

管家除了是系統中唯一可以執行工作的線程,也是唯一可以停止或暫停工作 的線程(另一說,由管家線程來發動工作的執行)。圖 3. 25 管家處理暫停/停止工 作的流程。當管家收到停止或暫停工作的訊息時,會先判斷該工作是否已在 Quartz 的控管下正在執行中,若還未執行且是停止的訊息,則直接將工作從工作 簿中移除(在這裡,不會看到暫停的訊息,因為暫停訊息出現的必要條件是該工 作正在執行中)。當工作目前在 Quartz 的控管下執行時,會先停止該工作,若該 工作使用 Streaming API,則直接將該工作從工作簿中移除(Streaming API 工作僅 有停止),若是使用 Search API 且為停止的訊息,則管家會將該工作從工作簿中移 除,此時 Token 的資源已經釋出,再從等待執行工作中,選取等待最久的工作加 以執行。若只是暫停的訊息,則僅需更新工作簿的狀態即可。

‧ 國

立 政 治 大 學

N a tio na

l C h engchi U ni ve rs it y

60

圖 3. 25 管家處理暫停/停止工作的流程。

綜合以上,管家的角色可以說是後台搜集程式的核心,工作的執行、暫停及 停止均由其所負責,與門房(Doorman)間的關係,管家是消費者,由他將 Lobby 中的訊息取出,而門房則是生產者,由他將 RabbitMQ 收下來的訊息放到 Lobby 中,然而管家與房務人員間的關係卻是生產者與消費者,因為當系統所有的 Token 不足時,管家會將需執行的工作放置到櫃台等候區的佇列裡,而房務人員則會依 其執行邏輯(3.5.3 節會加以說明)從該佇列中取得待執行的工作,從佇列中取出待 執行的工作,一言以蔽之,管家與房務人員是豪宅服務群的核心。