• ServiceStack.Redis的PooledRedisClientManager


    ServiceStack.Redis的PooledRedisClientManager蛋痛的设计

    PooledRedisClientManager是ServiceStack.Redis的连接池管理类,通过连接池可以实现更高效的Redis操作.但PooledRedisClientManager相关GetClient的设计似乎存在一些问题,如果你只Pool只指向一台Redis这倒不会有什么问题,但如果指向多台Redis那就可能产生悲剧的事情.下面解释一下指向多台Redis存在的一些问题.

    具体代码

    复制代码
     1 /// <summary>
     2         /// Called within a lock
     3         /// </summary>
     4         /// <returns></returns>
     5         private RedisClient GetInActiveWriteClient()
     6         {
     7             var desiredIndex = WritePoolIndex % writeClients.Length;
     8             //this will loop through all hosts in readClients once even though there are 2 for loops
     9             //both loops are used to try to get the prefered host according to the round robin algorithm
    10             for (int x = 0; x < ReadWriteHosts.Count; x++)
    11             {
    12                 var nextHostIndex = (desiredIndex + x) % ReadWriteHosts.Count;
    13                 var nextHost = ReadWriteHosts[nextHostIndex];
    14                 for (var i = nextHostIndex; i < writeClients.Length; i += ReadWriteHosts.Count)
    15                 {                    
    16                     if (writeClients[i] != null && !writeClients[i].Active && !writeClients[i].HadExceptions)
    17                         return writeClients[i];
    18                     else if (writeClients[i] == null || writeClients[i].HadExceptions)
    19                     {
    20                         if (writeClients[i] != null)
    21                             writeClients[i].DisposeConnection();
    22                         var client = RedisClientFactory.CreateRedisClient(nextHost.Host, nextHost.Port);
    23 
    24                         if (nextHost.RequiresAuth)
    25                             client.Password = nextHost.Password;
    26 
    27                         client.Id = RedisClientCounter++;
    28                         client.ClientManager = this;
    29                         client.NamespacePrefix = NamespacePrefix;
    30                         client.ConnectionFilter = ConnectionFilter;
    31                         
    32                         writeClients[i] = client;
    33 
    34                         return client;
    35                     }
    36                 }
    37             }
    38             return null;
    39         }
    复制代码

    工作原理

    以上代码的原理非常简单,就是轮循不同host下的可用连接,如果相关连接可用测直接返回.如果连接损耗则释放重新创建.

    存在问题

    如果只使用一个host倒没什么问题,但使用多个host的时候那你会发现如果其中一台的redis服务异常那对应的host还是会被轮循到,那就会导致轮循到应该服务的操作所有都异常,还有更悲剧的情况就是当一台服务器挡机了,就会导致连接到对应host的连接创建超时导致程序长时间等待然后报错,这情况对于并发应来说算是一个非常悲剧的事情.

    解决方法

    其实可以针对host来划分节点,每个节点存自有的连接池.当相关host的连接操作出现网络异常的时候,应该把host从当前轮循机制中排除.这样可以快速地保证操作会马上迁移到正常的host上面去.

    建立一个host恢复机制,PooledRedisClientManager应该存在一个内部机制对损坏的host 进行检测,通过connect到redis执行ping指令来确认host是否正常,如果正常马上把host恢复到轮循范围内.

    思考

    作者在连接的存储上并没有使用Stack,其实使用Stack在设计和管理上更简单,也是许是为不想在连接push到池中存在线程同步处理环节的开销.

     

  • 相关阅读:
    Coursera机器学习week11 单元测试
    关于 TypeReference 的解释
    getModifiers 方法解释。
    instanceof isInstance isAssignableFrom 比较
    elasticsearch 基础 语法总结
    kibana 启动 关闭 和进程查找
    MD5 SHA1 SHA256 SHA512 SHA1WithRSA 的区别
    spring boot 项目 热启动
    java zip 压缩文件
    Packet for query is too large (1660 > 1024). You can change this value on the server by setting the max_allowed_packet' variable.
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3094744.html
Copyright © 2020-2023  润新知