ServiceStack.Redis多线程冲突 [英] ServiceStack.Redis multi-threading collision

查看:166
本文介绍了ServiceStack.Redis多线程冲突的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a ServiceStack.Redis multi-threading collision. I have a kind of non-standard usage case for ServiceStack where I capture all routes in one "FallbackRoute". This means there is one service for that one route. Here is the 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
}

然后在Configure块中的AppHost.cs中,我已自动连接Redis:

Then in AppHost.cs in the Configure block I have autowired redis:

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

    container.RegisterAutoWired<RedisUsersCredentials>();

我从有关如何正确使用BasicRedisClientManager和多线程的帖子中获得了这一点.但是我得到像这样的异常:

I got this from posts on how to properly use the BasicRedisClientManager with multi-threading. But I get exceptions like:

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异常之一中死亡.

Only happens when I have more than one client. I can hit it repeatedly with one client, and very fast. If I add a client at the same time it dies in one of these Redis exceptions.

推荐答案

IRedisClient实例不是ThreadSafe实例,不应在多个线程之间共享.看起来您正在重用相同的RedisClient实例:

The IRedisClient instances are not ThreadSafe and should not be shared across multiple threads. This looks like you're reusing the same RedisClient instance:

IRedisClient Redis = RedisUsersCredentials.RedisClient;

您应该为每个请求访问并释放新的IRedisClient,这可以通过访问服务中的Redis客户端来完成,例如:

You should be accessing and releasing a new IRedisClient for each request which you can do by accessing the Redis client within the Service, e.g:

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

之所以有效,是因为它创建新实例该服务(如果不存在):

Which works because it creates a new instance for that Service if it doesn't exist:

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

如果创建则被处理服务执行后:

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

如果您不想使用从已配置的IRedisClientsManager创建的base.Redis实例,则必须在Service中创建自己的实例并自行处置,通常在使用中创建和处置阻止,例如:

If you don't want to use the base.Redis instance that gets created from the configured IRedisClientsManager than you must create your own instance within your Service and dispose of it yourself which you would typically create and dispose in a using block, e.g:

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

每次服务将使用不被任何其他线程共享的新客户端实例时,通过从IRedisClientsManager中解析并释放新的IRedisClient.

By resolving and releasing a new IRedisClient from a IRedisClientsManager each time your service will be using a new client instance that's not shared by any other threads.

这篇关于ServiceStack.Redis多线程冲突的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆