===============================================

  ccb_warlock

 ===============================================

最近有较多的时间给我做框架优化的工作,之所以会关注到redis连接池则是因为框架的数据路由层在redis连接异常时的处理有可以优化的地方,于是针对redis连接池的功能做了学习和测试。 


一、价值

1.1 池子的价值

这里简单提下池子设计的价值在于当某类连接需要反复创建,且创建的开销远远大于复用的开销时,可以选择引入池子来优化这块的设计。

一般来说,池子初始化时需要限定池子的大小。

最初池子里没有一个对象,当需要对象时,从池子里获取(没有时会自动创建一个跟踪的对象后提供你使用),当对象用完后并不做真正的释放,而是将该对象放回池子里等待下一个业务需要时取用。

 

1.2 redis池子的价值

一般在C#的项目中主要用StackExchange.Redis作为操作redis的轮子,而StackExchange.Redis通过创建TCP连接redis后对其进行一系列操作。

既然通过tcp,我们知道需要做3次握手后才能进行后续的业务,当业务并发执行时,池子就可以更好的降低创建连接的开销,提高连接效率。

二、NuGet包

 

StackExchange.Redis.ConnectionPool

PS.当前使用的版本为1.0.1

 

三、将redis连接池引入项目

3.1 前提

我只在基于asp.net core(2.2、3.1)的项目中测试过相关功能。

 

3.2 添加redis的配置信息

开发过asp.net core项目的应该知道,系统提供了用appsettings.json记录配置项、并通过依赖注入在项目中获取配置信息的方案。

 

假设appsettings.json的内容如下:

{
  "Redis": {
    "Host": "localhost",
    "Port": 6379,
    "Password": "123456",
    "PoolSize": 20
  }
}

 

3.3 创建接收配置的实体定义

public class RedisConfig
{
    public string Host { get; set; }
    public int Port { get; set; }
    public string Password { get; set; }
    public int PoolSize { get; set; }
}

 

3.4 添加连接池的依赖注入

这里先不考虑代码结构的问题,紧接着在Startup.cs中,添加下面的内容:

public class Startup
{
    private IConfiguration Configuration { get; }

    public Startup(IConfiguration configuration)
    {
         Configuration = configuration;
    }

    public IServiceProvider ConfigureServices(IServiceCollection services)
    {
        //todo

        // 根据实际的业务量来设置最小线程数
        ThreadPool.SetMinThreads(200, 200);
         
        var redisConfig = Configuration.GetSection("Redis").Get<RedisConfig>();

        var redisOptions = new ConfigurationOptions
        {
            EndPoints =
            {
                {redisConfig.Host, redisConfig.Port}
            },
            Password = redisConfig.Password,
        };

        services.AddRedisConnectionPool(redisOptions, redisConfig.PoolSize);

        //todo
    }

}

 

通过调用StackExchange.Redis.ConnectionPool提供的方法,就已经将redis连接池的实体注入到了整个项目中。

 


四、redis连接池的使用

由于我优化的框架是在数据路由层的拦截器里去使用连接池,故以此为例来做描述。

public class RouteInterceptor : BaseInterceptor
{
    private ObjectPool<PooledConnectionMultiplexer> Pool { get; set; }

    public RouteInterceptor(ObjectPool<PooledConnectionMultiplexer> pool)
    {
        Pool = pool;
    }

    protected override void Handler(IInvocation invocation)
    {
        var db = 1;
        //todo(获取要操作的db)

        PooledConnectionMultiplexer client = null;
        try
        {
            client = Pool.GetObject();
            var clientDb = redis.GetDatabase(db)
            
            //todo
        }
        catch (Exception e)
        {
            //todo
        }
        
        try
        {
            invocation.Proceed();
        }
        catch (Exception e)
        {
            //todo
        }
        finally
        {
            client?.Dispose();
        }
    }
}

 

接着就根据StackExchange.Redis的使用方法对redis进行操作就可以了。