我們談在效能調優時可能存在有很多不同的方面可以進行效能的最佳化,比如:良好的的編碼習慣,最大限度的發掘伺服器效能,減少下載流量等。但我們今天說的非同步和分流是在一個更大粒度下進行效能最佳化,當然非同步服務架構不僅僅是用來調優效能的、凡是需要非同步、離線、延時操作、處理高成本操作的情境都可以考慮使用非同步服務架構。
這個非同步服務架構會用到一些核心的技術:WCF 、MSMQ、IOC等,簡單介紹一下,WCF是用來在不同應用程式間進行通訊,WCF是一個很好的SOA應用的技術;MSMQ是一個佇列服務,它提供一套完整的非同步離線解決方案,這裡我們沒有直接使用MSMQ,而是通過WCF的封裝來應用,WCF的NetMsmqBinding很好的對MSMQ進行了封裝應用。IOC容器,用來支援不同應用外掛程式的開發和調用。
我們先來預覽一下非同步服務架構的幾個特點,在後續的講解中會有更加深刻的體會:
1、最佳化效能:分流高並發、高耗時、即時性不強的操作
2、易於擴充:通過部署更多的服務,以支援更多訊息流程
3、分組管理:合理分配訊息流程
4、外掛程式模式:為不同的應用開發獨立外掛程式
一、接下來看一下基礎系統架構圖,架構中還會有很多不同的服務,但是為了為了表述更為清晰,這裡就不一一列出。
#圖中可以看到所用到的必要技術:WCF、MSMQ、IOC、分組管理
#簡單的流程:用戶端-->分組管理-->調用資訊(選擇節點)+內部標識參數—>WCF(MSMQ)-->接收服務-->選擇外掛程式應用-->執行商務邏輯
#分組管理:用戶端—>SoureName-->分組管理-->分組下的服務節點列表-->選擇對應的服務節點
我們說服務可部署成很多不同的服務節點,所以用戶端在調用服務之前必須要知道自已應該調用的服務節點和通訊協定,所以用戶端會根據為自已的調用所分配置好的SourceName來從分組管理中擷取到自已對應的服務組,並從服務組的節點列表中跟據優先順序的不同選擇效能負載較好的節點和協議以備調用。invoker_groups.xml
#MSMQ:用戶端-->要處理的訊息及調用標識-->用戶端隊列—>WCF(MSMQ)-->服務端隊列-->處理……
用戶端把訊息插入用戶端隊列後,調用就完成了,這樣的操作耗時非常短,剩下的其它操作就由WCF(MSMQ)和後端的服務來完成,所以回應時間非常之快,如果是分流一個耗時的高成本操作,通過這樣的方式可以有效提高響應效能,避免線程阻塞。
如果由於網路故障不能與伺服器串連,用戶端隊列也不會掉失,直到網路故障排除後可以自動回復傳輸。
如果伺服器端的服務升級停止了服務,服務端的隊列也不會掉失,直到服務正常啟動後自動回復隊列的處理。
服務端隊列出隊的操作在WCF的處理下可以控制並發數量,通過控制並發量可以有效控制單服務節點的外理能力。
#外掛程式模式、動態調用:Source-->ServiceName,Version-->ICallService介面-->實際處理器-->處理……
Source對象中有兩個重要的參數ServiceName和Version,用來決定調用哪個ICallService介面的實現
二、用戶端用例子:通過簡單的配置便可以調用非同步服務架構中的服務。
1、引用組件:DMedia.Fetion.Framework.ServiceModel.dll, DMedia.Fetion.InvokeService.Contract.dll
2、添加配置:
<!-- localhost,online,functest –>
<add key="IServiceInvoker.RuntimeState" value="localhost" />
<add key="IServiceInvoker.ConfigurationFilePath" value="Configuration|*" />
其中:
RuntimeState 表示當前運行在哪種狀態之下,localhost表示本機調用,online表示線上生產環境,functest 表示功能測試環境
ConfigurationFilePath 表示分組設定檔的存放路徑,Configuration|* 表示優先選擇應用程式根目錄下的Configuration目錄,如果目錄下存在則就放在根目錄下,如果想再自義存放的路徑App_Data, 則可以寫成App_Data|Configuration|*
3、調用例子:
#方法一: ServiceInvokerManager.Invoke(“sourceName”, “identity”);
#方法二:ServiceInvokerManager.CreateIServiceInvoker(“sourceName”).Invoke(
Source.FromConfiguration(“sourceName”).SetClientIP("127.0.0.1"),
“identity”);
#方法三:ServiceInvokerManager.CreateIServiceInvoker(“sourceName”)
.Invoke(() => Source.FromConfiguration(“sourceName”).SetClientIP("127.0.0.1"), “identity”);
#標準方法:
IServiceInvoker iServiceInvoker = ServiceInvokerManager.CreateIServiceInvoker(“sourceName”);
if (iServiceInvoker != null)
{
Source source = Source.FromConfiguration(“sourceName”).SetClientIP("127.0.0.1");
if (source != null)
{
iServiceInvoker.Invoke(source, "abc");
}
}
三、外掛程式開發
1、實現ICallService介面
2、添加到容器ICallService.config
3、更新分組配置(invoker_groups.xml),給用戶端調用分配服務結點
四、更多服務
1、ILogService內部日誌
2、容錯服務(重試隊列和死信記錄)
3、非同步錯誤記錄檔記錄
4、非同步效能計數
5、回調服務功能(外部介面封裝)
6、……