SignalR+Redis做橫向擴展(集羣)

問題背景:當SignalR應用部署在一臺服務器的時候,隨着用戶量的增加,服務器的承載能力肯定會達到瓶頸,這時候就需要考慮多部署幾臺服務器來緩解壓力

解決辦法:多臺服務器部署SignalR應用,一臺服務器部署Redis服務

如上圖,一臺SignalR服務器對應一個用戶羣,SignalR應用服務器和Redis服務器之間採用發佈-訂閱模式。當用戶羣1的用戶向用戶羣2的用戶發送消息的時候,消息先到達SignalR應用服務器1,SignalR1服務器向Redis服務器發佈消息,其他服務器訂閱了Redis服務器的消息,會接受到SignalR服務器1的消息,SignalR服務器2發現是自己用戶消息,因此接受消息並將消息發送給用戶羣2裏面的用戶

實現:

在vs2017新建一個web應用,在nuget上安裝Microsoft.AspNetCore.SignalR.Redis 和Microsoft.AspNetCore.SignalR.StackExchangeRedis兩個應用組件

在Start.cs代碼文件裏面新增SignalR服務並配置Redis服務

services.AddSignalR()
                .AddRedis("127.0.0.1:6379", opitons =>
            {
                opitons.Configuration.ChannelPrefix = "myapp2";  //同一個SignalR應用配置相同的Redis頻道前綴(應爲要訂閱相同頻道的Redis消息)
            })
            ;

編寫Hub

 public class ChatHubs : Hub
    {
        public override Task OnConnectedAsync()
        {
            Clients.Client(this.Context.ConnectionId).SendAsync("ReceiveConnectionID", this.Context.ConnectionId);
            return base.OnConnectedAsync();
        }

        public override Task OnDisconnectedAsync(Exception exception)
        {
            return base.OnDisconnectedAsync(exception);
        }

        public async Task SendMessage(string connectionID,string user, string message)  //給某一個人發送消息
        {
            //await Clients.All.SendAsync("ReceiveMessage", user, message);            
            await Clients.Client(connectionID).SendAsync("ReceiveMessage", user, message);
        }
        
    }

發佈應用到兩個文件夾,使用dotnet命令分別運行兩個應用將網站跑起來,兩個網站分別綁定到不同的端口,比如我這裏分別綁定到5001和5002兩個端口

在5001這個端口下面的應用的ConnectionID填寫5002端口下面的那個ConnectionID值,這樣就可以實現5001端口應用向5002端口應用發送消息

這樣只要知道需要接受消息的那個人的ConnectionID,就可以向那個人發送消息,即便這收發消息的兩個人不是連在同一個服務器上也可以進行通信

這裏只是講講自己對SignrR+Redis方面的擴展的理解,真正的擴展還需要考慮用戶和SignalR服務器的之間轉發問題,因爲用戶和SignalR服務器之間是通過ConnectionID關聯的,所以當有多個服務器的時候,就需要考慮怎麼保持ConnectionID和服務器的對應關係,這裏可以使用Nginx實現用戶分發問題,利用Nginx的ip綁定策略實現ip固定訪問服務器的功能。

這裏附上通過ip綁定策略配置Nginx負載配置

修改Nginx配置文件nginx.conf

upstream myweb{ 
        ip_hash;
        server localhost:5001; 
        server localhost:5002; 
        keepalive 1000; 
    }

server {
        listen       81;
        server_name  localhost;
        location / {
            #root   html;
            index  index.html index.htm;
            proxy_pass http://myweb;
            #Nginx配置websocket
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";    
        }
    }

這樣在瀏覽器訪問 http://localhost:81地址,同一個ip用戶請求將只會被轉發到一臺固定的服務器

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章