본문 바로가기
Redis

Jedis 통신방식

by 스르나 2021. 6. 11.

선요약: Jedis는 Socket을 통해 InputStream,OutputStream을 이용해  통신

jedis

 

 

우선 Jedis는 DB연결과 비슷하게 Pool을 이용해서 Redis와 연결된 객체들을 관리한다. 사용자들은 Pool을 통해 Jedis객체를 가져와서 사용한다.

 

 

//jedis의 Pool클래스의 Jedis를 받아오는 메소드
public T getResource() {
    try {
      return internalPool.borrowObject();
    } catch (NoSuchElementException nse) {
      throw new JedisException("Could not get a resource from the pool", nse);
    } catch (Exception e) {
      throw new JedisConnectionException("Could not get a resource from the pool", e);
    }
  }

 

 

이렇게 가져온 Jedis를 통해 Redis의 get, set, hset, expire등의 명령어를 수행하는데, 이때 각 Redis명령어를 수행하는 것은 Jedis클래스에서 처리한다. Jedis클래스는 BinartJedis라는 클래스를 상속받고 있는데 Jedis, BinaryJedis에서 Redis명령어 수행에 필요한 메소드 들이 구현되어있다.

 

//Jedis
// Redis의 set명령어를 수행한다.
public String set(final String key, final String value, final String nxxx, final String expx,
      final long time) {
    checkIsInMultiOrPipeline();
    client.set(key, value, nxxx, expx, time);
    return client.getStatusCodeReply();
}


//BinaryJedis
//현재 Jedis가 multi상태인지 체크를 한다
protected void checkIsInMultiOrPipeline() {
    if (client.isInMulti()) {
      throw new JedisDataException(
          "Cannot use Jedis when in Multi. Please use Transation or reset jedis state.");
    } else if (pipeline != null && pipeline.hasPipelinedResponse()) {
      throw new JedisDataException(
          "Cannot use Jedis when in Pipeline. Please use Pipeline or reset jedis state .");
    }
 }

 

set메소드안에 client 부분이 Redis-Client에 붙어서 호출을 하는 역할이다.

이 client도 BinaryJedis라는 클래스를 상속받고 있고, BinaryJedis는 Connect라는 클래스를 상속받고 있다.

 

 

protected Connection sendCommand(final Command cmd, final byte[]... args) {
    try {
      connect();
      Protocol.sendCommand(outputStream, cmd, args);
      pipelinedCommands++;
      return this;
    } catch (JedisConnectionException ex) {
      /*
       * When client send request which formed by invalid protocol, Redis send back error message
       * before close connection. We try to read it to provide reason of failure.
       */
      try {
        String errorMessage = Protocol.readErrorLineIfPossible(inputStream);
        if (errorMessage != null && errorMessage.length() > 0) {
          ex = new JedisConnectionException(errorMessage, ex.getCause());
        }
      } catch (Exception e) {
        /*
         * Catch any IOException or JedisConnectionException occurred from InputStream#read and just
         * ignore. This approach is safe because reading error message is optional and connection
         * will eventually be closed.
         */
      }
      // Any other exceptions related to connection?
      broken = true;
      throw ex;
    }
  }

위 코드는 Connect에서 실제로 Redis-Client에 메세지를 전달하는 부분이다. 저안의 connect메소드에서 현재 Connect가 Redis-Client와 소캣 연결이 되어있는지 확인한다. 그리고 Socket연결로 OutputStream,InputStream을 이용해서 통신한다.

 

public void connect() {
    if (!isConnected()) {
      try {
        socket = new Socket();
        // ->@wjw_add
        socket.setReuseAddress(true);
        socket.setKeepAlive(true); // Will monitor the TCP connection is
        // valid
        socket.setTcpNoDelay(true); // Socket buffer Whetherclosed, to
        // ensure timely delivery of data
        socket.setSoLinger(true, 0); // Control calls close () method,
        // the underlying socket is closed
        // immediately
        // <-@wjw_add

        socket.connect(new InetSocketAddress(host, port), connectionTimeout);
        socket.setSoTimeout(soTimeout);
        outputStream = new RedisOutputStream(socket.getOutputStream());
        inputStream = new RedisInputStream(socket.getInputStream());
      } catch (IOException ex) {
        broken = true;
        throw new JedisConnectionException(ex);
      }
    }
  }
  
  
  
  private static void sendCommand(final RedisOutputStream os, final byte[] command,
      final byte[]... args) {
    try {
      os.write(ASTERISK_BYTE);
      os.writeIntCrLf(args.length + 1);
      os.write(DOLLAR_BYTE);
      os.writeIntCrLf(command.length);
      os.write(command);
      os.writeCrLf();

      for (final byte[] arg : args) {
        os.write(DOLLAR_BYTE);
        os.writeIntCrLf(arg.length);
        os.write(arg);
        os.writeCrLf();
      }
    } catch (IOException e) {
      throw new JedisConnectionException(e);
    }
  }