在使用redis的過程常見錯誤總結
1.JedisConnectionException Connection Reset
參考這邊文章:
- Connection reset原因分析和解決方案
https://blog.csdn.net/cwclw/article/details/52797131
1.1問題描述
Exception in thread "main" redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketException: Connection reset
at redis.clients.util.RedisInputStream.ensureFill(RedisInputStream.java:202)
at redis.clients.util.RedisInputStream.readByte(RedisInputStream.java:40)
at redis.clients.jedis.Protocol.process(Protocol.java:151)
at redis.clients.jedis.Protocol.read(Protocol.java:215)
at redis.clients.jedis.Connection.readProtocolWithCheckingBroken(Connection.java:340)
at redis.clients.jedis.Connection.getStatusCodeReply(Connection.java:239)
at redis.clients.jedis.BinaryJedis.set(BinaryJedis.java:211)
at com.swtx.infrastructure.dataAccess.redis.RedisOperation.addCognitionLinkToRedis(RedisOperation.java:181)
at com.swtx.domain.cognitron.sparkapi.CognitronAPI.addCognitionLinkToRedis(CognitronAPI.java:100)
at com.swtx.domain.cognitron.sparkapi.CognitronAPI.discovery(CognitronAPI.java:82)
at com.swtx.app.daimler.DaimlerLocalParallelTest_lipenghang.lambda$parallel$8(DaimlerLocalParallelTest_lipenghang.java:324)
at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
at java.util.HashMap$ValueSpliterator.forEachRemaining(HashMap.java:1628)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
at java.util.stream.ReduceOps$ReduceTask.doLeaf(ReduceOps.java:747)
at java.util.stream.ReduceOps$ReduceTask.doLeaf(ReduceOps.java:721)
at java.util.stream.AbstractTask.compute(AbstractTask.java:316)
at java.util.concurrent.CountedCompleter.exec(CountedCompleter.java:731)
at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
at java.util.concurrent.ForkJoinPool.helpComplete(ForkJoinPool.java:1870)
at java.util.concurrent.ForkJoinPool.externalHelpComplete(ForkJoinPool.java:2467)
at java.util.concurrent.ForkJoinTask.externalAwaitDone(ForkJoinTask.java:324)
at java.util.concurrent.ForkJoinTask.doInvoke(ForkJoinTask.java:405)
at java.util.concurrent.ForkJoinTask.invoke(ForkJoinTask.java:734)
at java.util.stream.ReduceOps$ReduceOp.evaluateParallel(ReduceOps.java:714)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:233)
at java.util.stream.LongPipeline.reduce(LongPipeline.java:438)
at java.util.stream.LongPipeline.sum(LongPipeline.java:396)
at java.util.stream.ReferencePipeline.count(ReferencePipeline.java:526)
at com.swtx.app.daimler.DaimlerLocalParallelTest_lipenghang.parallel(DaimlerLocalParallelTest_lipenghang.java:329)
at com.swtx.app.daimler.DaimlerLocalParallelTest_lipenghang.parallelUpdate(DaimlerLocalParallelTest_lipenghang.java:233)
at com.swtx.app.daimler.DaimlerLocalParallelTest_lipenghang.parallelTest(DaimlerLocalParallelTest_lipenghang.java:171)
at com.swtx.app.daimler.DaimlerLocalParallelTest_lipenghang.main(DaimlerLocalParallelTest_lipenghang.java:128)
Caused by: java.net.SocketException: Connection reset
at java.net.SocketInputStream.read(SocketInputStream.java:210)
at java.net.SocketInputStream.read(SocketInputStream.java:141)
at java.net.SocketInputStream.read(SocketInputStream.java:127)
at redis.clients.util.RedisInputStream.ensureFill(RedisInputStream.java:196)
... 33 more
Process finished with exit code 1
1.2該問題原因分析:
1.直接原因分析: 一端退出,但退出時並未關閉該連接,另一端如果在從連接中讀數據則拋出該異常(Connection reset)。簡單的說就是在連接斷開後的讀和寫操作引起的。
2.間接可能原因分析:
多線程情況下,多個線程共用一個連接池中的連接,可能其他連接使用了其他線程正在使用的(或者關閉的連接對象)
1.3解決方法:
在使用連接池的時候,最好使用 try-catch-finally語句塊關閉使用完成的redis連接(還回線程池),保證一個線程只處理一個socket連接;(放置異常的連接未關閉)
1.3.1配置連接池:
配置連接池
// 連接信息
private static final String HOST = "132.232.6.208";
private static final int PORT = 6381;
private JedisPoolConfig poolConfig = new JedisPoolConfig();
// 基本配置
poolConfig.setMaxTotal(1000); // 最大連接數
poolConfig.setMaxIdle(32); // 最大空閒連接數
poolConfig.setMaxWaitMillis(100*1000); // 最大等待時間
poolConfig.setTestOnBorrow(true); // 檢查連接可用性, 確保獲取的redis實例可用
private static JedisPool jedisPool = new JedisPool(poolConfig, HOST, PORT);
1.3.2業務部分修改
public static void test02() {
Jedis jedis = null;
try {
//jedisPool建議封裝成工具類;並採用單例模式(桌靜態對象)
jedis = jedisPool.getResource(); // 獲取Redus連接
// 業務
jedis.set("k1", "v111");
System.out.println(jedis.get("k1"));
}catch(Exception e){
e.printStackTrace();
} finally {
if(jedis != null){
//jedisPool.returnResourceObject(jedis); // 已廢棄,推薦使用jedis.close()方法
jedis.close(); // 關閉redis連接,還回redis連接池中;
}
}
}
其他相關redisPool連接參數解析:
https://www.cnblogs.com/forward22222/p/9601820.html
1.3.3正確使用方法:
package redistest.ml;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
/**
* Redis 連接池工具
*/
public class JedisPoolUtil {
private static final String HOST = "132.19.xxx.xxx";
private static final int PORT = 6388;
private static volatile JedisPool jedisPool = null;
static {
jedisPool = getJedisPoolInstance();
}
/**
* 獲取RedisPool實例(單例)
* @return RedisPool實例
*/
private static JedisPool getJedisPoolInstance() {
if (jedisPool == null) {
synchronized (JedisPoolUtil.class) {
if (jedisPool == null) {
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxTotal(1000); // 最大連接數
poolConfig.setMaxIdle(32); // 最大空閒連接數
poolConfig.setMaxWaitMillis(100*1000); // 最大等待時間
poolConfig.setTestOnBorrow(true); // 檢查連接可用性, 確保獲取的redis實例可用
jedisPool = new JedisPool(poolConfig, HOST, PORT);
}
}
}
return jedisPool;
}
/**
* 從連接池中獲取一個 Jedis 實例(連接),處理完業務員之後,還回連接池
*/
public static void testRedis() {
Jedis jedis = null;
try {
//jedisPool建議封裝成工具類;並採用單例模式(桌靜態對象)
jedis = jedisPool.getResource(); // 獲取Redus連接
// 業務
jedis.set("k1", "v111");
System.out.println(jedis.get("k1"));
}catch(Exception e){
e.printStackTrace();
} finally {
if(jedis != null){
//jedisPool.returnResourceObject(jedis); // 已廢棄,推薦使用jedis.close()方法
jedis.close(); // 關閉redis連接,還回redis連接池中;
}
}
}
}
2.jedis 的 Unexpected end of stream異常問題
參考這個https://blog.csdn.net/xiao__jia__jia/article/details/96011509