Redis2.1.0:Could not get a resource from the pool的分析

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介:

节前的最后一天,sso登陆出现问题,多数用户无法正常登陆。经查询日志,报错如下:

错误日志截取如下
2015-02-15 08:40:30,536 INFO [org.jasig.cas.authentication.AuthenticationManagerImpl] - <com.gaochao.oa.module.sso.authentication.handler.FxLdapMixAuthenticationHandler successfully authenticated[username: wei.guo]>
2015-02-15 08:40:30,536 INFO [org.jasig.cas.authentication.AuthenticationManagerImpl] - <Resolved principal wei.guo>
2015-02-15 08:40:30,536 INFO [org.jasig.cas.authentication.AuthenticationManagerImpl] - <com
.gaochao.oa.module.sso.authentication.handler.FxLdapMixAuthenticationHandler@7952dda7 authenticated wei.guo with credential [username: wei.guo].>
2015-02-15 08:40:30,537 INFO [com.github.inspektr.audit.support.Slf4jLoggingAuditTrailManager] - <Audit trail record BEGIN
2015-02-15 08:40:30,576 ERROR [com
.gaochao.oa.module.sso.ticket.registry.RedisTicketRegistry] - <Failed adding TGT-18015-B0igJB5vgG03iiVqXKl5VSO0tnBtYipfauzcKLCfD2MvhVYTEP-cas01.example.org, error message :Could not get a resource from the pool>
2015-02-15 08:40:30,576 INFO [com.github.inspektr.audit.support.Slf4jLoggingAuditTrailManager] - <Audit trail record BEGIN
2015-02-15 08:40:30,955 ERROR [com
.gaochao.oa.module.sso.ticket.registry.RedisTicketRegistry] - <Failed adding TGT-18016-nMaZefSqRG393dcANeR4S1Tc2ff1WWdCafrNGwESgXkwLkCfN3-cas01.example.org, error message :Could not get a resource from the pool>


  通过以上日志可以看出问题代码在sso中,红色加粗部分可以看出sso服务器证书以及用户鉴权是成功的。

1
2
3
4
5
6
7
8
9
if  (!authenticationHandler.authenticate(credentials)) {
             log.info( "{} failed to authenticate {}" , handlerName, credentials);
         else  {
             log.info( "{} successfully authenticated {}" , handlerName,
                     credentials);
             authenticatedClass = authenticationHandler;
             authenticated =  true ;
             break ;
         }

  但是生成认证服务凭据ticket并且获得资源时失败


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
try  {
             jedis = getResource();
             byte [] b = jedis.hget(SSO_HASH_ID, ticketId.getBytes());
             if  (b ==  null  || b.length ==  0 ) {
                 return  null ;
             }
             ByteArrayInputStream bais =  new  ByteArrayInputStream(b);
             ois =  new  ObjectInputStream(bais);
             ticket = (Ticket) ois.readObject();
         catch  (JedisException e) {
             borrowOrOprSuccess =  false ;
             returnBrokenResource(jedis);
             log.error( "Failed getTicket {}, error message :{}" , ticketId,
                     e.getMessage());
         catch  (Exception e) {
             log.error( "Failed getTicket {}, error message :{}" , ticketId,
                     e.getMessage());
         }

    这段代码中可能报出Redis异常和其他异常,通过Could not get a resource from the pool,可以认为是redis异常。再进一步跟踪报出异常的地方,见如下代码:

1
2
3
4
5
6
7
8
9
@SuppressWarnings ( "unchecked"
         public  T getResource() { 
         try 
         return  (T) internalPool.borrowObject(); 
         catch  (Exception e) { 
         throw  new  JedisConnectionException( 
         "Could not get a resource from the pool" , e); 
        
         }

  在网上查找资料,一般认为这种异常都与redis的池连接配置有关:

  产生红色部分的可能原因之一是客户端redis服务器拿连接(代码描述的是租用对象borrowObject)的时候,池中无可用连接,即池中所有连接被占用,且在等待时候设定的超时时间后还没拿到时,会报出此异常。 


解决办法:

1.调整JedisPoolConfigmaxActive为适合自己系统的阀值,当然这种情况下重启服务并将重建池连接是必然可行的。


我在查看我们系统的redis配置时,redis.properties中配置为redis.maxIdle=5000

1
2
3
4
5
# Redis settings
redis.maxIdle=5000
redis.maxActive=5000
redis.maxWait=10000
redis.testOnBorrow=true

  理论上来说5000的并发量是足够的,不会出现拿不到资源的情况,但是我们的系统却出现了,继续查资料发现产生这问题的原因还可能是我们使用的redis2.1.0redis2.4.0后不需要手动归还)需要手动归还redis,而我们有的调用未归还,导致连接被长期占用;比如我们自己重写的类com.gaochao.oa.module.sso.ticket.registry.RedisTicketRegistry.javagetTickets只有获取资源,并没有归还的地方。如这里被频繁调用,在不长的时间内就很有可能在5000的情况下即出现资源连接不够用的情况。如下:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
     /** 
      * @author **
      * @date 2013-7-15 下午10:13:19
      * @see org.jasig.cas.ticket.registry.TicketRegistry#getTickets()
      * @return
      */
     public  Collection<Ticket> getTickets() {
         Jedis jedis =  null ;
         jedis = getResource();
         Map< byte [],  byte []> map = jedis.hgetAll(SSO_HASH_ID);
         if (CollectionUtils.isEmpty(map)) {
             return  new  ArrayList<Ticket>();
         }
         Map<String, Ticket> result =  new  HashMap(map.size());
         for (Iterator<Map.Entry< byte [],  byte []>> iterator = map.entrySet().iterator(); iterator.hasNext();) {
             Map.Entry< byte [],  byte []> entry = iterator.next();
//          Object jsonValue = redisSerializer.parseObject(entry.getValue());
             String ticketId =  new  String(entry.getKey());
             Ticket ticket = getTicket(ticketId);
             if (ticket !=  null ) {
                 result.put(ticketId, ticket);
             }
         }
         return  result.values();
     }



  如是以上问题,建议

1.redis换用redis 2.4.0以上版本;

2.对我们自己写的类进行走读,凡获取redis资源的地方必须需释放(一般使用redis的地方都有一个finally即最终必须执行的代码负责归还连接)


如下:


1
2
3
4
5
6
7
finally 
         IOUtils.close(ois); 
         if  (borrowOrOprSuccess) { 
         //返回到资源池 
         returnResource(jedis); 
        
         }


  另外,其他的原因还可能是网络异常、redis服务器异常等。


  节前初步解决方案是每两天重启sso、redis服务器,另外节后对代码进行走读,将获取资源后未释放的代码全部进行修复。




     本文转自 gaochaojs 51CTO博客,原文链接:http://blog.51cto.com/jncumter/1615620,如需转载请自行联系原作者



相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
21天前
|
缓存 监控 NoSQL
【Redis性能瓶颈揭秘】「调优系列」深入分析热Key的排查策略和解决方案
【Redis性能瓶颈揭秘】「调优系列」深入分析热Key的排查策略和解决方案
69 0
|
2月前
|
缓存 监控 NoSQL
Redis - 在电商购物车场景下的实战分析
Redis - 在电商购物车场景下的实战分析
156 0
|
3月前
|
存储 缓存 NoSQL
【分布式】Redis与Memcache的对比分析
【1月更文挑战第25天】【分布式】Redis与Memcache的对比分析
|
4月前
|
NoSQL Java Redis
SpringBoot原理分析 | Redis集成
SpringBoot原理分析 | Redis集成
45 0
|
4月前
|
存储 NoSQL Ubuntu
在Ubuntu上安装Redis并学习使用get、set和keys命令
在Ubuntu上安装Redis并学习使用get、set和keys命令
|
21天前
|
缓存 运维 NoSQL
【Redis故障排查】「连接失败问题排查和解决」带你总体分析和整理Redis的问题故障实战开发指南及方案
【Redis故障排查】「连接失败问题排查和解决」带你总体分析和整理Redis的问题故障实战开发指南及方案
59 0
|
8月前
|
存储 NoSQL Java
|
21天前
|
缓存 NoSQL Shell
【Redis深度专题】「核心技术提升」探究Redis服务启动的过程机制的技术原理和流程分析的指南(持久化功能分析)
【Redis深度专题】「核心技术提升」探究Redis服务启动的过程机制的技术原理和流程分析的指南(持久化功能分析)
25 0
|
21天前
|
存储 缓存 NoSQL
【Redis深度专题】「核心技术提升」探究Redis服务启动的过程机制的技术原理和流程分析的指南(集群功能分析)(一)
【Redis深度专题】「核心技术提升」探究Redis服务启动的过程机制的技术原理和流程分析的指南(集群功能分析)
41 0
|
3月前
|
存储 监控 NoSQL
搞定 Redis 数据存储原理,别只会 set、get 了
搞定 Redis 数据存储原理,别只会 set、get 了
40 0

热门文章

最新文章