Redis BookSleeve套接字耗尽

时间:2013-12-31 17:45:54

标签: c# sockets redis booksleeve

我在使用BookSleeve连接和从Redis服务器添加/获取条目时收到SocketException。具体例外是:通常只允许使用每个套接字地址(协议/网络地址/端口)。

堆栈跟踪指向:BookSleeve.RedisConnectionBase.Wait(Task task) in d:\Dev\BookSleeve\BookSleeve\RedisConnectionBase.cs:2050

我的问题是我的代码中是否有错误(极有可能)是否正确关闭了连接或某种性质的东西?在大约60秒内执行约16000次操作后,往往会抛出异常。这似乎不是一个过多的操作,对吗?

相关代码如下,我很乐意提供任何其他信息。

public Cache.CacheEntry Get(string key, bool updateAccessed)
{
    var cacheKey = GetCacheableKey(key);    

    using (var conn = GetUnsecuredConnection())
    {
        var entry = conn.Get<Cache.CacheEntry>(cacheKey);
        return entry;
    }
}

public override void Add(string key, Cache.CacheEntry entry)
{
    var cacheKey = GetCacheableKey(key);    

    using (var conn = GetUnsecuredConnection())
    {
        using (var trans = conn.CreateTransaction())
        {
            trans.Set(cacheKey, entry);
            trans.Strings.Increment(DbNum, CacheEntryCountKey);
            trans.Strings.Increment(DbNum, CacheSizeKey, entry.DataLength);
            trans.Sets.Add(DbNum, CacheKeysKey, cacheKey);
            trans.Execute();
        }
    }
}

检索连接(这主要是从BookSleeve单元测试中复制的:

protected RedisConnection GetUnsecuredConnection(bool open = true, bool allowAdmin = false, bool waitForOpen = false)
{
    var host = ConfigurationManager.AppSettings["Redis.BookSleeve.Host"];
    var unsecuredPort = int.Parse(ConfigurationManager.AppSettings["Redis.BookSleeve.UnsecuredPort"]); //TODO: get this setting in a safer manner

    var conn = new RedisConnection(host, unsecuredPort, syncTimeout: 5000, ioTimeout: 5000, allowAdmin: allowAdmin);
    conn.Error += (s, args) => Log.Error(args.Exception.Message + args.Cause, args.Exception, typeof(RedisProviderBookSleeve));
    if (open)
    {
        var openAsync = conn.Open();
        if (waitForOpen) conn.Wait(openAsync);
    }
    return conn;
}

RedisConnection对象的通用扩展方法:

public static T Get<T>(this RedisConnection conn, string key, int dbNum = 0)
{
    if (typeof (T) == typeof (byte[]))
    {
        var task = conn.Strings.Get(dbNum, key);
        var result = conn.Wait(task);
        return (T) (object) result;
    }
    else
    {
        var task = conn.Strings.GetString(dbNum, key);
        var result = conn.Wait(task);
        if (result == null || typeof(T) == typeof(string))
            return (T)(object)result;

        return JsonSerializer.DeserializeFromString<T>(result);
    }
}


public static void Set<T>(this RedisConnection conn, string key, T value, int dbNum = 0)
{
    if (typeof (T) == typeof (byte[]))
    {
        conn.Strings.Set(dbNum, key, value as byte[]);
        return;
    }

    var serializedValue = JsonSerializer.SerializeToString(value);
    conn.Strings.Set(dbNum, key, serializedValue);
}

1 个答案:

答案 0 :(得分:1)

Marc对这个问题的评论让我重新考虑如何利用关系。我在另一个问题上遇到了这个答案:

Maintaining an open Redis connection using BookSleeve

我最终使用上面链接的答案中的代码,删除了我发布的'GetUnsecuredConnection'方法,现在只需在构造/执行Redis操作之前检索打开的连接。

不再有SocketException,一切似乎都按预期运行。谢谢你提示Marc!感谢@ ofer-zelig提供的连接代码。

public Cache.CacheEntry Get(string key, bool updateAccessed)
{
    var cacheKey = GetCacheableKey(key);    

    var conn = RedisConnectionGateway.Current.GetConnection();

    var entry = conn.Get<Cache.CacheEntry>(cacheKey);
    return entry;        
}

public override void Add(string key, Cache.CacheEntry entry)
{
    var cacheKey = GetCacheableKey(key);    

    var conn = RedisConnectionGateway.Current.GetConnection();

    using (var trans = conn.CreateTransaction())
    {
        trans.Set(cacheKey, entry);
        trans.Strings.Increment(DbNum, CacheEntryCountKey);
        trans.Strings.Increment(DbNum, CacheSizeKey, entry.DataLength);
        trans.Sets.Add(DbNum, CacheKeysKey, cacheKey);
        trans.Execute();
    }        
}