开发者社区> 技术小胖子> 正文

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

简介:
+关注继续查看

节前的最后一天,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,如需转载请自行联系原作者



版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
Ext架构分析(3)--Widget之父Component:总结
在这里,我们引用Ext Overview中的Component life cycle对组件的功能进行相应的总结: [list=1] 配置项对象生效: 组件对象的构造器会把全部的配置项传入到其子类中去,并且进行下列所有的步骤。
718 0
带你和Python与R一起玩转数据科学: 探索性数据分析
本系列将介绍如何在现在工作中用两种最流行的开源平台玩转数据科学。先来看一看数据分析过程中的关键步骤 – 探索性数据分析。
3056 0
Ext架构分析(3)--Widget之父Component:render方法
首先,让我们回忆一下对于组件的讨论:   1.只有配置了applyTo或renderTo属性才会在构建组件时立刻进行render方法的调用;   2.如果是applyTo属性,则会对component的容器进行渲染;renderTo则是对component进行渲染;     现在,让我们看一下ren...
715 0
Ext架构分析(3)--Widget之父Component:构建器
在Ext2.0中,Component是一切Widget的父类,所有的Widget都继承与它,而他又继承自Observable,因此,它天生就具备了对于事件的处理能力。 首先,让我们看一下它的构建器,它的构建器可以传入三种类型的对象: 对象(该对象的initailConfig属性为真正的配置对象;isAction属性决定了该参数是否是一个Ext.Action对象,如果是Ext.Action对象则注册Component对象)、Ext.Element对象和字符串对象。
788 0
Python数据分析之anaconda安装和使用
今天开始学习Python数据分析了,说到Python数据分析,大家都会推荐使用anaconda,但作为一个初学者,总是很多疑虑,但在实践中解决了一部分,先和大家分享分享。
1055 0
Kubernetes Ingress 日志分析与监控的最佳实践
Ingress 主要提供 HTTP 层(7 层)路由功能,是目前 K8s 中 HTTP/HTTPS 服务的主流暴露方式。为简化广大用户对于 Ingress 日志分析与监控的门槛,阿里云容器服务和日志服务将 Ingress 日志打通,只需要应用一个 yaml 资源即可完成日志采集、分析、可视化等一整套 Ingress 日志方案的部署。
5160 0
redis redis-2.6.17 安装失败 原因分析
  redis 安装 redis-2.6.17   redis 集群 安装 http://knight-black-bob.iteye.com/blog/2343192       zmalloc.
793 0
21117
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
OceanBase 入门到实战教程
立即下载
阿里云图数据库GDB,加速开启“图智”未来.ppt
立即下载
实时数仓Hologres技术实战一本通2.0版(下)
立即下载