SignalR原理讲解

SignalR是什么?

SignalR 是 Microsoft 开发的一个库,用于 ASP.NET 开发人员实现实时 web 功能。这意味着服务端代码可以实时地推送内容到连接的客户端,而不需要客户端定期请求或轮询服务器以获取新数据。SignalR 可以用于各种应用程序,如实时聊天、通知、实时数据更新等。

SignalR 提供了以下特点:

  1. 抽象层的连接:SignalR 提供了一种高级API,隐藏了底层实时通讯的复杂性。开发者不需要担心具体使用 WebSockets、Server-Sent Events、长轮询等,因为 SignalR 会根据客户端和服务器的能力自动选择最佳的通讯方式。

  2. 连接管理:自动处理连接、重连和断开连接的复杂性。

  3. 组播:可以广播消息到所有连接的客户端,或者只给特定的客户端或客户端组发送消息。

  4. 扩展性:支持可插拔的组件,允许开发者自定义或扩展其功能。

  5. 跨平台:除了在网页客户端上使用,还提供了客户端库支持各种平台,如 .NET、JavaScript、Java、Swift 和 Objective-C 等。

要使用 SignalR,开发者需要安装相应的 NuGet 包并按照文档中的指导进行配置和开发。

在近几年,SignalR 核心 (SignalR Core) 成为了主流,它是为 .NET Core 重新设计和实现的 SignalR 版本,提供了更好的性能和跨平台支持。

SignalR MessagePack

什么是 MessagePack?

MessagePack

是一种快速而紧凑的二进制序列化格式。 当担忧性能和带宽问题时,这很有用,因为它创建的消息比 JSON 创建的小。 查看网络跟踪和日志时,二进制消息不可读取,除非这些字节是通过 MessagePack 分析器传递的。 SignalR 为 MessagePack 格式提供内置支持,并提供 API 供客户端和服务器使用。

在服务器上配置 MessagePack

若要在服务器上启用 MessagePack 中心协议,请在应用中安装 Microsoft.AspNetCore.SignalR.Protocols.MessagePack 包。 在 Startup.ConfigureServices 方法中,将 AddMessagePackProtocol 添加到 AddSignalR 调用以在服务器上启用 MessagePack 支持。

services.AddSignalR()
.AddMessagePackProtocol();

:::info 小知识

JSON 默认启用。 添加 MessagePack 可同时支持 JSON 和 MessagePack 客户端。

:::

当启用了MessagePack,客户端会发送协议消息和版本

{"protocol":"messagepack","version":1}

后续会使用二进制传输,

:::tip 小知识

MessagePack在序列化中对比json序列化性能更好,并且体积更小,所以用于作为消息传输再合适不过了,但它不适合作为可读性的格式,所以在某些不需要可读性,需要性能的场景更合适。

:::

如何使用SignalR进行横向扩展

首先讲一下什么是横向扩展

横向扩展(Horizontally Scaling),也常称为“扩展出”或“扩展宽”,是一种增加系统容量的方法,通过在现有的硬件集群中添加更多的机器或节点来实现。与之相对的是纵向扩展(Vertically Scaling)或称为“扩展高”,它涉及增加单一机器的资源,如CPU、RAM或存储。

横向扩展的主要特点和优势:

  1. 弹性扩展:能够根据需求动态地添加或减少节点,这在云计算环境中特别受欢迎。
  2. 容错性:由于存在多个节点,即使某个节点出现故障,系统也可以继续运行。
  3. 负载分散:请求可以在多个服务器或节点之间进行分配,避免了单一节点的瓶颈。
  4. 通常更经济:与购买一个大型、昂贵的超级服务器相比,购买多台中低规格的机器往往更为经济。

总的来说,当我们的单体服务器无法支撑我们现有用户的时候,只需要在添加节点便可支持更多用户。但是横向扩展也一样会有缺点,

  1. 复杂性:管理和维护多个节点可能会比维护一个高性能的节点更加复杂。
  2. 数据一致性:在多个节点上分散数据可能导致数据同步和一致性问题。
  3. 网络开销:节点间的通信可能增加网络延迟。
  4. 软件兼容性:并不是所有软件都能轻松地进行横向扩展,某些应用可能需要特定的设计或配置。

为什么要实现横向扩展

由于一个服务器的资源是有限的,虽然说在使用的时候并没有达到硬件的上线但也存在Tcp连接数的限制,以下是官方介绍

Web 服务器可以支持的并发 TCP 连接数受到限制。 标准 HTTP 客户端使用临时连接。 这些连接可以在客户端进入空闲状态时关闭,并在以后重新打开。 另一方面,SignalR 连接是持久性的。 SignalR 连接即使在客户端进入空闲状态时也保持打开状态。 在为许多客户端提供服务的高流量应用中,这些持久性连接可能会导致服务器达到其最大连接数。

持久性连接还会占用一些额外内存来跟踪每个连接。

SignalR 大量使用连接相关资源可能会影响在同一服务器上托管的其他 Web 应用。 SignalR 打开并保持最后一个可用 TCP 连接时,同一服务器上其他 Web 应用也不再有可用连接。

如果服务器的连接用完,则你会看到随机套接字错误和连接重置错误。 例如:

复制

An attempt was made to access a socket in a way forbidden by its access permissions...

若要防止 SignalR 资源使用在其他 Web 应用中导致错误,请在与其他 Web 应用不同的服务器上运行 SignalR。

若要防止 SignalR 资源使用在 SignalR 应用中导致错误,请横向扩展以限制服务器必须处理的连接数。

Signalr是如何实现横向扩展的?

SignalR 通过一种称为“后端”或“后台”存储的机制实现横向扩展。在 SignalR 中,为了支持跨多个服务器或节点的连接和消息传递,需要一个中心的后台存储来确保消息在所有服务器之间都能正确地传递。

以下是 SignalR 实现横向扩展的几种常见方式:

  1. Redis 后端:Redis 是一个非常受欢迎的键值存储,SignalR 可以使用 Redis 作为后台存储来支持其横向扩展。当 SignalR 使用 Redis 时,所有的 SignalR 服务器都连接到同一个 Redis 实例或集群,并使用 Redis 的发布/订阅功能来传递消息。
  2. SQL Server 后端:SignalR 也支持使用 SQL Server 作为后台存储,但这种方式的性能和可扩展性可能不如 Redis。
  3. Azure Service Bus 后端:对于在 Azure 上运行的 SignalR 应用程序,Azure Service Bus 可以作为一个后台存储选项。
  4. 自定义后端存储:开发人员也可以为 SignalR 创建自定义的后端存储解决方案。

当 SignalR 使用后端存储进行横向扩展时,以下几点是需要考虑的:

  • 负载均衡:要确保所有的 SignalR 服务器之间的客户端连接请求能够均匀分配。
  • 服务器亲和性:在某些情况下,可能需要确保客户端总是连接到同一个 SignalR 服务器,这称为“服务器亲和性”或“会话亲和性”。但是,当使用后端存储如 Redis 时,这种亲和性往往不是必需的,因为所有的服务器都可以接收并广播消息。
  • 资源和成本:后端存储引入了额外的资源和成本,尤其是当使用付费服务(如 Azure Service Bus)或需要管理和维护的服务(如 Redis 或 SQL Server)时。

Redis横向扩展

SignalR 使用 Redis 作为后端存储来实现横向扩展的方式是基于 Redis 的发布/订阅 (pub/sub) 功能。这使得在多个 SignalR 服务器实例之间同步和传递消息成为可能。以下是 SignalR 如何使用 Redis 实现横向扩展的过程:

  1. 连接到 Redis:每个 SignalR 服务器实例在启动时都会与配置好的 Redis 服务器或集群建立连接。
  2. 订阅:SignalR 服务器实例使用 Redis 的发布/订阅功能进行订阅。每当有一个新的 SignalR 集群加入时,它都会订阅相关的通道,以便接收消息。
  3. 发布消息:当一个 SignalR 服务器实例需要发送消息给它的客户端时(这可能是因为一个客户端向另一个客户端发送消息,而这两个客户端可能连接到不同的服务器实例),该服务器实例会将消息发布到 Redis。
  4. 接收消息:由于所有 SignalR 服务器实例都订阅了 Redis 的通道,因此它们都会接收到该消息。收到消息的每个服务器实例都会检查该消息是否针对其上的任何客户端,如果是,则将消息转发给这些客户端。
  5. 负载均衡:在使用 Redis 进行横向扩展时,还需要一个负载均衡器来确保新的客户端连接请求在所有 SignalR 服务器实例之间进行均衡分配。这样,不同的客户端可能连接到不同的服务器实例。
  6. 持久连接和组:SignalR 的 Redis 后端不仅支持持久连接(如 Hubs)的消息传递,还支持分组操作。例如,如果你在一个服务器实例上将客户端加入一个特定的组,并且稍后想向该组发送消息,即使发送请求来自另一个服务器实例,Redis 也能确保消息正确地发送给该组的所有成员。

要使用 Redis 作为 SignalR 的后端存储,开发者需要安装相应的 SignalR Redis 包,并在应用程序的配置中指定 Redis 作为后端存储。

总的来说,通过使用 Redis 的发布/订阅功能,SignalR 能够在多个服务器实例之间同步和传递消息,从而实现横向扩展。

SqlServer横向扩展

SignalR 使用 SQL Server 作为后端来实现横向扩展主要是通过 SQL Server 的消息队列功能,特别是 SQL Server 的 Service Broker。以下是 SignalR 使用 SQL Server 进行横向扩展的基本原理:

  1. 设置 Service Broker:为了使用 SQL Server 作为 SignalR 的后端,首先需要确保 SQL Server 数据库启用了 Service Broker。
  2. 消息队列:SignalR 使用 Service Broker 提供的消息队列功能。当一个 SignalR 服务器实例需要广播消息到其他服务器实例时,它会将消息发布到 SQL Server 的一个特定队列中。
  3. 消息通知:当消息被放入队列时,Service Broker 会通知所有订阅了该队列的 SignalR 服务器实例。每个服务器实例随后可以从队列中检索并处理消息,然后将其转发给连接到该实例的客户端。
  4. 持久化:使用 SQL Server 作为后端的另一个优点是消息会持久化,这意味着即使所有的 SignalR 服务器都崩溃,消息仍然可以在系统恢复后被处理和传递。

要使用 SQL Server 作为 SignalR 的后端进行横向扩展,需要进行一些配置:

  • 安装适当的 NuGet 包,例如 Microsoft.AspNet.SignalR.SqlServer
  • 在 SignalR 的配置中,指定使用 SQL Server 作为后端并提供适当的连接字符串。
  • 确保使用的 SQL Server 数据库启用了 Service Broker。

尽管 SQL Server 可以作为 SignalR 的后端,并提供了持久化和横向扩展的能力,但使用它可能会引入一些性能考虑。例如,与内存中的解决方案(如 Redis)相比,使用 SQL Server 可能会导致更高的延迟。此外,还需要确保 SQL Server 自身具有足够的性能和资源来处理大量的 SignalR 消息流量。

EarthChat

一个基于.NET 7实现新版本QQ UI

单机支持十万人的在线Chat

技术交流群:737776595

Gitee开源:https://gitee.com/hejiale010426/chat

GitHub开源:https://github.com/239573049/chat

项目文档: https://116.196.96.91/docs/intro

提供Asp.NET Core相关知识文档讲解

EarthChat SignalR原理讲解的更多相关文章

  1. OAuth的机制原理讲解及开发流程

    本想前段时间就把自己通过QQ OAuth1.0.OAuth2.0协议进行验证而实现QQ登录的心得及Demo实例分享给大家,可一直很忙,今天抽点时间说下OAuth1.0协议原理,及讲解下QQ对于Oaut ...

  2. pureMVC简单示例及其原理讲解五(Facade)

    本节将讲述Facade,Proxy.Mediator.Command的统一管家.自定义Facade必须继承Facade,在本示例中自定义Facade名称为ApplicationFacade,这个名称也 ...

  3. pureMVC简单示例及其原理讲解四(Controller层)

    本节将讲述pureMVC示例中的Controller层. Controller层有以下文件组成: AddUserCommand.as DeleteUserCommand.as ModelPrepCom ...

  4. pureMVC简单示例及其原理讲解三(View层)

    本篇说的是View层,即视图层,在本示例中包括两个部分:MXML文件,即可视控件:Mediator. 可视控件 可视控件由UserForm.mxml(图1)和UserList.mxml(图2)两个文件 ...

  5. php 变量原理讲解

    php 变量原理讲解 一.变量概念   所谓变量,是指在程序中其值可以变化的量. 程序是管理和处理数据的.在程序运行过程中,我们需要存贮这些数据,变量和常量就是用于保存程序运行时的数据的. 变量通常由 ...

  6. ElasticSearch之 控制相关度原理讲解

    控制相关度 相关度评分背后的理论 如何计算评分的 Lucene 使用布尔模型(Boolean model) 查找匹配文档 并主要的借鉴了 词频/逆向文档频率(term frequency/invers ...

  7. MongoDB优化,建立索引实例及索引机制原理讲解

    MongoDB优化,建立索引实例及索引机制原理讲解 为什么需要索引? 当你抱怨MongoDB集合查询效率低的时候,可能你就需要考虑使用索引了,为了方便后续介绍,先科普下MongoDB里的索引机制(同样 ...

  8. 【SpringBoot】单元测试进阶实战、自定义异常处理、t部署war项目到tomcat9和启动原理讲解

    ========================4.Springboot2.0单元测试进阶实战和自定义异常处理 ============================== 1.@SpringBoot ...

  9. 马士兵hadoop第四课:Yarn和Map/Reduce配置启动和原理讲解

    马士兵hadoop第一课:虚拟机搭建和安装hadoop及启动 马士兵hadoop第二课:hdfs集群集中管理和hadoop文件操作 马士兵hadoop第三课:java开发hdfs 马士兵hadoop第 ...

  10. 马士兵hadoop第四课:Yarn和Map/Reduce配置启动和原理讲解(转)

    马士兵hadoop第一课:虚拟机搭建和安装hadoop及启动 马士兵hadoop第二课:hdfs集群集中管理和hadoop文件操作 马士兵hadoop第三课:java开发hdfs 马士兵hadoop第 ...

随机推荐

  1. 了解基于模型的元学习:Learning to Learn优化策略和Meta-Learner LSTM

    摘要:本文主要为大家讲解基于模型的元学习中的Learning to Learn优化策略和Meta-Learner LSTM. 本文分享自华为云社区<深度学习应用篇-元学习[16]:基于模型的元学 ...

  2. 前端下拉框组件CCDropDownFilter下拉框 筛选框 仿美团下拉筛选框

    快速实现下拉框 筛选框 仿美团下拉筛选框, 请访问uni-app插件市场地址:https://ext.dcloud.net.cn/plugin?id=12421 效果图如下:   # 下拉框使用方法 ...

  3. Go 语言 context 都能做什么?

    原文链接: Go 语言 context 都能做什么? 很多 Go 项目的源码,在读的过程中会发现一个很常见的参数 ctx,而且基本都是作为函数的第一个参数. 为什么要这么写呢?这个参数到底有什么用呢? ...

  4. 微信小程序常用的view、text、button、image组件

    [黑马程序员前端微信小程序开发教程,微信小程序从基础到发布全流程_企业级商城实战(含uni-app项目多端部署)] https://www.bilibili.com/video/BV1834y1676 ...

  5. Open LLM 排行榜近况

    Open LLM 排行榜是 Hugging Face 设立的一个用于评测开放大语言模型的公开榜单.最近,随着 Falcon 的发布并在 Open LLM 排行榜 上疯狂屠榜,围绕这个榜单在推特上掀起了 ...

  6. 【小小Demo】网页视频通话小🌰子

    工程名 video-call 一个简单的 音视频通话 demo,包含:视频.麦克风.屏幕共享操作. 项目环境 jdk1.8 idea maven springboot 2.1.1.RELEASE we ...

  7. Chrome 报错: Unchecked runtime.lastError: Could not establish connection. Receiving end does not exist.

    经检查,是由浏览器中的插件导致的报错. 解决方案: 将该插件移除或关闭

  8. Django2.2:UnicodeDecodeError: 'gbk' codec can't decode byte 0xa6 in position 9737: illegal multibyte sequence

    报错截图: 解决方案: 打开django/views下的debug.py文件,转到line331行: with Path(CURRENT_DIR, 'templates', 'technical_50 ...

  9. axios快速上手(简单使用)

    axios对ajax请求进行了封装,并且使用promise的链式调用使得网络请求的代码逻辑更为清晰,同时支持async和await的编写方式使代码看起来像同步,更加方便于理解和阅读.axios这个库的 ...

  10. python将print的打印内容保存到日志

    将python程序中的所有打印内容都输出到日志文件中,在程序执行完成后,方便查询程序运行过程是否出现异常. 1. 将打印内容输出到日志文件 1.1 代码实现: sys.stdout = open('s ...