使用redis中遇到的问题记录

1.redis批量删除key       redis-cli keys '*' | xargs redis-cli del

2.从连接池获取jedis链接,不需要进行关闭操作,如果关闭会报redis.clients.jedis.exceptions.JedisException: Could not return the resource to the pool异常,原因是多个线程会用同一个pedis连接,如果其中一个关闭了,另外一个还在用,那么会出错。
jedis=jedisConnectionFactory.getConnection().getNativeConnection();

3.could not get a resources from the pool
  连接池的资源用完了,无法获取链接了,原因是没有归还的原因。
  实际上使用jedisPool不需要进行归还资源,只需要在有异常的时候quit()或者disconnect();

4.redis java.lang.Long cannot be cast to [B
  这是因为多个线程同时使用一个jedis连接导致
具体原因:假设jedis在执行这个命令的时候,因为redis超负荷,jedis可能返回超时的异常,这个时候发生了什么,没有处理这个异常,直接将这个jedis的链接返回到了连接池,这样有没有问题呢? 
查看jedis源码发现他的connection中对网络输出流做了一个封装,其中自建了一个buffer,所以当发生异常的时候,这个buffer里还残存着上次没有发送或者发送不完整的命令,这个时候没有做处理,直接将该连接返回到连接池,那么重用该连接执行下次命令的时候,就会将上次没有发送的命令一起发送过去,所以才会出现上面的错误“返回值类型不对”; 
所以正确的写法应该是在发送异常的时候,销毁这个连接,不能再重用! 


5.redis中保存的key-set形式的都不需要设置过期时间,并且update之前要先删除,并且保存进redis时必须原子性,即要不全都保存,要不全都不保存进去。

6.Cannot get Jedis connection; nested exception is redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
使用jedis的时候,没有将jedis return,导致过多的client连接

8.Request processing failed; nested exception is com.alibaba.fastjson.JSONException: syntax error, expect {, actual error, pos 0
jedis不是线程安全的,当多个线程使用同一个jedis链接的时候,返回值就会发生混乱。
jedis使用的时候应该每个线程都有自己独立的jedis对象,利用jedispool配置,在pool中获取jedis对象,在出错的时候应该将jedis释放,不出错的时候不需要释放,新版本已经做了自动释放。

以上各种异常总结,使用redis时需要使用连接池,并且在连接错误或发生失败时释放该连接池。并且每个线程的链接要独立。
从jedis源码中,我们可以看出,当链接异常时调用的是:jedisPool.returnBrokenResource(jedis);
当链接正常返回时调用的是:jedisPool.returnResource(jedis);
继续跟进去可以看到returnBrokenResource()方法最终调用的是GenericObjectPool.invalidateObject(),
源代码如下:
  public void invalidateObject(T obj) throws Exception {
        PooledObject p = allObjects.get(obj);
        if (p == null) {
            if (isAbandonedConfig()) {
                return;
            } else {
                throw new IllegalStateException(
                        "Invalidated object not currently part of this pool");
            }
        }
        synchronized (p) {
            if (p.getState() != PooledObjectState.INVALID) {
                destroy(p);
            }
        }
    }

最终实际处理销毁的代码就是de story()方法,跟进去可以看到逻辑很清晰:
   private void destroy(PooledObject toDestory) throws Exception {
        toDestory.invalidate();
        idleObjects.remove(toDestory);
        allObjects.remove(toDestory.getObject());
        try {
            factory.destroyObject(toDestory);
        } finally {
            destroyedCount.incrementAndGet();
            createCount.decrementAndGet();
        }
    }


如果是正常返回的链接,调用的returnResource()方法,实际上最终执行的方法是:
resource.resetState();
returnResourceObject(resource);
主要做如下处理:把链接返回到连接池,如果连接池设置了maxIdle最大空闲连接数,如果连接池中最大空闲连接数已经等于maxIdle,则会销毁这个链接;如果连接池设置了testOnReturn=true,则在返回前会先校验这个链接有效性,如果无效会被销毁。


       

你可能感兴趣的:(技术)