2881099 / FreeRedis

🦄 FreeRedis is .NET40+ redis client. supports cluster, sentinel, master-slave, pub-sub, lua, pipeline, transaction, streams, client-side-caching, and pooling.
MIT License
920 stars 164 forks source link

【压力测试】Task.Run执行一些接口时会出现连接redis-server失败的情况 #147

Closed CodingdAwn closed 1 year ago

CodingdAwn commented 1 year ago

测试代码: using FreeRedis;

class Program { static Lazy _cliLazy = new Lazy(() => { var r = new RedisClient("127.0.0.1:6379,database=10"); //redis 3.2 return r; }); public static RedisClient cli => _cliLazy.Value;

static void TestSet()
{
    for (var a = 0; a < 1000000; a++)
        cli.Lock($"{a}", 10, false);
}

static void TestLock()
{
    var tasks = new Task[1000];
    var r = new Random();
    for (var a = 0; a < tasks.Length; a++)
        tasks[a] = Task.Run(() => {
            int key = r.Next();
            //Console.WriteLine($"key is {key}");
            using var lk = cli.Lock($"{key}", 2);
        });
    Task.WaitAll(tasks);
}

static void Main(string[] args)
{
    //TestSet();
    TestLock();
}

}

同步运行的话 Set和Lock都没有问题 但是异步使用task.run执行的话(即使数量比较少的情况下也会出问题) set和lock都会出现连接redis-server timeout的错误

错误log: ---> (Inner Exception #989) System.Exception: 【127.0.0.1:6379/10】状态不可用,等待后台检查程序恢复方可使用。Connect to redis-server(127.0.0.1:6379) timeout ---> System.TimeoutException: Connect to redis-server(127.0.0.1:6379) timeout at FreeRedis.Internal.DefaultRedisSocket.Connect() at FreeRedis.Internal.DefaultRedisSocket.Write(CommandPacket cmd) at FreeRedis.RedisClient.SingleInsideAdapter.<>cDisplayClass5_01.<AdapterCall>b__0() at FreeRedis.RedisClient.LogCallCtrl[T](CommandPacket cmd, Func1 func, Boolean aopBefore, Boolean aopAfter) at FreeRedis.RedisClient.LogCall[T](CommandPacket cmd, Func1 func) at FreeRedis.RedisClient.SingleInsideAdapter.AdapterCall[TValue](CommandPacket cmd, Func2 parse) at FreeRedis.RedisClient.Call[TValue](CommandPacket cmd, Func2 parse) at FreeRedis.RedisClient.Ping(String message) at FreeRedis.Internal.RedisClientPoolPolicy.PrevReheatConnectionPool(ObjectPool1 pool, Int32 minPoolSize) --- End of inner exception stack trace --- at FreeRedis.Internal.ObjectPool.ObjectPool1.GetFree(Boolean checkAvailable) at FreeRedis.Internal.ObjectPool.ObjectPool1.Get(Nullable1 timeout) at FreeRedis.RedisClient.PoolingAdapter.GetRedisSocket(CommandPacket cmd) at FreeRedis.RedisClient.PoolingAdapter.<>c__DisplayClass9_01.b0() at FreeRedis.RedisClient.LogCallCtrl[T](CommandPacket cmd, Func1 func, Boolean aopBefore, Boolean aopAfter) at FreeRedis.RedisClient.LogCall[T](CommandPacket cmd, Func1 func) at FreeRedis.RedisClient.PoolingAdapter.AdapterCall[TValue](CommandPacket cmd, Func2 parse) at FreeRedis.RedisClient.Call[TValue](CommandPacket cmd, Func2 parse) at FreeRedis.RedisClient.Set[T](String key, T value, TimeSpan timeout, Boolean keepTtl, Boolean nx, Boolean xx, Boolean get) at FreeRedis.RedisClient.SetNx[T](String key, T value, Int32 timeoutSeconds)

也是第一次使用c#做项目,这里是我使用的错误么,不应该使用task.run去异步执行redis的操作么

CodingdAwn commented 1 year ago

实际上我看项目中的LockTest.cs中也是使用Task.run做测试的,只是数量比较少 var tasks = new Task[4]; for (var a = 0; a < tasks.Length; a++) tasks[a] = Task.Run(() => { var lk = cli.Lock("testlock1", 10); Thread.CurrentThread.Join(1000); Assert.True(lk.Unlock()); }); Task.WaitAll(tasks);