SignalR学习笔记(五) 横向扩展之SQL Server

当一个Web应用程序达到一台服务器能力限制,即请求处理数量限制之后,有2种解决方案:纵向扩展和横向扩展。

  • 纵向扩展即用更强的服务器(或虚拟机),或为当前的服务器添加更多的内存,CPU等
  • 横向扩展即添加多台服务器或者虚拟机来做负载均衡 

纵向扩展的问题是,服务器的配置升级的费用比较高,而且总有升级的极限,很容易就再次达到限制。而横向扩展就没有这个限制,不同的用户可以被分流到不同的服务器,从而解决负载问题

 

 

 

但是这样的横向解决方案,会有一个问题,即用户被分流到不同SignalR服务器之后, 不同服务器上的用户就没有办法同步消息。

 

以一个聊天室程序为例,可能用户A,用户B被分流到服务器A, 用户C被分流到服务器B, 当用户A发送普通广播消息, 用户B因为和用户A分流到同一台服务器,所以能收到这条消息,用户C因为不在服务器A上,所以就没有办法收到这条消息。

 

底板(backplane)

 

Signal引入了一个底板的概念来解决不同服务器之间同步的问题。如果SignalR启用底板功能,每个应用实例发送消息的消息都会先传输到底板,底板会向所有连接的服务器发送同步消息,每个SignalR实例会把接收到的消息保存在内存中,然后同步给连接该实例的客户端。这样就解决了消息不同步的问题。

 

 

但是正因为有了底板机制,与单服务器SignalR应用相比,端到端通信和高并发应用的速度会减慢,同时发送的消息数量会减少,因为所有的客户端消息都是高频率的发送到SignalR服务器,SignalR服务器发送该消息到底板,底板再和所有的服务器同步消息,最在才通知到所有的连接客户端,所以对于这2种应用场景最适合还是单服务器SignalR应用。

 

底板最适合的是服务器广播,股市报价或者比赛文字直播就是最好的例子,因为所有的客户端都是被动接受消息,服务器端可以控制同时发送消息的数量。

 

SignalR默认支持的三种底板

  • Azure Service Bus
  • Redis
  • SQL Server

 

SignalR使用SQL Server做横向扩展

 

 

 

 

底板功能需要SQL Server 2005或以上版本的支持(精简版除外)。

 

配置数据库#

  1. 打开SQL Server管理器,创建新的数据库SignalR
  2. 使用一下命令检查数据库是否支持Service Broker
1
2
3
SELECT [name], [service_broker_guid], [is_broker_enabled]
 
FROM [master].[sys].[databases]



  1. 如果SignalR的is_broker_enabled标志是false, 请输入以下命令启用Service Broker
1
ALTER DATABASE YOUR_DATABASE SET ENABLE_BROKER



 

Service Broker#

Service Broker为SQL Server提供的原生的消息队列功能,启用Service Broker可以使底板更有效率的更新同步消息。但是不启用Service Broker, 底板依然可以运作。

 

创建项目#

参照学习笔记(三)的代码,创建以下解决方案

ScaleoutSqlServer, ScaleoutSqlServer2与之前学习笔记(三)SignalRSelfHost代码完全相同

ChatRoom和ChatRoom2与与之前学习笔记(三)ChatRoom的代码完全相同

 #

引入SQL Server底板支持#

打开Package Manage Console面板,输入以下命令, 分别对

 

Install-Package Microsoft.AspNet.SignalR.SqlServer

 

启用SQL Server底板#

打开ScaleoutSqlServer和ScaleoutSqlServer2工程中的Program.cs

 

ScaleoutSqlServer

 

   

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
class Program
 
    {
 
        static void Main(string[] args)
 
        {
 
            using (WebApp.Start<Startup>("http://localhost:9021"))
 
            {
 
                Console.WriteLine("Server started.");
 
                Console.Read();
 
            }
 
        }
 
    }
 
  
 
    class Startup
 
    {
 
        public void Configuration(IAppBuilder app)
 
        {
 
            // Any connection or hub wire up and configuration should go here
 
            string sqlConnectionString = "Server=.;Initial Catalog=SignalR; Integrated Security=true";
 
            GlobalHost.DependencyResolver.UseSqlServer(sqlConnectionString);
 
            app.UseCors(CorsOptions.AllowAll);
 
            app.MapSignalR();
 
        }
 
}

 

 

 

 

ScaleoutSqlServer2

 

   

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
class Program
 
    {
 
        static void Main(string[] args)
 
        {
 
            using (WebApp.Start<Startup>("http://localhost:9032"))
 
            {
 
                Console.WriteLine("Server started.");
 
                Console.Read();
 
            }
 
        }
 
    }
 
  
 
    class Startup
 
    {
 
        public void Configuration(IAppBuilder app)
 
        {
 
            // Any connection or hub wire up and configuration should go here
 
            string sqlConnectionString = "Server=.;Initial Catalog=SignalR; Integrated Security=true";
 
            GlobalHost.DependencyResolver.UseSqlServer(sqlConnectionString);
 
            app.UseCors(CorsOptions.AllowAll);
 
            app.MapSignalR();
 
        }
 
}

 

 

 

 

前台页面链接不同的SignalR服务器#

修改ChatRoom, ChatRoom2中的ChatRoom.html

 

ChatRoom

   

 

   

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<script src="Scripts/jquery.signalR-2.2.2.min.js"></script>
 
    <!--<script src="signalr/hubs"></script>-->
 
    <script src="http://localhost:9021/signalr/hubs"></script>
 
  
 
    <script type="text/javascript">
 
        $(function () {
 
  
 
            $.connection.hub.url = 'http://localhost:9021/signalr';

 

 

 

 

ChatRoom2

 

 

   

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<script src="Scripts/jquery.signalR-2.2.2.min.js"></script>
 
    <!--<script src="signalr/hubs"></script>-->
 
    <script src="http://localhost:9032/signalr/hubs"></script>
 
  
 
    <script type="text/javascript">
 
        $(function () {
 
  
 
            $.connection.hub.url = 'http://localhost:9032/signalr';

 

 

 

 

 

最终效果#

分别启动2个SignalR服务器, 并分别打开2个ChatRoom.html页面。

虽然2个Web应用程序访问的是不同的SignalR服务器,但是他们之间的消息同步了。

 

posted @   LamondLu  阅读(620)  评论(0编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
点击右上角即可分享
微信分享提示
主题色彩