Signalr-Redis "No Connection with that ID"
Signalr-Redis "No Connection with that ID"
背景
我有一个部署在 Google 云上的网站。本网站使用 asp.net 核心 (v2.2) 和 signalr 编写。
我的应用程序架构是我有两台机器,运行ning Linux,服务于同一个站点。该站点由 Kastrel(本地主机)提供服务并由 nginx 包装(用于外部网络)。我有云负载平衡器,它在这两个实例之间分配流量。 LB 定义为按会话亲和性拆分流量。
我将 SignalR 定义为使用 Redis,以便在多实例环境中正常工作。
我的startup.cs
代码:
var redisCs = ConfigurationOptions.Parse("REDIS CS");
services.AddSignalR().AddRedis(options =>
{
options.ConnectionFactory = async writer =>
{
var connection = await ConnectionMultiplexer.ConnectAsync(redisCs, writer);
return connection;
};
options.Configuration.ClientName = "Main-website-Signalr";
});
问题
当我测试它时,有时它能正常工作,而有时却不行。
当它失败时,我在浏览器控制台上看到这个日志:
WebSocket connection to 'wss://mysite.com/hubs/myhub?id=R_Zmaew-lRN_r2d_c-xOyg' failed: Error during WebSocket handshake: Unexpected response code: 404
在我的浏览器 "Network" 选项卡上,我看到浏览器尝试与地址 wss://mysite.com/hubs/myhub?id=R_Zmaew-lRN_r2d_c-xOyg
通信并获得 404 响应。
我的调查
我担心 nginx 以某种方式阻止连接,所以我决定在没有任何中介的情况下与 Kestrel 连接。我通过 ssh 进入机器并 运行 这个命令:
$ curl 127.0.0.1:5000/hubs/businesses?id=Tta4PmrjMrzHBHa8CT0SPQ -v
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to 127.0.0.1 (127.0.0.1) port 5000 (#0)
> GET /hubs/myhub?id=Tta4PmrjMrzHBHa8CT0SPQ HTTP/1.1
> Host: 127.0.0.1:5000
> User-Agent: curl/7.52.1
> Accept: */*
>
< HTTP/1.1 404 Not Found
< Date: Wed, 05 Jun 2019 06:26:09 GMT
< Content-Type: text/plain
< Transfer-Encoding: chunked
<
* Curl_http_done: called premature == 0
* Connection #0 to host 127.0.0.1 left intact
No Connection with that ID
所以,我遇到了 404 错误 - 就像我从浏览器上得到的一样。我想现在没有人以某种方式阻止连接。它只是 SignalR 配置的某些东西被破坏了。
为什么SignalR能找到连接?
我登录的是哪台机器有关系吗?连接不是通过 Redis 以某种方式传递的吗?
当您在单个 load-balancer 后面有多个服务器实例时,您需要启用粘性会话,这意味着唯一的客户端将永远只连接到一台机器。
您可以在 https://docs.microsoft.com/en-us/aspnet/core/signalr/scale?view=aspnetcore-2.2#redis-backplane
中查看有关 Redis 背板的一些信息
SignalR 是一种协议,该协议的一部分意味着将在 "negotiate" 期间在服务器上创建连接 ID。这意味着您不能随机地使用 ID 卷曲端点,因为卷曲不理解 SignalR 协议。
如果您对该协议感兴趣,可以阅读 https://github.com/aspnet/AspNetCore/tree/master/src/SignalR/docs/specs
背景
我有一个部署在 Google 云上的网站。本网站使用 asp.net 核心 (v2.2) 和 signalr 编写。
我的应用程序架构是我有两台机器,运行ning Linux,服务于同一个站点。该站点由 Kastrel(本地主机)提供服务并由 nginx 包装(用于外部网络)。我有云负载平衡器,它在这两个实例之间分配流量。 LB 定义为按会话亲和性拆分流量。
我将 SignalR 定义为使用 Redis,以便在多实例环境中正常工作。
我的startup.cs
代码:
var redisCs = ConfigurationOptions.Parse("REDIS CS");
services.AddSignalR().AddRedis(options =>
{
options.ConnectionFactory = async writer =>
{
var connection = await ConnectionMultiplexer.ConnectAsync(redisCs, writer);
return connection;
};
options.Configuration.ClientName = "Main-website-Signalr";
});
问题
当我测试它时,有时它能正常工作,而有时却不行。
当它失败时,我在浏览器控制台上看到这个日志:
WebSocket connection to 'wss://mysite.com/hubs/myhub?id=R_Zmaew-lRN_r2d_c-xOyg' failed: Error during WebSocket handshake: Unexpected response code: 404
在我的浏览器 "Network" 选项卡上,我看到浏览器尝试与地址 wss://mysite.com/hubs/myhub?id=R_Zmaew-lRN_r2d_c-xOyg
通信并获得 404 响应。
我的调查
我担心 nginx 以某种方式阻止连接,所以我决定在没有任何中介的情况下与 Kestrel 连接。我通过 ssh 进入机器并 运行 这个命令:
$ curl 127.0.0.1:5000/hubs/businesses?id=Tta4PmrjMrzHBHa8CT0SPQ -v
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to 127.0.0.1 (127.0.0.1) port 5000 (#0)
> GET /hubs/myhub?id=Tta4PmrjMrzHBHa8CT0SPQ HTTP/1.1
> Host: 127.0.0.1:5000
> User-Agent: curl/7.52.1
> Accept: */*
>
< HTTP/1.1 404 Not Found
< Date: Wed, 05 Jun 2019 06:26:09 GMT
< Content-Type: text/plain
< Transfer-Encoding: chunked
<
* Curl_http_done: called premature == 0
* Connection #0 to host 127.0.0.1 left intact
No Connection with that ID
所以,我遇到了 404 错误 - 就像我从浏览器上得到的一样。我想现在没有人以某种方式阻止连接。它只是 SignalR 配置的某些东西被破坏了。
为什么SignalR能找到连接?
我登录的是哪台机器有关系吗?连接不是通过 Redis 以某种方式传递的吗?
当您在单个 load-balancer 后面有多个服务器实例时,您需要启用粘性会话,这意味着唯一的客户端将永远只连接到一台机器。
您可以在 https://docs.microsoft.com/en-us/aspnet/core/signalr/scale?view=aspnetcore-2.2#redis-backplane
中查看有关 Redis 背板的一些信息SignalR 是一种协议,该协议的一部分意味着将在 "negotiate" 期间在服务器上创建连接 ID。这意味着您不能随机地使用 ID 卷曲端点,因为卷曲不理解 SignalR 协议。
如果您对该协议感兴趣,可以阅读 https://github.com/aspnet/AspNetCore/tree/master/src/SignalR/docs/specs