zoukankan      html  css  js  c++  java
  • 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; 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
     
       
     
     
     
     
     
     
     
     
     
     
     
  • 相关阅读:
    计算机组成原理_存储器
    常用CMD命令
    swiper及其父级隐藏之后轮播失效问题
    canvas生成海报
    移动端h5 实现多个音频播放
    vuex的一些学习
    关于H5的一些杂思细想(一)
    vue Error: No PostCSS Config found in
    vue路由传参的三种方式区别(params,query)
    vue-cli+mock.js+axios模拟前后台数据交互
  • 原文地址:https://www.cnblogs.com/tiaoshuidenong/p/8595721.html
Copyright © 2011-2022 走看看