毕业作品是做网站的答辩会问什么,分类信息网站如何优化,个人做的网站百度搜索不到,网站更换服务器怎么做Redis作为当前服务架构不可或缺的Cache#xff0c;其支持丰富多样的数据结构#xff0c;Redis在使用中其实也有很多坑#xff0c;本次博主遇到的坑或许说是Java程序员会遇到的多一点#xff0c;下面就听博主详细道来。线上服务堵塞String key keyOf(appid);int retryCount…Redis作为当前服务架构不可或缺的Cache其支持丰富多样的数据结构Redis在使用中其实也有很多坑本次博主遇到的坑或许说是Java程序员会遇到的多一点下面就听博主详细道来。线上服务堵塞String key keyOf(appid);int retryCount 3;int socketRetryCount 3;Exception ex null;while(retryCount 0 socketRetryCount 0) {try {return redisDao.getMap(key);}catch (Exception e) {}}12月2日被告知服务出现异常查看日志发现其运行到上述代码getMap方法处后日志就没有内容了。问题分析pool-13-thread-6 prio10 tid0x00007f754800e800 nid0x71b5 waiting on condition [0x00007f758f0ee000]java.lang.Thread.State: WAITING (parking)at sun.misc.Unsafe.park(Native Method)- parking to wait for 0x0000000779b75f40 (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2043)at org.apache.commons.pool2.impl.LinkedBlockingDeque.takeFirst(LinkedBlockingDeque.java:583)at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:442)at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:363)at redis.clients.util.Pool.getResource(Pool.java:49)at redis.clients.jedis.JedisPool.getResource(JedisPool.java:99)at org.reborndb.reborn.RoundRobinJedisPool.getResource(RoundRobinJedisPool.java:300)at com.le.smartconnect.adapter.spring.RebornConnectionFactory.getConnection(RebornConnectionFactory.java:43)at org.springframework.data.redis.core.RedisConnectionUtils.doGetConnection(RedisConnectionUtils.java:128)at org.springframework.data.redis.core.RedisConnectionUtils.getConnection(RedisConnectionUtils.java:91)at org.springframework.data.redis.core.RedisConnectionUtils.getConnection(RedisConnectionUtils.java:78)at xxx.run(xxx.java:80)at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)at java.util.concurrent.FutureTask.run(FutureTask.java:262)at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)at java.lang.Thread.run(Thread.java:745)Locked ownable synchronizers:- 0x000000074f529b08 (a java.util.concurrent.ThreadPoolExecutor$Worker)从线程日志可以看出服务堵塞在获取redis连接处.分析代码配置中redis最大连接为3000redis配置中session_max_timeout为0即永不断开连接一次修改分析从以上两点分析得出redis连接被耗尽于是查找代码得知由于重写spring-data-redis中的hscan方面导致代码如下RedisConnection rc redisTemplate.getConnectionFactory().getConnection();if (rc instanceof JedisConnection) {JedisConnection JedisConnection (JedisConnection) rc;return new ConvertingCursor, Map.Entry(JedisConnection.hScan(rawValue(key), cursor, scanOptions),new Converter, Map.Entry() {Overridepublic Entry convert(final Entry source) {return new Map.Entry() {Overridepublic String getKey() {return hashKeySerializer.deserialize(source.getKey());}Overridepublic String getValue() {return hashValueSerializer.deserialize(source.getValue());}Overridepublic String setValue(String value) {throw new UnsupportedOperationException(Values cannot be set when scanning through entries.);}};}});} else {return hashOps.scan(key, scanOptions);}上述代码返回ConvertingCursor后未释放连接导出连接被占满。二次修改分析于是修改代码为正常释放连接try {...}finally {RedisConnectionUtils.releaseConnection(rc, factory);}代码经过上线再次跑程序查看线上日志发现报了大量的Connection time out.于是博主就思考是不是由于重写代码不对尝试使用spring-data-redis的原生代码即直接调用hashOps.scan(key, scanOptions)方法再次上线。上线后观察日志发现这次不是报Connection time out,日志中大量报Unknown reply:错误。分析如下由于代码是在多线程环境下运行有几百个线程去调用hscan操作spring-data-redis原生的代码执行完一次hscan操作后就会关闭连接并返回一个迭代器Cursor但是遍历Cursor时在本次count后会再次根据游标重新使用该连接进行查询可是连接却已经被关闭这时会使用新的连接是可以正常迭代的但是一旦复用到其他线程使用的连接则会导致报错Unknown reply.三次修改分析经过思考后得出结论redis在执行scan操作时一旦连接被释放那么scan操作将不会进行下去则报Connection time out.查阅官方文档得出结论redis的scan操作需要full iteration即最优方式是一个连接将以此scan任务执行完全后释放该连接。redis-scan-doc修改代码如下RedisConnectionFactory factory redisTemplate.getConnectionFactory();RedisConnection rc factory.getConnection();if (rc instanceof JedisConnection) {JedisConnection JedisConnection (JedisConnection) rc;Cursor cursorResult new ConvertingCursor, Map.Entry(JedisConnection.hScan(rawValue(key), cursor, scanOptions),new Converter, Map.Entry() {...});return new ScanResult(cursorResult, factory, rc);}public void releaseConnection() throws IOException{IOException ex null;if(cursor ! null) {try {cursor.close();} catch (IOException e) {ex e;}}try {RedisConnectionUtils.releaseConnection(rc, factory);} catch (Exception e) {}if(ex ! null) {throw ex;}}将连接返回给业务代码并在业务代码执行完毕后将连接释放问题解决。总结连接一旦开启就必须释放否则造成内存泄漏或服务堵塞不可用重写代码时需要谨记仔细查阅官方文档给出的方案并实施多线程下使用redis的scan操作需要使用一个连接遍历完Cursor而不能复用连接否则导致报错Unknown reply.