一、redis资源未释放的起因:

N年前,在修改一个古老程序时,不小心把redis释放的这块给干掉了,

if (jedis != null) {
if (!isInProcess) {
jedis.del(currentPageRunControlRedisKey);
}
JedisUtil.getInstance().closeJedis(jedis);
}

程序调用了一会之后,就获取不到redis连接了,异常如下:

redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
at redis.clients.util.Pool.getResource(Pool.java:42)

对比代码,定位到问题之后,修复上线。

二、事后分析出错的原因:

1、对于redis的认知不足.

2、java从集成redis角度上,我的认知:

2.1、选择spring-data-redis集成,目前我们的osp框架支持我们用这种方式,我目前的项目在用(po服务化).

集成后用RedisTemplate即可来操作。

好处:spring来帮你管理redis的连接获取和释放,我们只需要关注自己的业务就好.

坏处:限制于spring框架,其他暂未感觉...

2.2、用jedis来操作吧,

自己写好一个类,来获取JedisPool,对于redis的操作,记住操作完成后,释放连接回连接池,否则就会发生,我这次发生的这种问题。

好处:操作上更加灵活,不限于spring。

坏处:容易出错。

三、改进:

对于资源未释放,想到了在io操作,db操作等情况,最好封装统一的方法,保证最后资源一定是释放的。

redis方面,我参考spring的redisTemplate,

封装一个redis工具类,对每种类型的redis操作,封装一个方法,操作完后将资源释放回连接池,可避免再忘记释放redis。

代码示例:         

 import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; /**
* 描 述:JedisUtil
* 作 者:潇邦
*/
public class JedisUtil { private static final Log logger = LogFactory.getLog(JedisUtil.class); //Redis服务器IP
private static String IP = "127.0.0.1"; //Redis的端口号
private static int PORT = 6379; //可用连接实例的最大数目,默认值为8;
//如果赋值为-1,则表示不限制;如果pool已经分配了maxActive个jedis实例,则此时pool的状态为exhausted(耗尽)。
private static int MAX_ACTIVE = 64; //控制一个pool最多有多少个状态为idle(空闲的)的jedis实例,默认值也是8。
private static int MAX_IDLE = 20; //等待可用连接的最大时间,单位毫秒,默认值为-1,表示永不超时。如果超过等待时间,则直接抛出JedisConnectionException;
private static int MAX_WAIT = 3000; private static int TIMEOUT = 3000; //在borrow一个jedis实例时,是否提前进行validate操作;如果为true,则得到的jedis实例均是可用的;
private static boolean TEST_ON_BORROW = true; //在return给pool时,是否提前进行validate操作;
private static boolean TEST_ON_RETURN = true; private static Map<String, JedisPool> maps = new ConcurrentHashMap<String, JedisPool>(); private JedisUtil() {
} /**
* 类级的内部类,也就是静态的成员式内部类,该内部类的实例与外部类的实例 没有绑定关系,而且只有被调用到时才会装载,从而实现了延迟加载。
*/
private static class RedisUtilHolder {
private static JedisUtil instance = new JedisUtil();
} /**
* 当getInstance方法第一次被调用的时候,它第一次读取 RedisUtilHolder.instance,导致RedisUtilHolder类得到初始化;而这个类在装载并被初始化的时候,会初始化它的静
* 态域,从而创建RedisUtil的实例,由于是静态的域,因此只会在虚拟机装载类的时候初始化一次,并由虚拟机来保证它的线程安全性。 这个模式的优势在于,getInstance方法并没有被同步,
* 并且只是执行一个域的访问,因此延迟初始化并没有增加任何访问成本。
*/
public static JedisUtil getInstance() {
return RedisUtilHolder.instance;
} /**
* 获取连接池.
*/
private JedisPool getPool(String ip, int port) {
String key = ip + ":" + port;
JedisPool pool = null;
if (!maps.containsKey(key)) {//根据ip和端口判断连接池是否存在.
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(MAX_ACTIVE);
config.setMaxIdle(MAX_IDLE);
config.setMaxWaitMillis(MAX_WAIT);
config.setTestOnBorrow(TEST_ON_BORROW);
config.setTestOnReturn(TEST_ON_RETURN);
try {
pool = new JedisPool(config, ip, port, TIMEOUT);
maps.put(key, pool);
} catch (Exception e) {
logger.error("初始化Redis连接池异常:", e);
}
} else {
pool = maps.get(key);
}
return pool;
} /**
* 获取Jedis实例
*/
public Jedis getJedis() {
Jedis jedis = null;
try {
jedis = getPool(IP, PORT).getResource();
} catch (Exception e) {
logger.error("获取Jedis实例异常:", e);
// 销毁对象
getPool(IP, PORT).returnBrokenResource(jedis);
}
return jedis;
} /**
* 释放jedis资源到连接池
*/
public void returnResource(final Jedis jedis) {
if (jedis != null) {
getPool(IP, PORT).returnResource(jedis);
}
} /**
* 获取数据
*/
public Object get(String key) {
Object value = null;
Jedis jedis = null;
try {
jedis = getJedis();
value = jedis.get(key);
} catch (Exception e) {
logger.warn("获取数据异常:", e);
} finally {
//返还到连接池
returnResource(jedis);
}
return value;
} public static void main(String[] args) {
Object val = JedisUtil.getInstance().get("redisKey");
System.out.println(val);
} }

四、redis的概念:

redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。

五、数据库连接池的概念:

数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个;释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏。这项技术能明显提高对数据库操作的性能。

六、参考的资料:

http://www.cnblogs.com/linjiqin/archive/2013/06/14/3135248.html

http://www.sjsjw.com/kf_www/article/70_11941_26800.asp

http://www.cnblogs.com/tankaixiong/p/3660075.html

http://blog.csdn.net/truong/article/details/46711045

http://my.oschina.net/ydsakyclguozi/blog/465859

http://blog.csdn.net/aacm1992/article/details/21977237

http://www.cnblogs.com/jifeng/p/4676863.html

redis资源未释放引发的问题的更多相关文章

  1. 解决切换场景时NGUI图集资源未释放的问题

    使用unity3d编辑器,在切换场景的时候.NGUI的图集没有释放造成内存不足游戏闪退的问题. 默认情况下,unity3d切换场景之后会释放不用的内存,即内部会调用Resources.UnloadUn ...

  2. 使用HttpURLConnection时遇到的资源未释放的问题

    http://blog.sina.com.cn/s/blog_56beadc60100j9zu.html 今天自己写了一个压力测试的小程序,同时启100个线程,每个线程都串行地访问应用服务器上的一个j ...

  3. 图层损坏 E/ArcGIS﹕ The map or layer has been destroyed or recycled. 资源未释放

    看到论坛上有个网友和我一样的问题: The map or layer has been destroyed or recyled t Hello, I have a problem when the ...

  4. 一次 Redis 事务使用不当引发的生产事故

    这是悟空的第 170 篇原创文章 官网:http://www.passjava.cn 你好,我是悟空. 本文主要内容如下: 一.前言 最近项目的生产环境遇到一个奇怪的问题: 现象:每天早上客服人员在后 ...

  5. mysql优化, 删除数据后物理空间未释放(转载)

    mysql优化, 删除数据后物理空间未释放(转载) OPTIMIZE TABLE 当您的库中删除了大量的数据后,您可能会发现数据文件尺寸并没有减小.这是因为删除操作后在数据文件中留下碎片所致.OPTI ...

  6. 关于mysql 删除数据后物理空间未释放(转载)

    转自 关于mysql 删除数据后物理空间未释放(转载) - NETDATA - 博客园http://www.cnblogs.com/shawnloong/archive/2013/02/07/2908 ...

  7. jsch连接sftp后连接未释放掉问题排查

    项目中通过jsch中的sftp实现上传下载文件.在压测过程中,由于调用到sftp,下载文件不存在时,系统不断抛出异常,内存飙升,逐渐把swap区也占满,通过top监控未发现占用内存的进程,通过查找ss ...

  8. java输入输出流操作同一资源实现覆盖引发冲突的解析

    一.问题发生的场景 题目:把s.txt中大写转成小写,小写转成大写,空格转成下划线,在输入到文件中覆盖之前的 前面的没有问题,问题出现在后面的覆盖文件上,输入流.输出流要操作同一个文件的问题 二.小白 ...

  9. linux删除文件未释放空间问题处理

    linux删除文件未释放空间问题处理 或者 /根分区满了 (我的根分区是/dev/sda1,/dev/sda1满了) http://blog.csdn.net/donghustone/article/ ...

随机推荐

  1. ffplay.c函数结构简单分析(画图)

    最近重温了一下FFplay的源代码.FFplay是FFmpeg项目提供的播放器示例.尽管FFplay只是一个简单的播放器示例,它的源代码的量也是不少的.之前看代码,主要是集中于某一个"点&q ...

  2. 刀片服务器和磁盘阵列卡(RAID)技术---永和维护

    近期客户需要更换服务器,客户把买好的服务器送来了,原本感觉很小的一个服务器,可当我看到的时候是一个大个的又长又宽,类似机房服务器的那种,后来米老师给大致讲解一番:这个是刀片服务器. 刀片服务器是指在标 ...

  3. UIPassValue页面传值&nbsp;UI_08(下)

    2.从前一个界面到后一个界面 注意:解题思路  葵花宝典:属性传值  第一步:在下一个界面视图控制器的.h文件中定义一个属性  第二步:在push之前将数据存储到属性中  第三步:取出属性中的值让控件 ...

  4. 一个大数据方案:基于Nutch+Hadoop+Hbase+ElasticSearch的网络爬虫及搜索引擎

    网络爬虫架构在Nutch+Hadoop之上,是一个典型的分布式离线批量处理架构,有非常优异的吞吐量和抓取性能并提供了大量的配置定制选项.由于网络爬虫只负责网络资源的抓取,所以,需要一个分布式搜索引擎, ...

  5. memcached 详解

    Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载.它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态.数据库驱动网站的速度.Memcached ...

  6. HTML入门笔记

    HTML简介 HTML是做网页最基本的技术 1_由标签组件 2_在任何操作系统平台,只要有浏览器,都有执行HTML 3_浏览器中有HTML解析器 4_编辑HTML可以使用任何文本编辑工具,如记事本,建 ...

  7. Linux进程-命令行参数和环境列表

    命令行参数 在C中,main函数有很多的变种,比如 main(), int main(), int main(int argc, char *argv[]), int main(int argc, c ...

  8. HTML移动开发参考

    小强的HTML5移动开发之路 http://blog.csdn.net/dawanganban/article/details/17591373 其他: http://blog.csdn.net/gf ...

  9. 17_Android中Broadcast详解(有序广播,无序广播)最终广播,Bundle传递参数,传递参数的时候指定权限

     1  Broadcast是Android中的四大组件之一,他的用途很大,比如系统的一些广播:电量低.开机.锁屏等一些操作都会发送一个广播. 2  广播被分为两种不同的类型:"普通广播( ...

  10. 手把手教你画一个 逼格满满圆形水波纹loadingview Android

    才没有完结呢o( ̄︶ ̄)n .大家好,这里是番外篇. 拜读了爱哥的博客,又学到不少东西.爱哥曾经说过: 要站在巨人的丁丁上. 那么今天,我们就站在爱哥的丁丁上来学习制作一款自定义view(开个玩笑,爱 ...