背景java
前幾個月,使用Vertx重構了公司的一個子系統,該系統負責公司核心數據subscriber的採集、處理、存儲和搜索。這裏介紹下重構該系統時的一些關鍵點。web
架構redis
重構前系統部署圖:數據庫
重構前系統主要有2部分組成,這2部分都會對Subscriber數據操做:緩存
Java APP: 是個定時任務觸發的APP,每2小時跑一次,每次啓動後作如下的事情:網絡
- 從MongoDB里加載已有的數據到內存。
- 讀取準備好的Data文件,處理文件中的數據,和已加載的數據作合併,這個處理的過程會致使Subscriber數據有添加、刪除和更新操做。
- 處理完Data文件後,將數據持久化到MongoDB和Elasticsearch。
JBoss服務:架構
- 從Kafka中來的消息數據,批量處理Kafka消息,會添加和更新Subscriber數據到MongoDB和Elasticsearch中。
- 從其餘系統觸發的API調用,接收一些API請求,這些請求也會增長、刪除和更新Subscriber數據。在更新的時候,由於查詢條件的多樣性,爲了提升查詢Subscriber的速度,對MongoDB的Subscriber Collection建了各類索引。
重構緣由併發
- 對同一種的數據的操做在2個不一樣的服務中,一種是war一種是jar,不利於維護。代碼在不一樣的Rep和Project下,維護也不方便。
- Jboss如今是單實例部署,Jboss中還部署有其餘的服務,Jboss的穩定性直接影響了該服務。爲了提升查詢速度,對數據創建了多種不一樣的索引,更新數據增長了數據庫的負擔。
- 定時任務JavaAPP每次在處理某個客戶的Subscriber數據時候,都要從MongoDB加載數據到內存,耗時沒有效率。由於是定時任務,對數據更新不夠及時,會影響其餘依賴Subscriber數據的服務。
- 數據更新衝突:在定時任務把數據加載到內存,正在處理時,此時若是Jboss也在更新數據會致使數據更新衝突(如今採用了一個很tricky的方式解決)。
重構後系統部署圖app
重構後,系統組件介紹和說明:異步
Adapter服務:
- 數據適配服務,統一接收來自文件、Kafka和API調用的數據,對數據進行預處理,發送相應的業務消息到Event Bus。
- 由於對Adapter的觸發方式只有2種,一種是REST API,另外一種是鏈接Kafka讀取消息,因此Adapter服務能夠經過部署多個實例來增長可用性,也順便提升了總體性能。
Mapper服務:
- 數據處理服務,按數據分片進行部署,分片規則能夠按客戶大小來分,好比把10個大客戶的數據部署在一個實例上,200個小客戶的數據部署在另外一個實例上,也能夠按數據量平均分。
- 初始啓動時候加載所屬該實例的全部Subscriber數據到內存,從EventBus上接收來自Adapter的業務請求,處理請求並對數據進行更新。
- 數據更新策略:
- 來自API的請求都會實時的更新到MongoDB和Elasticsearch中。
- 來自文件和Kafka的數據更新量比較大,爲了不每次對數據更新的時候都去操做DB和ES,經過一個隊列緩存全部的更新。觸發隊列持久化條件:一種是當緩存Size達到閾值時候觸發,另外一種是定時觸發,觸發後批量更新數據到MongoDB和Elasticsearch中。
- 內存、MongoDB和Elasticsearch中數據一致性:由於如今數據在內存中,使用了Vertx的MongoClient的異步回調機制,保證只有更新到MongoDB成功後纔去更新Elasticsearch,保證MongoDB裏數據的準確性是第一位的。而ElasticSearch中數據的準確性是經過「定時補償機制」去保證:有其餘定時執行的腳本去定時檢查,並決定是否從新對某個客戶的數據重建索引。
重構以後的可改進項:
- 耗內存,全部的Subscriber數據都分片加載到了JVM裏。這部分能夠把數據放到其餘的存儲中,好比redis,但就算是放到redis,也是耗內存。
- 若是系統出錯,會致使數據在MongoDB和ElasticSearch之間不一致,須要其餘方式去作「數據一致性補償」。若是資源容許,能夠把數據更新同步單獨拿出來實現,使用相似處理「分佈式系統數據一致性」的方式來改善這一點。
小結
一些技術關鍵點
1 異步非阻塞
Vertx的異步非阻塞機制有很好的併發性能。網絡IO依賴了Netty,Java NIO的特性。
2 Vert.x-Web
Vertx-web能夠很方便的去實現一個web app,很容易實現一些REST APIs。
3 Data access client
Vertx提供了訪問各類存儲的Client,這些client的API都是異步的,能夠很方便的去訪問MongoDB,JDBC,Redis等。
4 Event Bus
Vertx的一個核心功能,重構這個子系統時也很依賴這個功能。Event Bus可用於不一樣Verticle之間的通訊,也能夠用於Vertx cluster之間的通訊。
5 功能解耦
系統中各個子功能能夠按不一樣的Verticle去實現,不一樣的Verticle能夠經過EventBus去通訊解耦。Vertx支持動態的加載和卸載Verticle,也就能夠實如今運行時動態的加載卸載某些功能。
6 集羣模式
Adapter服務和Mapper服務是經過Vertx的Cluster模式組成了集羣,集羣中節點發現和通訊經過Hazelcast管理。使用Vertx實現的服務,能夠單實例部署,也能夠組成集羣提供服務。
參考