0

Hi All I am trying to set up redis server using java. My Redis server is linux server with ulimit unlimited.

Here is my spring bean which creates connection

public class JedisService implements IJedisService, InitializingBean, DisposableBean{ private JedisPool jedisPool;

public JedisService() {

}

public JedisPool getJedisPool() {
    return jedisPool;
}

@Override
public void destroy() throws Exception {
    if(jedisPool != null){
        jedisPool.destroy();
    }

}

@Override
public void afterPropertiesSet() throws Exception {
    JedisPoolConfig poolConfig = new JedisPoolConfig();
    poolConfig.setMaxActive(1000);
    poolConfig.setMaxIdle(10);
    poolConfig.setMinIdle(1);
    poolConfig.setMaxWait(30000);
    poolConfig.setNumTestsPerEvictionRun(10);
    poolConfig.setTestOnBorrow(true);
    poolConfig.setTestOnReturn(true);
    poolConfig.setTestWhileIdle(true);
    poolConfig.setTimeBetweenEvictionRunsMillis(30000);

    jedisPool = new JedisPool(poolConfig,Config.REDIS_HOST,
            RestrictionUtils.REDIS_PORT,RestrictionUtils.REDIS_CONNECTION_TIMEOUT);

}

public boolean validateHitsCount(String hostKey,String urlKey,int hostHitsCount, int urlHitsCount, long timeKey,Map<String, Object> overLimit){
    int retryCount = 0;
    return recursiveRedisConnection(retryCount,hostKey,urlKey,hostHitsCount,urlHitsCount,timeKey,overLimit);
}

private boolean recursiveRedisConnection(int retryCount,String hostKey,String urlKey,int hostHitsCount, int urlHitsCount, long timeKey,Map<String, Object> overLimit){
    Jedis jedis = null;
    boolean returnObj = true;
    try {
        //Connection
        jedis = getJedisPool().getResource();
        jedis.connect();

        //Delete previous keys
        try {
            deletePreviouskeys(jedis, urlKey, hostKey, timeKey);
        } catch (Exception e) {
        }

        //Validation
        String value = jedis.get(hostKey+timeKey);
        if(value != null){
            try {
                int count = Integer.parseInt(value);
                System.out.println("HostCount: "+hostKey+ "    "+count);
                if(count < hostHitsCount){
                    jedis.incr(hostKey+timeKey);
                    returnObj = validateURLHits(jedis, urlKey, urlHitsCount, timeKey, overLimit);
                }else{
                    returnObj = false;
                    overLimit.put("Data", "You have reached maximum limit for hits---"+hostKey);
                }
            } catch (Exception e) {
            }

        }else{
            value = 1+"";
            jedis.set(hostKey+timeKey, value);
            jedis.expire(hostKey+timeKey, 60);
            returnObj = validateURLHits(jedis, urlKey, urlHitsCount, timeKey, overLimit);
        }

    } catch (Exception e) {
        retryCount ++;
        if(retryCount < 3){
            recursiveRedisConnection(retryCount,hostKey,urlKey,hostHitsCount,urlHitsCount,timeKey,overLimit);
        }else{
            e.printStackTrace();
            returnObj = false;
        }
    }finally{
        if(jedis != null && jedis.isConnected()){
            getJedisPool().returnResource(jedis);
        }
    }
    return returnObj;
}

private boolean validateURLHits(Jedis jedis,String urlKey, int urlHitsCount, long timeKey,Map<String, Object> overLimit){
    boolean returnObj = true;
    String value = jedis.get(urlKey+timeKey);
    if(value != null){
        try {
            int count = Integer.parseInt(value);
            System.out.println("URLCount: "+urlKey+ "    "+count);
            if(count < urlHitsCount){
                jedis.incr(urlKey+timeKey);
            }else{
                returnObj = false;
                overLimit.put("Data", "Reached maximum limit of hits for this URL");
            }
        }catch(Exception e){
        }
    }else{
        jedis.set(urlKey+timeKey, 1+"");
        jedis.expire(urlKey+timeKey, 60);
    }
    return returnObj;
}

private void deletePreviouskeys(Jedis jedis,String urlKey, String hostKey, long timeKey){
    /*Set<String> keys = jedis.keys("*");
    for(String key :  keys){
        if(!key.equalsIgnoreCase(urlKey+timeKey)){
            if(!key.equalsIgnoreCase(hostKey+timeKey)){
                jedis.del(key);
            }
        }

    }*/
}

}

The method validateURLHits is called in controller. But when i Run this code in multiple threads i get this error

redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool at redis.clients.util.Pool.getResource(Pool.java:22) at com.til.ibeat.service.JedisService.recursiveRedisConnection(JedisService.java:60) at com.til.ibeat.service.JedisService.recursiveRedisConnection(JedisService.java:95) at com.til.ibeat.service.JedisService.recursiveRedisConnection(JedisService.java:95) at com.til.ibeat.service.JedisService.validateHitsCount(JedisService.java:52) at com.til.ibeat.controller.MashupController.handleRequest(MashupController.java:66) at org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(SimpleControllerHandlerAdapter.java:48) at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:763) at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:709) at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:613) at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:525) at javax.servlet.http.HttpServlet.service(HttpServlet.java:621) at javax.servlet.http.HttpServlet.service(HttpServlet.java:728) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99) at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:936) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407) at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1004) at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589) at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310) at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source) at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) at java.lang.Thread.run(Unknown Source) Caused by: java.util.NoSuchElementException: Could not create a validated object, cause: ValidateObject failed

viren
  • 1,073
  • 1
  • 17
  • 41

1 Answers1

1

Did you check that your JedisPool is instanciated only once and not more?

As your Spring bean is accessed through many threads and Jedis is not thread-safe, it is possible that you can have more than one JedisPool that returns strange Jedis instances, or jedis instances used by different threads simutanously. Each thread can have a local copy of this JedisPool and/or Jedis instances and then gets errors from that.

You have two options: you can declare JedisPool as static final (only one value per classloader) or use a double-check locking (with volatile) to ensure there is only one JedisPool accessed by all the threads without local copy, according to that each Jedis used by a thread will not be accessed by another thread.

zenbeni
  • 7,019
  • 3
  • 29
  • 60