本文翻譯自Building Analytics Engine Using Akka, Kafka & ElasticSearch,已獲得原作者Satendra Kumar和網站授權。
在這篇文章里,我將和大家分享一下我用Scala、Akka、Play、Kafka和ElasticSearch等構建大型分布式、容錯、可擴展的分析引擎的經驗。
我的分析引擎主要是用於文本分析的。輸入有結構化的、非結構化的和半結構化的數據,我們會用分析引擎對數據進行大量處理。如下圖所示為第一代架構,分析引擎可以用REST客戶端或Web客戶端(引擎內置)訪問。
簡單描述一下用到的技術:
- Play框架做REST服務器和WEB應用。Play是個基於輕量級、無狀態和WEB友好的MVC框架。
- Akka集群作處理引擎。Akka是個工具集,用於在JVM上簡化編寫高並發、分布式、和有彈性的消息驅動應用。
- ClusterClient用於與Akka集群通信。它運行在REST服務器上,將任務發給Akka集群。使用ClusterClient是一個非常錯誤的決定,因為它並不會維持與Akka集群的長連接,因而會經常報連接錯誤,而且重新建立連接時還要把那個Client所在的JVM也一起重啟。
- ElasticSearch用作查詢引擎和數據存儲,包括原始數據和分析結果。
- Kibana用作可視化平台。Kibana是有彈性的分析和可視化平台。
- Akka Actor用作ElasticSearch的數據導入導出服務。它的表現非常好,服務從來沒出過故障。
- S3用作集中化文件存儲。
- Elastic Load Balance用作節點之間的負載均衡。
- MySQL用於元數據存儲。
我們從Akka 2.2.x版開始用起,也碰到了一些嚴重問題,主要表現為:
- ClusterClient與Akka集群之間連接斷開:在負載大CPU使用率高時,ClusterClient常常莫名其妙的與Akka集群斷開連接。因為它是個第三方庫,所以我們只好把JVM重啟來讓它繼續工作,有的時候還要半夜爬起來處理問題。
- 資源利用率:我們發現REST服務器上CPU使用率只有2-5%,這樣太浪費資源了,Amazon EC2服務器可不便宜。
- 延遲問題:REST服務器運行在不同的服務器上。這樣就造成了延遲問題,因為對於每一條Client發過來的請求,它都要把請求反序列化,再序列化然后才能發到Akka集群。從Akka集群發來的響應消息也是一樣,要先反序列化再序列化,然后才能發給請求方。這樣的序列化和反序列化過程常常導致超時問題。而且,我們只是把Play用作REST后台而不是完整的WEB框架,我承認這是我們的設計問題。
為了解決這些問題我們設計了第二代架構,主要變化有:
- 去掉Akka ClusterClient。
- 用Spray替換掉Play架構,因為把Play用作REST服務不是個正確的決定。Spray是個輕量級HTTP服務器。
- 為了減少端到端的延遲,我們把REST服務運行在Akka集群節點所在的JVM上,而不是單獨的節點上。
新架構是這樣的:
太棒了,這樣的系統工作得非常好。生活又變得非常美好,團隊也得到了很多表揚。
三個月后,來了個要增加Datasift做為數據源的新需求,提供流數據和歷史數據。這個需求好滿足,只要增加一個新服務,從Datasift中拉取數據並發送到分析集群上即可。
增加新服務很簡單,但卻導致了新問題:
- 上述架構本質上來說是個推送模型,每當有大量的流或歷史數據被推送過來時,集群就會處理不過來。
- 我們決定把集群由4個節點擴展為8個節點。這樣峰值情況下還可以,但正常情況下大多數節點都處於非常空閑的狀態。我們用的是Amazon EC2 4x.Large節點,非常貴,所以就引發出了基礎設施的費用問題。
- 我們決定使用Amazon的自動擴容服務。在集群上負載增加時它的確是自動擴容了,可是負載降下來時它卻沒有縮容。Amazon自動擴容服務對我們的業務情況處理得不夠好。
- 另一個問題是Akka集群的內部節點通信在CPU使用率超過90%時常常出問題,原因可能是因為我們經驗不夠不會配Akka集群,也有可能是Akka集群那時候不象現在這么成熟。
- 如果有節點崩潰的話,那整個處理過程就會停止。
當我們在努力為這個問題找解決方案時,又收到需求要再增加一種數據源!
在經過很多次頭腦風暴之后,我們明白了現有架構的問題,於是做出了一個簡單、可擴展和容錯的第三代架構:
在這個新架構里,我們去掉了Akka集群,重寫了分析引擎。它完全是基於Akka Actor的,REST服務也是運行在相同的JVM上。REST服務只是簡單的從客戶端接收請求,做認證和鑒權,然后創建一條待處理消息發送到Kafka隊列中去。分析引擎的每個節點都會從Kafka隊列中拉取數據,處理完畢再拉取下一批。這樣它就永遠不會忙不過來。
受益於Kafka的內部機制,不管哪個節點死掉了,Kafka都會自動的把要處理的消息發送到另一個正常節點上,所以不會有任何消息丟失。
在這個架構下我們就不必繼續租用以前的Amazon EC2 4X large服務器了,只要用Amazon EC2 2X large就可以支持任何負載,節省了很多錢。(此處應有掌聲。:) )
這完全是個基於拉取模式的架構。所有的請求和浪涌 都通過Kafka集群處理。它永遠不會忙不過來,因為所有操作都是基於拉取模式的。整個系統部署在26台EC2節點上,已經快兩年了,生產系統一次故障都沒出過。
我們也用Kafka保存了各種服務日志來分析性能、安全和用戶行為。Kafka生產者會把日志發送到Kafka服務器中。因為我們已經有了ElasticSearch的導入導出服務,我們可以仍然用它們來推送ElasticSearch的日志。我們也可以輕松地用Kibana將用戶行為可視化。
結論
- Akka Actors非常適合於打造高並發、分布式、有彈性的應用程序。
- Spray非常適合作輕量級HTTP服務器。現在它已改名為Akka-HTTP。
- Play框架非常適合於構建高並發、可擴展的WEB應用,它底層是Akka。
- ElasticSearch是個非常好的搜索引擎,它底層是Lucene,可以提供全文檢索功能。盡管我們也把它當成數據存儲來用,但數據持久化並不是它的強項(比如與Cassandra相比)。
- Kafka非常適合於流處理和日志匯聚。它的架構設計就已經支持可擴展、分布式、容錯等功能。
請耐心等待我改進第四版架構之后再更新這篇文章吧……快樂編程,不斷創新!
http://www.infoq.com/cn/articles/use-akka-kafka--build-analysis-engine?utm_campaign=rightbar_v2&utm_source=infoq&utm_medium=articles_link&utm_content=link_text