Redis_常见JedisConnectionException异常分析

最近项目开发中用到了Redis, 选择了官网推荐的java client Jedis。
Redis常用命令学习:http://redis.io/commands
Redis官方推荐Java客户端Jedis(包含了所有Redis命令的实现):https://github.com/xetorthio/jedis

Jedis使用过程中最常见异常JedisConnectionException有时确实给我们带来了很多困惑,这个异常通常出现在两个使场景。

一、当我们执行如下JedisPool类实例的getResource()时抛出can‘t get a resource异常。

异常代码如下:

redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool

at redis.clients.util.Pool.getResource(Pool.java:22)

分析:

redis.clients.util.Pool.getResource会从JedisPool实例池中返回一个可用的redis连接。分析源码可知JedisPool extends redis.clients.util.Pool<Jedis> .而Pool<T>是通过

commons-pool开源工具包中的org.apache.commons.pool.impl.GenericObjectPool来实现对Jedis实例的管理的。所以我们分析一下GenericObjectPool或许能找到答案。

首先看一下common-pool的api:http://commons.apache.org/pool/apidocs/index.html?org/apache/commons/pool/impl/GenericObjectPool.html
其中三个重要个几个属性是:
MaxActive: 可用连接实例的最大数目,为负值时没有限制。
MaxIdle: 空闲连接实例的最大数目,为负值时没有限制。Idle的实例在使用前,通常会通过org.apache.commons.pool.BasePoolableObjectFactory<T>的activateObject()方法使其变得可用。
MaxWait: 等待可用连接的最大数目,单位毫秒(million seconds)。
     (注:pool.getResource()方法实际调用的GenericObjectPool类borrowObject()方法,该方法会根据MaxWait变量值在没有可用连接(idle/active)时阻塞等待知道超时,具体含义参看api。)

也就是说当连接池中没有active/idle的连接时,会等待maxWait时间,如果等待超时还没有可用连接,则抛出Could not get a resource from the pool异常。所以为避免这样的错误,

我们应该根据程序实际情况合理设置这三个参数的值,同时在我们获取一个连接的程序方法中也应该合理的处理这个异常,当没有连接可用时,等待一段时间再获取也许是个比较好的选择。

二、当我们获取连接后对redis进行操作时,抛出redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketTimeoutException: Read timed out异常。

异常代码如下:

redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketTimeoutException: Read timed out

at redis.clients.jedis.Protocol.process(Protocol.java:79)
at redis.clients.jedis.Protocol.read(Protocol.java:131)
at redis.clients.jedis.Connection.getIntegerReply(Connection.java:188)
at redis.clients.jedis.Jedis.sismember(Jedis.java:1266)

这是一个比较麻烦的异常,困扰了我一天的时间。我们都知道Redis是对内存进行操作,速度应该都在毫秒级,这是我们通常的认识,所以当对Redis操作出现几秒的超时时间,你能想象吗?
我们还是先分析一下Jedis的源代码吧,以sadd操作为例:

  1. public Long sadd(final String key, final String... members) {
  2. checkIsInMulti();
  3. client.sadd(key, members);
  4. return client.getIntegerReply();
  5. }

client是redis.clients.jedis.Client.java的实例,继承关系如下:
public class Client extends BinaryClient implements Commands;

public class BinaryClient extends Connection;

Connection包装了对Redis server的socket操作,命令写操作通过socket.getOutputStream()输出流将命令信息发送到redis server,当写完命令后要通过socket.getInputStream()的到的输入流将
命令执行结果返回,这中间必然会有一个命令执行到结果返回的延时时间,这就是一个Jedis调用redis命令操作所用的时间。

需要说明的是,Redis server是单线程执行所有连接发送过来的命令的,也就是说不管并发中有多少个client在发送命令,redis-server端是单线程处理的,并按照默认的FIFO方式处理请求,

这个可在redis.conf配置文件中配置。关于redis server的详细运行机制参见:http://redis.io/documentation

所以client.sadd(key, members);调用完后只是将命令信息发送到了redis server端,具体有没有执行要看redis server的负载情况。然后,通过client.getIntegerReply();等待(time out)返回结果。
Connection初始化socket时有多种选择,其中设置socket time out 的方法如下:

  1. public void rollbackTimeout() {
  2. try {
  3. socket.setSoTimeout(timeout);
  4. socket.setKeepAlive(false);
  5. } catch (SocketException ex) {
  6. throw new JedisException(ex);
  7. }
  8. }

由redis.clients.jedis.Protocol.DEFAULT_TIMEOUT = 2000 我们知道默认的超时时间是2秒,这个时间相对于redis操作内存毫秒级的速度来说已经很长,那我们为什么还会遇到
ava.net.SocketTimeoutException: Read timed out异常呢?redis操作内存虽然平均毫秒级的,但当数据量很大时未必都如此快速。在我的开发过程中就遇到过一个集合到了

千万级数据量,一次操作超时时间在秒级是很正常的,而且机器性能很好的情况下已经如此,更何况我们本机开发的机器相对于生产服务器来说速度会更慢了。所以在初始化JedisPool时应该根据实际

情况通过redis.clients.jedis.JedisPoolConfig合理设置连接池参数,通过edisPool构造方法,合理设置socket读取输入InputStream的超时时间。

  1. pool = new JedisPool(config, host, port, 100000);

注意第四个参数time out,设置成我们能容忍的超时时间,单位是毫秒。但不知道为什么既然单位是毫秒,为什么参数类型是int而不是long。

设置第四个参数后,我在四千万数据量集合上操作最多一次大概超时5秒,问题基本解决。

时间: 2024-10-11 11:13:04

Redis_常见JedisConnectionException异常分析的相关文章

Java异常打印输出中常见方法的分析

Java异常是在Java应用中的警报器,在出现异常的情况下,可以帮助我们程序猿们快速定位问题的类型以及位置.但是一般在我们的项目中,由于经验阅历等多方面的原因,依然有若干的童鞋在代码中没有正确的使用异常打印方法,导致在项目的后台日志中,没有收到日志或者日志信息不完整等情况的发生,这些都给项目埋下了若干隐患.本文将深入分析在异常日志打印过程中的若干情况,并给出若干的使用建议. 1. Java异常Exception的结构分析 我们通常所说的Exception主要是继承于Throwable而来,可以参

【译】常见 Java 异常解释(恶搞版)

常见 Java 异常解释:(译者注:非技术角度分析.阅读有风险,理解需谨慎o(╯□╰)o) java.lang ArithmeticException 你正在试图使用电脑解决一个自己解决不了的数学问题,请重新阅读你的算术表达式并再次尝试. ArrayIndexOutOfBoundsException 请查看 IndexOutOfBoundsException.不同之处在于这个异常越界的元素不止一个. ArrayStoreException 你已用光了所有数组,需要从数组商店中购买更多的数组. C

Android异常分析(转)

关于异常 异常? 异常就是一种程序中没有预料到的问题,既然是没有预料到的,就可能不在原有逻辑处理范围内,脱离了代码控制,软件可能会出现各种奇怪的现象.比如:android系统常见异常现象有应用无响应.应用停止运行.冻屏.重启.死机等,这些异常系统有统一的异常处理机制,出现异常系统就会执行相应的操作,最终有相应的现象体现出来.另外,一些不在预料之中的界面显示问题,操作问题,运行卡顿问题等也可以归于异常,只不过这种异常是人为逻辑缺陷,对系统来说是正常的,但这些缺陷在异常现象中占比却相当大,直接体现出

java.lang.ArrayIndexOutOfBoundsException 异常分析及解决

参考:http://blog.csdn.net/javaeeteacher/article/details/4485834 这是一个非常常见的异常,从名字上看是数组下标越界错误,解决方法就是查看为什么下标越界. 下面是一个错误示例: Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 2 at test4.State.nextStates(State.java:93) at test4.State.m

java.lang.ArrayIndexOutOfBoundsException异常分析及解决

参考:http://blog.csdn.net/javaeeteacher/article/details/4485834 http://bbs.csdn.net/topics/90298133 这是一个非常常见的异常,从名字上看是数组下标越界错误,解决方法就是查看为什么下标越界. 下面是一个错误示例: Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 2 at test4.State.nextSt

java中常见的异常种类

Java常见的异常种类 ------------------------------------------------------------------------------- java Exception: 1.Error 2.Runtime Exception运行时异常 3.Exception 4.throw用户自定义异常 异常类分为两个大的类型:Error类代表了编译和系统的错误,不允许被捕获:Exception代表了java库方法所激发的异常.Exception类还包括Runtim

(转)Db2 数据库常见堵塞问题分析和处理

原文:https://www.ibm.com/developerworks/cn/analytics/library/ba-lo-db2-common-blocking-problem-analyze/index.html Db2 数据库堵塞怎么办 作为一个数据库管理员,工作中经常会遇到的一个问题:当数据库出现故障的情况下,如何快速定位问题和找到解决方案.尤其是在运维非常重要系统的时候,解决问题恢复服务是分秒必争.Db2 作为广泛使用的商业数据库,内部提供了众多方法论和诊断工具等来协助分析问题.

MySQL 外键异常分析

外键约束异常现象 如下测例中,没有违反引用约束的插入失败. create database `a-b`; use `a-b`; SET FOREIGN_KEY_CHECKS=0; create table t1(c1 int primary key, c2 int) engine=innodb; create table t2(c1 int primary key, c2 int) engine=innodb; alter table t2 add foreign key(c2) referen

SylixOS 之epoll异常分析

1. SylixOS epoll介绍 SylixOS为了兼容Linux的epoll,创建了epoll的兼容子系统,并支持了epoll的部分功能.SylixOS epoll兼容子系统是由select子系统模拟出来的,所以效率没有select高. 2. epoll异常分析 2.1epoll异常场景 在使用线程A创建AF_UNIX匿名套接字发送数据:线程B把套接字加入epoll监听,且设置属性为一次有效:线程C等待epoll事件产生,并读取套接字中的数据.如程序清单 2-1所示.