0

我有一个 ServiceStack.Redis 多线程冲突。我有一种 ServiceStack 的非标准用例,我在一个“FallbackRoute”中捕获所有路由。这意味着该一条路线有一项服务。这是 DTO:

[FallbackRoute("/{Path*}")]
public class S3Request  : IRequiresRequestStream{ 
  public string Path{ get; set; }
  public Stream RequestStream { get; set; }
}

该服务是:

public class S3Service : Service
{
    public RedisUsersCredentials RedisUsersCredentials { get; set; }
    // S3 Request Mutual Exclusion Objects:
    static readonly object syncBucket = new object();
    static readonly object syncObject = new object();

public object Get(S3Request request){
  IRedisClient Redis = RedisUsersCredentials.RedisClient;
  // Do a bunch of stuff with Redis
}

public object Put(S3Request request){
  IRedisClient Redis = RedisUsersCredentials.RedisClient;
  // Do a bunch of stuff with Redis
}

然后在配置块中的 AppHost.cs 中,我自动装配了 redis:

container.Register<ServiceStack.Redis.IRedisClientsManager>(c =>
    new ServiceStack.Redis.BasicRedisClientManager("localhost:6379"));

    container.RegisterAutoWired<RedisUsersCredentials>();

我从有关如何正确使用带多线程的 BasicRedisClientManager 的帖子中得到了这个。但我得到如下例外:

multi-request: 581, sPort: 40900, LastCommand: SMEMBERS            TenantOwnerSet:s3devel</Message><StackTrace>[S3Request: 4/1/2015 6:36:50 PM]:
[REQUEST: {}]
ServiceStack.Redis.RedisResponseException: Unknown reply on multi-request:     581, sPort: 40900, LastCommand: SMEMBERS TenantOwnerSet:s3devel
at ServiceStack.Redis.RedisNativeClient.CreateResponseError (string) &lt;IL     0x0003a, 0x00153&gt;
at ServiceStack.Redis.RedisNativeClient.ReadMultiData () &lt;IL 0x000e5,     0x0060f&gt;
at ServiceStack.Redis.RedisNativeClient.SendExpectMultiData (byte[][])     &lt;IL 0x00037, 0x001db&gt;
at ServiceStack.Redis.RedisNativeClient.SMembers (string) &lt;IL 0x0001a,     0x000cf&gt;
at    ServiceStack.Redis.Generic.RedisTypedClient`1&lt;string&gt;.GetAllItemsFromSet    (ServiceStack.Redis.Generic.IRedisSet`1&lt;string&gt;) &lt;0x00083&gt;
at ServiceStack.Redis.Generic.RedisClientSet`1&lt;string&gt;.GetAll ()     &lt;0x0006f&gt;
at S3OL.TenantManager.getTenantOwner () [0x0001e] in     /home/admin/devgit/ols3/mono/src/TenantManager.cs:87
at S3OL.TenantManager..ctor (ServiceStack.Redis.IRedisClient,string)     [0x00084] in /home/admin/devgit/ols3/mono/src/TenantManager.cs:60
at S3OL.BucketManager..ctor (ServiceStack.Redis.IRedisClient,string,string)    [0x00016] in /home/admin/devgit/ols3/mono/src/BucketManager.cs:120
at S3OL.S3Service.Delete (S3OL.S3Request) [0x00195] in     /home/admin/devgit/ols3/mono/Interface.cs:570
at (wrapper dynamic-method) object.lambda_method     (System.Runtime.CompilerServices.Closure,object,object) &lt;IL 0x0000c,    0x000a3&gt;
at ServiceStack.Host.ServiceRunner`1&lt;S3OL.S3Request&gt;.Execute   (ServiceStack.Web.IRequest,object,S3OL.S3Request) &lt;0x00642&gt;
</StackTrace><Errors /></ResponseStatus></ErrorResponse>

只有当我有多个客户时才会发生。我可以用一个客户反复点击它,而且速度非常快。如果我同时添加一个客户端,它会死于这些 Redis 异常之一。

4

1 回答 1

1

这些IRedisClient实例不是线程安全的,不应在多个线程之间共享。这看起来像您正在重用相同的 RedisClient 实例:

IRedisClient Redis = RedisUsersCredentials.RedisClient;

您应该IRedisClient通过访问服务中的 Redis 客户端来访问和发布每个请求的新请求,例如:

public object Put(S3Request request){
    base.Redis;
    // Do a bunch of stuff with Redis
}

哪个有效,因为如果它不存在,它会为该服务创建一个新实例:

private IRedisClient redis;
public virtual IRedisClient Redis
{
    get { return redis ?? (redis = RedisManager.GetClient()); }
}

如果它是在服务执行后创建的,它也会被处理:

public virtual void Dispose()
{
    ...
    if (redis != null)
        redis.Dispose();
}

如果您不想使用base.Redis从配置中创建的实例,IRedisClientsManager那么您必须在您的服务中创建自己的实例并自己处理它,您通常会在 using 块中创建和处理它,例如:

public object Get(S3Request request)
{
    using (var redis = RedisUsersCredentials.CreateRedisClient())
    {
        // Do a bunch of stuff with Redis
    }
}

通过每次您的服务将使用不被任何其他线程共享的新客户端实例时解析和释放一个新IRedisClient的。IRedisClientsManager

于 2015-04-02T00:11:26.617 回答