本文部分内容来自《Redis开发与运维》一书,转载请声明。原文如下:
更多Redis的开发、运维、架构以及新动态,欢迎关注微信公众号:
在Redis客户端的使用过程中,无论是客户端使用不当或者Redis服务端出现问题,客户端会反应出一些异常,下面分析一下Jedis使用过程中常见的异常情况:
一.无法从连接池获取到连接
JedisPool中的Jedis对象个数是有限的,默认是8个。这里假设使用的默认配置,如果有8个Jedis对象被占用,并且没有归还,如果调用者还要从JedisPool中借用Jedis,就需要进行等待(例如设置了maxWaitMillis>0),如果在maxWaitMillis时间内仍然无法获取到Jedis对象就会抛出如下异常。
redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool … Caused by: java.util.NoSuchElementException: Timeout waiting for idle object at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:449)
还有一种情况,就是设置了blockWhenExhausted=false,那么调用者发现池子中没有资源时,会立即抛出异常不进行等待,下面的异常就是blockWhenExhausted=false时的效果。
redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool … Caused by: java.util.NoSuchElementException: Pool exhausted at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:464)
对于这个问题,需要重点讨论的是为什么连接池没有资源了,造成没有资源的可能的原因非常多
-
1.客户端:高并发下连接池设置过小,出现供不应求,所以会出现上面的错误,但是正常情况下只要比默认的最大连接数(8个)多一些即可,因为正常情况下JedisPool以及Jedis的处理效率足够高。
-
2.客户端:没有正确使用连接池,比如没有进行释放,例如下面代码所示:
定义JedisPool,使用默认的连接池配置。
GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig(); JedisPool jedisPool = new JedisPool(poolConfig, "127.0.0.1", 6379); //向JedisPool借用8次连接,但是没有执行归还操作。 for (int i = 0; i < 8; i++) { Jedis jedis = null; try { jedis = jedisPool.getResource(); jedis.ping(); } catch (Exception e) { e.printStackTrace(); } }
当调用者再向连接池借用Jedis时(如下操作),就会抛出异常:
jedisPool.getResource().ping();
- 3.客户端:存在慢查询操作,这些慢查询持有的Jedis对象归还速度会比较慢,造成池子满了。
- 4.服务端:客户端是正常的,但是Redis服务端由于一些原因造成了客户端命令执行过程的阻塞,也会使得客户端抛出这种异常。
可以看到造成这个异常的原因是多个方面的,不要被异常的表象所迷惑,而且并不存在通用的解决方案,开发和运维只能不断加强对于Redis的理解,顺藤摸瓜逐渐找到问题所在。
二、 客户端读写超时
Jedis在调用Redis时,如果出现了读写超时后,会出现下面的异常:
redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketTimeoutException: Read timed out造成该异常的原因也有以下几种:
- 读写超时设置的过短。
- 命令本身就比较慢。
- 客户端与服务端网络不正常。
- Redis自身发生阻塞。
三 客户端连接超时
Jedis在调用Redis时,如果出现了读写超时后,会出现下面的异常:
redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketTimeoutException: connect timed out造成该异常的原因也有以下几种:
- 连接超时设置的过短。
- Redis发生阻塞,造成tcp-backlog已满,造成新的连接失败。
- 客户端与服务端网络不正常。
四、客户端缓冲区异常
Jedis在调用Redis时,如果出现客户端数据流异常,会出现下面的异常。
redis.clients.jedis.exceptions.JedisConnectionException: Unexpected end of stream.造成这个异常原因可能有如下几种:
- 1.输出缓冲区满。例如将普通客户端的输出缓冲区设置为1M 1M 60:
config set client-output-buffer-limit "normal 1048576 1048576 60 slave 268435456 67108864 60 pubsub 33554432 8388608 60"
如果使用get命令获取一个bigkey(例如3M),就会出现这个异常。
- 2.长时间闲置连接被服务端主动断开,可以查询timeout配置的设置以及自身连接池配置是否需要做空闲检测。
- 3.不正常并发读写:Jedis对象同时被多个线程并发操作,可能会出现上述异常。
五、Lua脚本正在执行
如果Redis当前正在执行Lua脚本,并且超过了lua-time-limit,此时Jedis调用Redis时,会收到下面的异常。对于如何处理这类问题(Lua lua-time-limit配置之前章节已经介绍了)
redis.clients.jedis.exceptions.JedisDataException: BUSY Redis is busy running a script. You can only call SCRIPT KILL or SHUTDOWN NOSAVE
六、Redis正在加载持久化文件
Jedis调用Redis时,如果Redis正在加载持久化文件,那么会收到下面的异常。
redis.clients.jedis.exceptions.JedisDataException: LOADING Redis is loading the dataset in memory
七、Redis使用的内存超过maxmemory配置
Jedis调用Redis执行写操作时,如果Redis的使用内存大于maxmemory的设置,会收到下面的异常,此时应该调整maxmemory并找到造成内存增长的原因(maxmemory之前章节已经介绍了)
redis.clients.jedis.exceptions.JedisDataException: OOM command not allowed when used memory > 'maxmemory'.
八、客户端连接数过大
如果客户端连接数超过了maxclients,新申请的连接就会出现如下异常:
redis.clients.jedis.exceptions.JedisDataException: ERR max number of clients reached
此时新的客户端连接执行任何命令,返回结果都是如下:
127.0.0.1:6379> get hello (error) ERR max number of clients reached
- 1.客户端:如果maxclients参数不是很小的话,应用方的客户端连接数基本不会超过maxclients,通常来看是由于应用方对于Redis客户端使用不当造成的。此时如果应用方是分布式结构的话,可以通过下线部分应用节点(例如占用连接较多的节点),使得Redis的连接数先降下来。从而让绝大部分节点可以正常运行,此时在再通过查找程序bug或者调整maxclients进行问题的修复。这个问题可能会比较棘手,因为此时无法执行Redis命令,一般来说可以从两个方面进行着手。
- 2.服务端:如果此时客户端无法处理,而当前Redis为高可用模式(例如Redis Sentinel和Redis Cluster),可以考虑将当前Redis做故障转移。
相关推荐
本文将详细介绍 Redis 客户端常见的异常类型、原因和解决方法。 一、无法从连接池获取连接异常 在使用 JedisPool 连接 Redis 时,可能会出现无法从连接池获取连接的异常。这是因为 JedisPool 中的 Jedis 对象个数...
本文将围绕“Redis客户端Java服务接口封装”这一主题进行深入探讨,结合给定的`RedisClientTemplate.java`文件,我们将讨论如何在Java环境中高效地与Redis进行交互。 首先,`RedisClientTemplate`这个名字暗示它是...
### 常见的Redis客户端桌面连接工具 1. **Redis Desktop Manager**:一款非常流行的开源Redis客户端工具,支持多种数据类型显示,并具备良好的跨平台兼容性。 2. **RedisInsight**:由Redis Labs推出的官方客户端...
2.Redis的内存优化 3.Redis的Linux系统优化 4.Redis客户端常见异常分析 6.Redis无限全量复制问题分析与优化
例如,StackExchange.Redis是一个常见的C# Redis客户端,它完全支持RESP2协议,提供了丰富的API来操作Redis。 数据库相关知识点: 1. 键值对存储:Redis的核心特性之一是其键值对存储模型,键可以是任何字符串,值...
本文将详细介绍两个常见的Redis客户端连接工具:Redis Desktop Manager和RedisClient。 1. Redis Desktop Manager Redis Desktop Manager是一款跨平台的图形用户界面(GUI)工具,适用于Windows、macOS和Linux操作...
2. **Redis客户端**: - `RedisDesktopManager`(如`Redis+Desktop+Manager++v0.7.6可视化查看工具.exe`)是一个流行的图形用户界面(GUI)工具,用于连接并管理Redis服务器,进行键值操作、数据浏览和集群管理。 ...
2. **Java客户端**:Java中常见的Redis客户端有Jedis、Lettuce和Redisson等。它们都提供了与Redis服务器通信的API,包括连接管理、命令执行、事务处理等功能。例如,Jedis是较早的Redis客户端,功能完备,而Lettuce...
标题 "A C++ Redis client.zip" 提供了一个关键信息,即这个压缩包包含了一个用C++编写的Redis客户端。Redis是一种高性能的键值存储系统,常用于数据缓存、消息队列以及数据库等多个场景。C++是通用的、面向对象的...
StackExchange.Redis是.NET平台上广泛使用的Redis客户端,提供了丰富的功能和良好的性能。 首先,让我们深入了解一下Redis的基础知识。Redis作为一个内存数据存储系统,支持多种数据结构,如字符串、哈希、列表、...
"redis-client-windows" 是一个专为Windows操作系统设计的Redis客户端工具,它提供了便捷的方式在本地Windows环境中与Redis服务器进行交互,包括复制、查询和修改Redis中的数据。 在Windows上使用Redis通常涉及以下...
Jedis是较早且广泛应用的Redis客户端,支持多种Redis命令,而Lettuce则提供了更现代的Netty基础的异步API,适合高并发场景。 2. **集成步骤** - 添加依赖:在Maven或Gradle项目中,你需要在pom.xml或build.gradle...
2. C++库选择:熟悉cpp-redis、hiredis等C++ Redis客户端库,了解其API用法。 3. 网络编程:理解TCP/IP协议基础,能够建立和管理网络连接。 4. 数据序列化:了解如何将C++的数据结构转换为Redis能识别的命令格式,...
StackExchange.Redis是.NET社区广泛使用的Redis客户端,提供了丰富的API接口来与Redis服务器进行交互。你可以通过NuGet包管理器在项目中添加这个库。 1. **配置Redis连接** 在C#代码中,首先创建一个`...
2. **完整的Redis命令支持**:`scredis`实现了Redis的所有标准命令,可以方便地执行常见的数据操作。 3. **连接池**:支持连接池管理,有效利用资源,减少创建和销毁连接的开销。 4. **命令流水线**:通过批量发送...
RedisUtils通常依赖于Jedis,这是一个Java语言编写的Redis客户端。通过Jedis,我们可以实现连接Redis服务器、执行各种命令(如GET、SET、HGETALL等)以及断开连接等功能。在工具类中,我们通常会定义静态方法,如`...
本教程将围绕"C# Redis引用dll+简单教程"这一主题,详细介绍如何在C#项目中引入Redis客户端库以及进行基本操作。 首先,为了在C#项目中使用Redis,我们需要一个支持.NET的Redis客户端库。常见的有StackExchange....
这意味着当网络出现问题时,客户端不会立即抛出异常并阻塞整个应用程序,而是可以设置超时和重试策略。StackExchange.Redis 提供了异步操作支持,如 `Task` 基于的 API,这使得应用程序可以在等待 Redis 回应的同时...
在Qt应用中集成Redis,我们通常会使用第三方库如`QRedis`,这是一个基于Qt的Redis客户端库,它提供了一系列方便的API来操作Redis。首先,你需要将`QRedis`库添加到你的Qt项目中,可以通过配置项目文件.pro或使用...
3. **Java Redis客户端**:在Java项目中,我们通常使用Jedis或Lettuce等库来操作Redis。这些客户端库提供了丰富的API,便于与Redis进行交互。 4. **订单状态管理**:订单可以有多种状态,如"新建"、"已支付"、"已...