zoukankan      html  css  js  c++  java
  • 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到池中存在线程同步处理环节的开销.

  • 相关阅读:
    年轻人的第一个 Spring Boot 应用,太爽了!
    面试问我 Java 逃逸分析,瞬间被秒杀了。。
    Spring Boot 配置文件 bootstrap vs application 到底有什么区别?
    坑爹的 Java 可变参数,把我整得够惨。。
    6月来了,Java还是第一!
    Eclipse 最常用的 10 组快捷键,个个牛逼!
    Spring Cloud Eureka 自我保护机制实战分析
    今天是 Java 诞生日,Java 24 岁了!
    厉害了,Dubbo 正式毕业!
    Spring Boot 2.1.5 正式发布,1.5.x 即将结束使命!
  • 原文地址:https://www.cnblogs.com/smark/p/3094523.html
Copyright © 2011-2022 走看看