具有 Redis 背板的横向扩展信号服务器无法正常工作(vue 前端)

Che*_*ama 4 c# websocket signalr vue.js

感谢任何答案!

\n

我创建了一个基于 .net core 3.1 在 docker(debian) 上运行的 signalr 后端服务器。\n当我只在 kubernetes 上创建单个服务器部署时,它运行良好。\n但是当我将副本增加到超过 1 时,它运行不正确。\n它看起来是redis底板不工作,导致多台服务器之间通讯不通。

\n

按照官方文档,我安装了nuget包:

\n
<PackageReference Include="Microsoft.AspNetCore.SignalR.StackExchangeRedis" Version="3.1.13" />\n
Run Code Online (Sandbox Code Playgroud)\n

这是后端服务器startup.cs代码:

\n
public void ConfigureServices(IServiceCollection services)\n{\n// ...\n  services\n    .AddSignalR(option =>\n    {\n        option.EnableDetailedErrors = true;\n    })\n    .AddNewtonsoftJsonProtocol()\n    .AddStackExchangeRedis(option =>\n    {\n    option.ConnectionFactory = async writer =>\n    {\n        var config = new ConfigurationOptions\n        {\n            AbortOnConnectFail = false,\n            ChannelPrefix = "devopshub",\n            ServiceName = "devopshub",\n            ClientName = "devopshub"\n        };\n        config.DefaultDatabase = 13;\n        var connection = await ConnectionMultiplexer.ConnectAsync("redis host:6379,allowAdmin=true,defaultdatabase=13", writer);\n        connection.ConnectionFailed += (_, e) =>\n        {\n            Console.WriteLine("SignalR Redis Server Connection Failed.");\n        };\n        if (connection.IsConnected)\n            Console.WriteLine("SignalR Redis Server Connected.");\n        else\n            Console.WriteLine("SignalR Redis Server Not Connected.");\n        return connection;\n    };\n// ... \n}\n\npublic void Configure(IApplicationBuilder app, IWebHostEnvironment env)\n{\n// ...\n    app.UseRouting();\n    app.UseCors(builder => builder\n    .SetIsOriginAllowed(_ => true)\n    .AllowAnyMethod()\n    .AllowAnyHeader()\n    .AllowCredentials());\n    app.UseEndpoints(builder =>\n    {\n        builder.MapHub<LogHub>("/api/loghub").RequireCors(t => t.SetIsOriginAllowed(_ => true).AllowAnyMethod().AllowAnyHeader().AllowCredentials());\n        builder.MapHub<ProcessDetailStatusSyncHub>("/api/processdetailstatussynchub").RequireCors(t => t.SetIsOriginAllowed(_ => true).AllowAnyMethod().AllowAnyHeader().AllowCredentials());\n        builder.MapControllers();\n        builder.MapHealthChecks("/health");\n    });\n// ...\n}\n\n
Run Code Online (Sandbox Code Playgroud)\n

所有代码似乎都正常,并且当服务器部署为单一时,它确实可以正常工作。一旦我添加副本,websocket 连接将立即或几秒钟后重置或断开连接。\n之后,前端(vue)项目将抛出取消处理错误,然后就会崩溃。

\n

像这样:

\n
Error: read ECONNRESET\n    at TCP.onStreamRead (internal/stream_base_commons.js:205:27)\nEmitted 'error' event on Socket instance at:\n    at emitErrorNT (internal/streams/destroy.js:92:8)\n    at emitErrorAndCloseNT (internal/streams/destroy.js:60:3)\n    at processTicksAndRejections (internal/process/task_queues.js:84:21) {\n  errno: 'ECONNRESET',\n  code: 'ECONNRESET',\n  syscall: 'read'\n}\nnpm ERR! code ELIFECYCLE\nnpm ERR! errno 1\nnpm ERR! frontendProjectName@0.0.1 dev: `vue-cli-service serve`\nnpm ERR! Exit status 1\nnpm ERR!\nnpm ERR! Failed at the frontendProjectName@0.0.1 dev script.\nnpm ERR! This is probably not a problem with npm. There is likely additional logging output above.\n\nnpm ERR! A complete log of this run can be found in:\nnpm ERR!     C:\\Users\\ASUS\\AppData\\Roaming\\npm-cache\\_logs\\2021-03-18T03_13_05_435Z-debug.log\n\xe7\xbb\x88\xe7\xab\xaf\xe8\xbf\x9b\xe7\xa8\x8b\xe2\x80\x9cC:\\WINDOWS\\System32\\WindowsPowerShell\\v1.0\\powershell.exe -Command npm run dev\xe2\x80\x9d\xe5\xb7\xb2\xe7\xbb\x88\xe6\xad\xa2\xef\xbc\x8c\xe9\x80\x80\xe5\x87\xba\xe4\xbb\xa3\xe7\xa0\x81: 1\xe3\x80\x82\n
Run Code Online (Sandbox Code Playgroud)\n

最后一行中文意思是“进程停止,退出代码1”

\n

这是日志文件内容:

\n
0 info it worked if it ends with ok\n1 verbose cli [\n1 verbose cli   'D:\\\\nodejs\\\\node.exe',\n1 verbose cli   'D:\\\\nodejs\\\\node_modules\\\\npm\\\\bin\\\\npm-cli.js',\n1 verbose cli   'run',\n1 verbose cli   'dev'\n1 verbose cli ]\n2 info using npm@6.13.4\n3 info using node@v12.16.1\n4 verbose run-script [ 'predev', 'dev', 'postdev' ]\n5 info lifecycle frontendProjectName@0.0.1~predev: frontendProjectName@0.0.1\n6 info lifecycle frontendProjectName@0.0.1~dev: frontendProjectName@0.0.1\n7 verbose lifecycle frontendProjectName@0.0.1~dev: unsafe-perm in lifecycle true\n8 verbose lifecycle frontendProjectName@0.0.1~dev: PATH: D:\\nodejs\\node_modules\\npm\\node_modules\\npm-lifecycle\\node-gyp-bin;E:\\workspace\\CICD\\hualv-devops-frontend\\node_modules\\.bin;C:\\Users\\ASUS\\AppData\\Roaming\\npm;C:\\ProgramData\\DockerDesktop\\version-bin;C:\\Program Files\\Docker\\Docker\\Resources\\bin;C:\\Python27\\;C:\\Python27\\Scripts;C:\\WINDOWS\\system32;C:\\WINDOWS;C:\\WINDOWS\\System32\\Wbem;C:\\WINDOWS\\System32\\WindowsPowerShell\\v1.0\\;C:\\Program Files\\dotnet\\;C:\\Program Files (x86)\\Microsoft SQL Server\\140\\Tools\\Binn\\;C:\\Program Files (x86)\\Microsoft SQL Server\\140\\DTS\\Binn\\;D:\\Program Files\\platform-tools;C:\\WINDOWS\\System32\\OpenSSH\\;C:\\Program Files\\Microsoft SQL Server\\140\\Tools\\Binn\\;C:\\Program Files\\Microsoft SQL Server\\140\\DTS\\Binn\\;C:\\Program Files\\Microsoft SQL Server\\Client SDK\\ODBC\\130\\Tools\\Binn\\;C:\\Program Files (x86)\\Microsoft SQL Server\\Client SDK\\ODBC\\130\\Tools\\Binn\\;C:\\Program Files (x86)\\Microsoft SQL Server\\140\\Tools\\Binn\\ManagementStudio\\;C:\\Program Files\\Microsoft\\Web Platform Installer\\;C:\\Program Files\\Microsoft SQL Server\\130\\Tools\\Binn\\;C:\\Program Files\\Git\\cmd;C:\\Program Files\\TortoiseGit\\bin;D:\\nodejs\\;C:\\Program Files (x86)\\ATI Technologies\\ATI.ACE\\Core-Static;C:\\Program Files\\Microsoft SQL Server\\Client SDK\\ODBC\\170\\Tools\\Binn\\;E:\\Nuget;C:\\Users\\ASUS\\AppData\\Roaming\\npm;C:\\Users\\ASUS\\AppData\\Local\\Microsoft\\WindowsApps;D:\\Program Files\\Fiddler;D:\\Docker Toolbox;C:\\Users\\ASUS\\.dotnet\\tools;D:\\JetBrains Rider\\bin;;D:\\Microsoft VS Code\\bin;E:\\Nuget;C:\\Users\\ASUS\\AppData\\Local\\Programs\\Fiddler;C:\\Users\\ASUS\\AppData\\Local\\Microsoft\\WindowsApps;D:\\JetBrains Rider 2020.3.2\\bin;\n9 verbose lifecycle frontendProjectName@0.0.1~dev: CWD: E:\\workspace\\CICD\\hualv-devops-frontend\n10 silly lifecycle frontendProjectName@0.0.1~dev: Args: [ '/d /s /c', 'vue-cli-service serve' ]\n11 silly lifecycle frontendProjectName@0.0.1~dev: Returned: code: 1  signal: null\n12 info lifecycle frontendProjectName@0.0.1~dev: Failed to exec dev script\n13 verbose stack Error: frontendProjectName@0.0.1 dev: `vue-cli-service serve`\n13 verbose stack Exit status 1\n13 verbose stack     at EventEmitter.<anonymous> (D:\\nodejs\\node_modules\\npm\\node_modules\\npm-lifecycle\\index.js:332:16)\n13 verbose stack     at EventEmitter.emit (events.js:311:20)\n13 verbose stack     at ChildProcess.<anonymous> (D:\\nodejs\\node_modules\\npm\\node_modules\\npm-lifecycle\\lib\\spawn.js:55:14)\n13 verbose stack     at ChildProcess.emit (events.js:311:20)\n13 verbose stack     at maybeClose (internal/child_process.js:1021:16)\n13 verbose stack     at Process.ChildProcess._handle.onexit (internal/child_process.js:286:5)\n14 verbose pkgid frontendProjectName@0.0.1\n15 verbose cwd E:\\workspace\\CICD\\hualv-devops-frontend\n16 verbose Windows_NT 10.0.19041\n17 verbose argv "D:\\\\nodejs\\\\node.exe" "D:\\\\nodejs\\\\node_modules\\\\npm\\\\bin\\\\npm-cli.js" "run" "dev"\n18 verbose node v12.16.1\n19 verbose npm  v6.13.4\n20 error code ELIFECYCLE\n21 error errno 1\n22 error frontendProjectName@0.0.1 dev: `vue-cli-service serve`\n22 error Exit status 1\n23 error Failed at the frontendProjectName@0.0.1 dev script.\n23 error This is probably not a problem with npm. There is likely additional logging output above.\n24 verbose exit [ 1, true ]\n\n
Run Code Online (Sandbox Code Playgroud)\n

服务器控制台记录如下内容:

\n
Socket connection closed prematurely.\nSystem.Net.WebSockets.WebSocketException (0x80004005): The remote party closed the WebSocket connection without completing the close handshake.\n ---> System.Net.WebSockets.WebSocketException (0x80004005): The remote party closed the WebSocket connection without completing the close handshake.\n   at System.Net.WebSockets.ManagedWebSocket.ThrowIfEOFUnexpected(Boolean throwOnPrematureClosure)\n   at System.Net.WebSockets.ManagedWebSocket.EnsureBufferContainsAsync(Int32 minimumRequiredBytes, CancellationToken cancellationToken, Boolean throwOnPrematureClosure)\n   at System.Net.WebSockets.ManagedWebSocket.ReceiveAsyncPrivate[TWebSocketReceiveResultGetter,TWebSocketReceiveResult](Memory`1 payloadBuffer, CancellationToken cancellationToken, TWebSocketReceiveResultGetter resultGetter)\n   at System.Net.WebSockets.ManagedWebSocket.ReceiveAsyncPrivate[TWebSocketReceiveResultGetter,TWebSocketReceiveResult](Memory`1 payloadBuffer, CancellationToken cancellationToken, TWebSocketReceiveResultGetter resultGetter)\n   at Microsoft.AspNetCore.Http.Connections.Internal.Transports.WebSocketsServerTransport.StartReceiving(WebSocket socket)\n
Run Code Online (Sandbox Code Playgroud)\n

Che*_*ama 5

好吧,都是我的错。再次仔细阅读官方文档后,我找到了原因。我忽略了最后一点:

配置服务器场负载平衡软件以实现粘性会话。

我的情况的解决方案是配置 nginx ingress 以启用Sticky Session,如下所示:

    nginx.ingress.kubernetes.io/affinity: cookie
    nginx.ingress.kubernetes.io/affinity-mode: balanced
    nginx.ingress.kubernetes.io/session-cookie-expires: "86400"
    nginx.ingress.kubernetes.io/session-cookie-max-age: "86400"
Run Code Online (Sandbox Code Playgroud)

将上面的配置添加到ingress yaml 中的metadata:annotations节点

  • 感谢大家看到这个问题。 (2认同)