asp.net core 五 SignalR 負載均衡


       SignalR : Web中的實時功能實現,所謂實時功能,就是所連接的客戶端變的可用時,服務端能實時的推送內容到客戶端,而不是被動的等待客戶端的請求。Asp.net SignalR 源碼 :  https://github.com/SignalR/SignalR   .net Core下源碼地址: https://github.com/aspnet/SignalR
  asp.net core 中的實現,目前沒有正式版本的signalr出現,只有非正式版本
  1.創建asp.net core項目
  2.引用nuget包 Microsoft.AspNetCore.SignalR
  3.創建自定義Hub,我創建的為 SignalHub,繼承自Hub
     
  4.修改Startup.cs文件
     
     
     在如上的兩個方法中加入代碼
  5.編寫index.html     
    
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    你的昵稱:<span id="txt_nickName"></span><br/>
    <span>請輸入你要聊天對象的昵稱:</span><input type="text" id="txt_other"/><br/>
    <span>請輸入您要發送的消息內容:</span><input type="text" id="txt_msg"/><br/>
    <input type="button" value="發送" id="btn_send"/>
 
    <div style="position: absolute;top: 0;right: 0;width: 400px">
        <ul id="ul_recive">
        </ul>
    </div>
    <script src="jquery.min.js"></script>
    <script src="signalr.min.js"></script>
<script>
    var hubConnection = new signalR.HubConnection(`http://${document.location.host}/SignalRHub`, { transport: signalR.TransportType.WebSockets });
    $(function () {      
        var groupName = prompt('請輸入你的昵稱');
        $("#txt_nickName").text(groupName);
        hubConnection.start().then(function () {
            hubConnection.invoke('JoinGroup', groupName);
        }).catch(function(err){
            console.error(err)
        });
 
        hubConnection.on('Send', function (data) {          
            $('#ul_recive').append($('<li>').text(data));
        });
        $("#btn_send").on('click', function () {
            var reciver = $("#txt_other").val().trim();
            var msg = $("#txt_msg").val().trim();
            if (!reciver || !msg) {
                alert('請輸入接收人或消息內容');
                return;
            }
            hubConnection.invoke('Send', msg, reciver);
        });
    });
</script>
</body>
</html>
   signalr.min.js從官網連接下載即可
 
負載均衡
    SignalR在真正使用的過程中,如果業務系統為單節點還好,但是如果業務網站進行了負載均衡,情況將會變得負載,首先我理解的分為兩種解決情況,nginx負載配置進行解決,通過signalr.redis等支持的分發方式解決 ,當然這種區分是根據各自系統的業務
    我在系統開發中,業務場景是消息經過MQ會分發到各個網站后台,網站后台再通過Signalr推送到前台,普通的連接方式可能會出現消息接受不到,連接斷開的情況,針對前段頁面來說,兩個網站就是完全獨立的兩個服務器,A頁面開始連接了 A服務器,B頁面連接了B服務器,MQ消息隊列接收到消息后,通過Signalr推送,但是這時A與A服務器的連接斷開了,因為經過了負載這時A就可能已經斷開了與后端的SignalR的連接,消息也就無法正常的推送到前端,針對這種情況有以下方式處理
1.nginx負載配置
   a.首先nginx可以通過 ip_hash ,ip_hash就是固定了每個訪問者的訪問服務器,根據ip計算后就固定訪問特定的服務器   
1. upstream backend {  
2. ip_hash;  
3. server localhost:3301 max_fails=2 fail_timeout=30s ;  
4. server localhost:3302 max_fails=2 fail_timeout=30s ;  
5. server localhost:3303 max_fails=2 fail_timeout=30s ;  
6. }
   b.配置Upgrade與connection標頭,讓WebSocket保持常連接,不隨意變動訪問節點
   
   nginx配置
   
events {
    worker_connections  1024; #單個進程最大連接數(最大連接數=連接數*進程數)
}
http {
    map $http_upgrade $connection_upgrade {
        default upgrade;
        '' close;
    }
 
    upstream websocket {
        server 127.0.0.1:5000;
        server 127.0.0.1:5001;
    }
 
    server {
        listen 5002;
        server_name  127.0.0.1;
        
        location /SignalRHub {            
            proxy_pass http://websocket;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection $connection_upgrade;
        }
        location /{
            root   html;
            index  index.aspx index.html index.htm;            
            proxy_pass http://websocket;
            #設置主機頭和客戶端真實地址,以便服務器獲取客戶端真實IP
            proxy_set_header   Host             $host;
            proxy_set_header   X-Real-IP        $remote_addr;
            proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
        }
    }
}
配置兩個負載規則,針對Signalr使用socket長連接,這樣前端與后台進行SignalR WebSocket長連接之后,就不會斷開
2.通過SignalR.Redis等方式進行分發
     是不是也會存在連接斷開,如果沒有配置nginx,本質其實是websocket連接斷開,而不是消息分發的問題
     原先的項目中,復制兩份,通過Nginx負載,然后訪問連接,兩個連接的SignalR之間的消息沒有任何的交互
      訪問兩個網站,兩個網站的用戶根本無法進行互相通信
     
     
     那就有如下的代碼,通過SignalR.Redis進行分發、     
     a.項目文件中添加Nuget包引用 Pomelo.AspNetCore.SignalR.Redis
        
     b.修改原先網站的Startup文件
        
     c.其他代碼無需改動,原先的方式,復制兩份網站,兩個端口,5001,500 ,都加入到統一的組,看能否互相通信,消息是否得到分發
           
        如上圖,兩個網站的SignalR通信分發得到解決
 
     兩種方式,第一種采用的是回話保持的機制,缺點在於只是將不同用戶分配到不同節點,而並非將不同的請求分配到不同節點,粒度過大,會導致負載不夠均衡。
     針對以上方式,在我的系統中我更推薦使用第一種Nginx配置的方式,系統中已經使用了MQ進行消息的分發,而且業務中基本都是后台的數據推送前端,很少出現前端主動推送后台的情況,也就不會涉及到前端的數據需要分發到各個后台服務器,因為這種配置方式其實還是保持的前端與后端的單獨連接,前端發送的消息並沒有一個分發的過程,當然在這種設計情況下,后台的消息經過mq分發到了各個服務器,那前端的消息發送到后台后,其實也是可以經過mq分發至各個服務器的,我的系統中沒有業務的需求,也就暫時沒有實現
    第二種的方式,其實個人覺得類似我系統中的后台消息利用MQ分發到各個后台服務器,然后在通過SignalR分發一樣,只是SiganlR.Redis實現了客戶端發送的消息也會進行分發的機制,我覺得MQ也可以做到
       
    附上例子的連接:https://files.cnblogs.com/files/xiangchangdong/Common.SignalR.zip
 
   
 
 
 
 
 
 
 
 
 
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM