.NET 大牛们,这次遇到了一个涉及知识盲区的 BUG,与 Redis 有关

9 天前
 maymay5
fail: Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware[1]
      An unhandled exception has occurred while executing the request.
      StackExchange.Redis.RedisCommandException: Command cannot be issued to a replica: DEL cache_4f4bc6e0-4278-d758-4312-3be96b11d34e
         at StackExchange.Redis.ConnectionMultiplexer.PrepareToPushMessageToBridge[T](Message message, ResultProcessor`1 processor, IResultBox`1 resultBox, ServerEndPoint& server) in /_/src/StackExchange.Redis/ConnectionMultiplexer.cs:line 1967
         at StackExchange.Redis.ConnectionMultiplexer.TryPushMessageToBridgeAsync[T](Message message, ResultProcessor`1 processor, IResultBox`1 resultBox, ServerEndPoint& server) in /_/src/StackExchange.Redis/ConnectionMultiplexer.cs:line 2013
         at StackExchange.Redis.ConnectionMultiplexer.ExecuteAsyncImpl[T](Message message, ResultProcessor`1 processor, Object state, ServerEndPoint server) in /_/src/StackExchange.Redis/ConnectionMultiplexer.cs:line 2191
         at StackExchange.Redis.RedisBase.ExecuteAsync[T](Message message, ResultProcessor`1 processor, ServerEndPoint server) in /_/src/StackExchange.Redis/RedisBase.cs:line 54
         at StackExchange.Redis.RedisDatabase.KeyDeleteAsync(RedisKey key, CommandFlags flags) in /_/src/StackExchange.Redis/RedisDatabase.cs:line 758
         at aibotPro.Service.RedisService.DeleteAsync(String key) in /Users/mayday/Desktop/GitHub/AIBot-Pro/AIBot-Pro/aibotPro/aibotPro/Service/RedisService.cs:line 75
         at aibotPro.Service.UsersService.GenerateCodeImage(String account, String key) in /Users/mayday/Desktop/GitHub/AIBot-Pro/AIBot-Pro/aibotPro/aibotPro/Service/UsersService.cs:line 151
         at aibotPro.Controllers.UsersController.GenerateCodeImage(String key) in /Users/mayday/Desktop/GitHub/AIBot-Pro/AIBot-Pro/aibotPro/aibotPro/Controllers/UsersController.cs:line 388
         at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
      --- End of stack trace from previous location ---
         at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|25_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync()
      --- End of stack trace from previous location ---
         at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
         at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
         at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
         at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.<Invoke>g__Awaited|6_0(ExceptionHandlerMiddleware middleware, HttpContext context, Task task)
fail: Microsoft.AspNetCore.Mvc.ViewFeatures.ViewResultExecutor[3]
      The view 'Error' was not found. Searched locations: /Views/Home/Error.cshtml, /Views/Shared/Error.cshtml
fail: Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware[3]
      An exception was thrown attempting to execute the error handler.
      System.InvalidOperationException: The view 'Error' was not found. The following locations were searched:
      /Views/Home/Error.cshtml
      /Views/Shared/Error.cshtml
         at Microsoft.AspNetCore.Mvc.ViewEngines.ViewEngineResult.EnsureSuccessful(IEnumerable`1 originalLocations)
         at Microsoft.AspNetCore.Mvc.ViewFeatures.ViewResultExecutor.ExecuteAsync(ActionContext context, ViewResult result)
         at Microsoft.AspNetCore.Mvc.ViewResult.ExecuteResultAsync(ActionContext context)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResultFilterAsync>g__Awaited|30_0[TFilter,TFilterAsync](ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResultExecutedContextSealed context)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext[TFilter,TFilterAsync](State& next, Scope& scope, Object& state, Boolean& isCompleted)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeResultFilters()
      --- End of stack trace from previous location ---
         at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|25_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync()
      --- End of stack trace from previous location ---
         at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
         at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
         at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
         at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.HandleException(HttpContext context, ExceptionDispatchInfo edi)

1023 次点击
所在节点    .NET
5 条回复
kk2syc
9 天前
根据报错 < StackExchange.Redis.RedisCommandException: Command cannot be issued to a replica: DEL cache_4f4bc6e0-4278-d758-4312-3be96b11d34e > 来看
你如果是定义一个实例的时候同时连接 db1 和 db5 的话,组件会默认把 db5 当作 [只读缓存] 副本,通常副本是不允许写入操作的,于是报错了。
----

1. 你应该定义两个 redis 实例并以单例形式添加到服务中:
```
public static IServiceCollection AddStackExchangeRedis(this IServiceCollection services, IConfiguration configuration)
{
ConfigurationOptions options1 = new ConfigurationOptions()
{
EndPoints = {
{Address1, Port1 }
},
Password = Password1,
ClientName = Name1,
DefaultDatabase = DefaultDatabaseNumber1,
AllowAdmin = true
};

ConfigurationOptions options2 = new ConfigurationOptions()
{
EndPoints = {
{ Address2, Port2 }
},
Password = Password2,
ClientName = Name2,
DefaultDatabase = DefaultDatabaseNumber2,
AllowAdmin = true
};
services.AddSingleton<IConnectionMultiplexer>(ConnectionMultiplexer.Connect(options1));
services.AddSingleton<IConnectionMultiplexer>(ConnectionMultiplexer.Connect(options2));
return services;
}
```

2. 使用 IEnumerable 选择对 ClientName ( Name1 或 Name2 )进行查询的任何 redis 实例:
```
public class YourClass
{
private readonly IConnectionMultiplexer _connectionMultiplexer;

public YourClass(IEnumerable<IConnectionMultiplexer> connectionMultiplexer)
{
_connectionMultiplexer= connectionMultiplexer.Where(c => c.ClientName == Name1).First();
}
}
```
maymay5
9 天前
@kk2syc 大佬,场景好像不同,我并不是一个实例连接两个 db ,db1 和 db5 ,完全不是同一个项目,他们是分开部署的两个网站,进程都不是同一个,很奇怪
kk2syc
9 天前
@maymay5 那把两个 webapi 相关 redis 操作时候的各个数据都打 log ,看看会不会有参数为空、类型错误等等,造成死循环挤满 redis 连接了?主要是不理解你描述的。假如你的两个 webapi 不共用 db1 和 db5 的数据,那么 db1 、5 是数据独立的,不存在 db5 的业务挂了影响 db1 的业务。清除 db5 就恢复肯定指向 redis 因为什么卡了
wuhuiwenzi
9 天前
furion 做的??我遇到过,要定义两个 redis 实例。。类似这种
_redisConnZK = new FullRedis();
_redisConnDS = new FullRedis();
_redisConnZK.Init(cacheOptions.RedisConnectionStringZK);
_redisConnDS.Init(cacheOptions.RedisConnectionStringDS);
maymay5
9 天前
@wuhuiwenzi 谢谢解答,我现在怀疑是 StackExchange.Redis 库的一个 bug ,因为我两个 db 完全不在同一个进程中,但事实就是我一个进程中的 db5 挂了(也不能说挂了,因为我用客户端工具依旧可以增删改查,就是程序里用不了),另一个使用 db1 的进程也挂了

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1072092

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX