SignalR的通信方式決定了其高性能,可是即使如此,當消息的併發量上來之後,單節點的Hub服務器依然可能沒法承載總的消息吞吐量,那麼如何對Hub服務器作水平擴展呢?服務器
從微軟官方的文檔上看,SignalR是具備消息底板功能的,SignalR核心組件公開了一個IMessageBus的接口,只須要實現該接口,就能實現消息訂閱功能。官網提供了3種解決方案:Azure、Redis、SqlServer,nuget平臺上有更多的基於消息隊列的第三方底板。本篇以Redis爲例子展現一下以消息底板模式運做的Hub服務器。併發
服務端app
public class Startup { public void Configuration(IAppBuilder app) { GlobalHost.DependencyResolver.UseRedis("192.168.1.66", 6379, string.Empty, "SignalRBus"); app.Map("/signalr", map => { map.UseCors(CorsOptions.AllowAll); var hubConfiguration = new HubConfiguration { EnableJSONP = true }; map.RunSignalR(hubConfiguration); }); } }
在啓動類中,經過DependencyResolver的擴展方法來註冊基於Redis的MessageBus,其中前2個參數是地址和端口,第三個參數爲Redis服務器的密碼,消息訂閱的名稱。性能
public class ChatHub : Hub { public void Chat(string msg) { Clients.All.Display("Receive Msg:" + msg); } }
創建一個簡單的Hub,只提供一個Chat的方法,內部實現廣播。ui
static void Main(string[] args) { using (WebApp.Start<Startup>("http://*:8001/")) { Console.WriteLine("Server running at http://localhost:8001/"); Console.ReadLine(); } }
static void Main(string[] args) { using (WebApp.Start<Startup>("http://*:8002/")) { Console.WriteLine("Server running at http://localhost:8002/"); Console.ReadLine(); } }
創建2個啓動項,端口號分別爲8001和8002,用以啓動2個hub的實例。spa
客戶端code
static void Main(string[] args) { var hubConn = new HubConnection("http://localhost:8001"); var proxy = hubConn.CreateHubProxy("ChatHub"); hubConn.Start().Wait(); while (true) { var guid = Guid.NewGuid().ToString(); Console.WriteLine("Send Msg:" + guid); proxy.Invoke("Chat", guid).Wait(); Thread.Sleep(2000); } }
客戶端1鏈接上8001,利用一個循環不斷的往服務端發guid。blog
static void Main(string[] args) { var hubConn = new HubConnection("http://localhost:8002"); var proxy = hubConn.CreateHubProxy("ChatHub"); proxy.On<string>("Display", (msg) => { Console.WriteLine(msg); }); hubConn.Start().Wait(); Console.ReadLine(); }
客戶端2鏈接上8002,註冊一個Display的方法,用於接收服務端推送的消息。接口
運行狀況隊列
圖中可知,client1的send msg,被client2接受到了。