上一篇我們通過示范案例基本了解了一個獨立交易型別的庫存管理模塊應該是怎樣的一塊業務,這篇我們討論一些如何從技術上來實作這樣的業務模塊,講確切點應該說如何借助kafka的特性來實作功能開發,
底層方面:多節點服務器集群、kafka分布部署,
對上一層主要關注partition相關的問題:partition的分布與consumer如何對應,根據kafka官方檔案:一個topic分出多個partition,一般按照集群節點broker倍數設定,那么一個topic的partition差不多以同等數量分布于每個broker上,或者針對一個topic,每個集群節點上都有多個partition,從consumer配置來講就是在每個節點上部署同一組(相同consumer-group-id)consumer,所謂consumer就是alpakka-kafka的一個stream,由于最終的完整應用會部署在每一個集群節點,應用中包括了consumer,所以每組consumer已經是分布式的了,不需要分片sharding機制,在每個節點啟動應用時就開始運行多個應用里的kafka-conusmer-stream就行了,至于consumer分布式運算是體現在底層kafka的分布式部署上的,
再上一層是庫存交易運算層,這部分功能是業務實作核心,包括:庫存狀態更新、庫存流轉、交易日志、庫存賬目等等,我們目前只關心庫存狀態,但假設這部分完整業務功能是多并發、復雜又消耗資源的,那么應該把它作為分片sharded-entity來設計,這樣,這些耗資源的運算可以被分發到各節點上去運算了,還有一個問題需要考慮的:alpakka-kafka提供了一個獨特的分片部署策略kafkaSharding,能實作partition與某分片在同一節點對應,這樣可以節省訊息跨節點傳遞,把訊息讀取和業務處理放到同一節點上去完成,不過對我們的案例來說,跨節點訊息傳遞與把龐大的運算均衡的分發到多個節點上去相比較就顯得微不足道了,所以,我們否定了使用kafkaSharding的想法,
這個庫存管理業務模塊應該是獨立全封閉的,那么與其它業務模塊甚至第三方軟體交流就需要按照事先約定的通訊協議進行了,最合適的標準應該是http協議了,在庫存管理模塊外表構建一層http api,提供與外界的資訊互動,這個案例的庫存管理會通過api為外界用戶提供讀、寫服務,具體作業場景如下:用戶通過任何節點上的http端點用http-request呼叫api傳遞指令(讀、寫庫存)-> api把指令寫入kafka -> consumer從kafka讀出指令傳給一個shard-entity -> shard-entity按照指令處理庫存資料 -> 通過http-response回傳處理結果,
還有一些流程細節需要厘清:業務api的http-request分兩大型別:庫存查詢(讀)和庫存更新(寫),其中庫存更新又分單向和雙向(fire-and-forget and request-response),庫存查詢不需要kafka,直接發到一個shard-entity上面去查就行了,只有庫存處理指令,因為要保證執行順序,需要先寫入kafka,然后consumer按照寫入時序讀出來交由一個shard-entity去處理,麻煩的是需要回傳結果的雙向指令,處理完業務后該如何把結果回傳正確的http-request,畢竟指令是通過kafka發過去的,如果通過kafka回傳結果,前端還需要構建consumer來接收,另一個方案是通過actor方式回傳,這需要回傳時獲取正確的actorRef,這個比較容易實作:建一個管理結果回傳請求的actor,把所有未完成請求訊息放到一個集合里,請求訊息里除提供請求者actorRef之外還必須有個文本型別的messageID,一個代表唯一的字串,具體流程如下:http接到雙向指令后分別構建包含messageID的producerRecord寫入kafka、向回傳請求管理actor發一條包含replyTo, messageID訊息 -> consumer從kafka讀取包括業務指令及messageID的訊息 -> 把包含messageID的訊息傳給業務分片shard-entity進行業務處理 -> shard-entity處理業務完畢后向回傳請求管理actor發一條包括處理結果及messageID的訊息 -> 回傳請求管理actor按照messageID從存放請求訊息的集合里找到相應的actorRef -> 向actorRef發還結果,整個流程看起來好像又長又復雜,實際用了kafka效率還是很高的,到這已經把全部技術實作各節點都過了一遍,下面我們就可以一塊一塊分步去實作了,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/270639.html
標籤:Scala
