ServiceStack.Redis的源码分析(连接与连接池)

前几天在生产环境上redis创建连接方面的故障,分析过程中对ServiceStack.Redis的连接创建和连接池机制有了进一步了解。问题分析结束后,通过此文系统的将学习到的知识点整理出来。

从连接池获取RedisClient的流程

业务程序中通过PooledRedisClientManager对象的GetClient()方法获取客户端对象,就以此处的源码作为入口:

查看代码

public IRedisClient GetClient()
        {
            RedisClient redisClient = null;
            DateTime now = DateTime.Now;
            for (; ; )
            {
                if (!this.deactiveClientQueue.TryPop(out redisClient))
                {
                    if (this.redisClientSize >= this.maxRedisClient)
                    {
                        Thread.Sleep(3);
                        if (this.PoolTimeout != null && (DateTime.Now - now).TotalMilliseconds >= (double)this.PoolTimeout.Value)
                        {
                            break;
                        }
                    }
                    else
                    {
                        redisClient = this.CreateRedisClient();
                        if (redisClient != null)
                        {
                            goto Block_5;
                        }
                    }
                }
                else
                {
                    if (!redisClient.HadExceptions)
                    {
                        goto Block_6;
                    }
                    List<RedisClient> obj = this.writeClients;
                    lock (obj)
                    {
                        this.writeClients.Remove(redisClient);
                        this.redisClientSize--;
                    }
                    RedisState.DisposeDeactivatedClient(redisClient);
                }
            }
            bool flag2 = true;
            if (flag2)
            {
                throw new TimeoutException("Redis Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use.");
            }
            return redisClient;
        Block_5:
            this.writeClients.Add(redisClient);
            return redisClient;
        Block_6:
            redisClient.Active = true;
            this.InitClient(redisClient);
            return redisClient;
        }

此方法的主体是死循环,主要实现了这几项功能:

  • this.deactiveClientQueue代表空闲的Client集合,是ConcurrentStack<RedisClient>类型的。
  • 当this.deactiveClientQueue能够Pop出redisClient时,则跳转到Block_6分支:标记redisClient.Active属性,并执行this.InitClient(redisClient),然后将redisClient实例返回。
  • 当this.deactiveClientQueue没有可以Pop的元素时,首先执行Client数量上限的判断this.redisClientSize >= this.maxRedisClient;
    • 如果未到达上限,则执行redisClient = this.CreateRedisClient();
    • 如果达到上限,则先休眠3毫秒,然后判断是否超过连接池超时时间this.PoolTimeout,单位毫秒。超时的话直接break中断循环,不超时的话继续下一次for循环。

上述流程就是从连接池获取Client的主要流程,其中this.deactiveClientQueue相当于“Client池”。需要注意this.PoolTimeout的含义是当连接池耗尽时调用方等待的时间。

上述过程通过流程图表示为:

创建新Client的过程:CreateRedisClient()

源码如下:

查看代码

  private RedisClient CreateRedisClient()
		{
			if (this.redisClientSize >= this.maxRedisClient)
			{
				return null;
			}
			object obj = this.lckObj;
			RedisClient result;
			lock (obj)
			{
				if (this.redisClientSize >= this.maxRedisClient)
				{
					result = null;
				}
				else
				{
					Random random = new Random((int)DateTime.Now.Ticks);
					RedisClient newClient = this.InitNewClient(this.RedisResolver.CreateMasterClient(random.Next(100)));
					newClient.OnDispose += delegate()
	
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值