Azure Signalr Service Connection详解

目前的Azure SignalR Service是建立在ASP.NET Core SignalR Framework的基础上,支持Server端应用跑在ASP.NET Core SignalR 或者ASP.NET SignalR上面。下面这个图形是最为常见的SignalR 应用的架构图。

arch

这种架构是目前微软比较推荐的架构。App Server负责实现应用的逻辑。Client与Server的互动可以分为两个方面。

  1. Client与Server的互动仍然可以通过传统的HTTP请求直接发送到App Server上面。
  2. 跟SignalR相关的功能,Client和Server分别与Azure SignalR Service保持长链接,通过WebSocket交换信息。由一方将消息发送到Azure SignalR Service上,然后由Azure SignalR Service转发到其他的客户端或者Server.

这里的connection的连接方式与传统 Self-Hosting SignalR (ASP.NET Core SignalR 或者 ASP.NET SignalR) 略有不同。传统的方式中,是客户端与服务端建立长连接。而ASRS中,Client和Server分别与Azure SignalR Service保持长链接.

Connection 建立的过程

在ASRS中,Client和Server分别与Azure SignalR Service保持长链接. Azure SignalR Service SDK 为每个个Hub暴露了一个 negotiate的endpoint. 这个Endpoint 用于跟接收客户端negotiate的请求,然后把客户端的请求转接到ASRS,使得客户端可以跟ASRS建立长链接。

  1. Negotiated requests. Client端首先要跟Server端发送一个Negotiate的请求。Server端负责做Client的验证,并且回传两个重要的参数,url和accessToken
    img1

    1
    2
    3
    4
    {
    "url":"https://srchatroom.service.signalr.net/client/?hub=chat&asrs.op=%2Fchat"
    ,"accessToken":"XXXXXX"
    }
  2. 转移到ASRS上的 websocket connections. 拿到第一步的url和accessToken之后,客户端能够与ASRS建立WS的链接并且传递消息。
    img2

  3. 在WS的frame中就能看到传递的message.
    img3

Server Connection Count

我曾经注意到一个现象,当Server Application连上ASRS后,默认就有5个server connection, 即使没有任何的客户连上来的情况下。

imgconn

调查过后发现这是个默认的SignalR SDK的行为。当Server Applicaiton启动起来之后,SignalR SDK会主动的链接ASRS上。默认的情况下,一个hub会保持这5个Server Connection的链接数目。ASP.NET Core SignalR和ASP.NET SignalR会略微有点不同。Client端的连接通过ASRS与这些Server Connection中的一个建立连接。如果一个Server Connection或者一个hub的5个Server Connections掉线了,那么与之相连的所有Client Connections都会掉线。

  • 对于ASP.NET Core SignalR, Azure SignalR SDK 会为每一个hub创建 5 个 WebSocket的链接。如果只有1给hub,则是5个connection, 如果是2个hub,则是10个connection. 同样的,如果应用本身是1个hub,但是server applicaiton一同启了2个instances, 那么将会是10个connections.
  • 对于ASP.NET SignalR, Azure SignalR SDK 会为每一个hub创建 5 个 WebSocket的链接, 然后每个 server application 还会单独创建一个WebSocket链接。

每个hub有5个链接这是个默认值,通过代码可以修改这个值。参考链接看这里

1
2
3
4
5
6
7
services.AddSignalR()
.AddAzureSignalR(options =>
{
options.ConnectionCount = 10;
options.AccessTokenLifetime = TimeSpan.FromDays(1);
options.ClaimsProvider = context => context.User.Claims;
});