開源地址:https://github.com/tangxuehua/enode
上一篇文章,介紹了enode框架的物理部署思路。本文我們再簡單分析一下Command Service的API設計:
Command Service在enode框架中的地位非常重要,用戶使用enode框架的主入口就是command service。UI層如controller會通過發送command給command service,然后框架就開始處理該command。不然看出,command service有可能會被高並發的訪問。那么command service該提供什么樣的API呢?
首先command service的職責是什么?是處理controller發送過來的command,那如何處理呢?大方向一般就兩種,即同步執行command和異步處理command;同步的時候,用戶希望command完全處理完才返回,中間如果遇到任何錯誤,就報異常,然后controller會捕獲該異常,然后做后續處理;一般用戶希望馬上知道command有沒有執行成功時,會用同步的方法來執行command。異步處理command,用戶只需要把command發送給command service,然后不用等待command處理完成。但是用戶可能希望知道command什么處理完成了,所以需要提供一個回調函數,通過回調函數來通知用戶某個command處理完成了,一般異步編程的風格都會有回調函數的設計。基於上面的分析,enode的ICommandService接口的設計如下:
/// <summary>Represents a service to send or execute command. /// </summary> public interface ICommandService { /// <summary>Send a command asynchronously. /// </summary> void Send(ICommand command, Action<CommandAsyncResult> callback = null); /// <summary>Execute a command synchronously. /// </summary> void Execute(ICommand command); }
代碼應該很清晰了,就不解釋了。如果我們追求最快的用戶可用性,那可以選擇異步執行command,即調用send方法;如果每次都希望command執行完才返回,則可以使用同步執行command,即execute方法;目前框架中同步執行command的實現原理其實是在異步的基礎上加了一個同步控制,
優點:
- 框架內部對command的處理流程可以完全一致了,不必因為需要同步和異步的處理而設計重復的代碼,當然,我們可以做一些抽象,以減少重復的代碼,但實際上這比較困難;
- 內部都是異步處理可以很方便的實現command的重試機制;
- 利用ManualResetEvent實現異步同步化,我們可以很方便的實現command的處理超時控制;
- 因為內部所有command的處理都是異步的,也就是所有的command都在固定的一些隊列中排隊等候處理,而隊列的消費者,即處理command的線程我們在框架啟動時就做了配置,所以訪問domain in memory的並發線程數量可控,這樣我們就可以一定程度上降低並發沖突的可能性;
缺點:
用戶調用ICommandService.Execute方法法執行某個command時,他的意圖是希望馬上執行某個command並返回結果;但是我們現在內部並不是馬上處理該command,而是先排隊,然后用ManualResetEvent卡住當前線程,然后當command處理完成后,才允許當前線程繼續往下走。當然,如果command遲遲未被執行(默認是10秒),則會自動超時,然后返回給command發起者;這樣做的壞處是當並發很高的時候,同步執行command可能會超時;對於這一點,在這篇博文中已經對如何提高系統的“高吞吐量、低延遲、高可用”做了比較詳細的思路分析,還沒看過的朋友可以去看一下。