Jedis source code analysis: client design and implementation routine

Keywords: Java socket Redis Jedis

Preface

Jedis is the preferred client for java application to access Redis service. This paper analyses the source code of jedis client, and picks up the common routine of client design and implementation.

Connection

To access (Redis) services, you first need to establish a connection with the service, so the client library first needs to abstract and encapsulate the connection. Jedis uses the Connection class to encapsulate a socket connection with the server:

public class Connection implements Closable {
    private Socket socket;
    private connectionTimeout = Protocol.DEFAULT_TIMEOUT;
    private int soTimeout = Protocol.DEFAULT_TIMEOUT;
    ...
    public Connection() {}
    public Connection(final String host) {
        this.host = host;
    }
    public Connection(final String host, final int port) {
        this.host = host;
        this.port = port;
    }
}

Usually, the Connection class also encapsulates the read and write of socket s. For the Redis client, it sends commands and gets results. Here, the Command class is an enumeration type of commands, and args is a variable length parameter, representing command parameters.

protected Connection sendCommand(final Command cmd, final byte[]... args) {
    // See below
}

Due to the instability of network communication, the communication between client and server usually needs to catch various exceptions and recover (retry, reconnect)

// sendCommand Implementation
    try {
      connect();
      Protocol.sendCommand(outputStream, cmd, args);
      pipelinedCommands++;
      return this;
    } catch (JedisConnectionException ex) {
      try {
        String errorMessage = Protocol.readErrorLineIfPossible(inputStream);
        if (errorMessage != null && errorMessage.length() > 0) {
          ex = new JedisConnectionException(errorMessage, ex.getCause());
        }
      } catch (Exception e) {
      }
      // Any other exceptions related to connection?
      broken = true;
      throw ex;
    }

The connect method establishes the connection, which is not necessary if the connection has been established. Here are some common parameters of socket.

  • reuse address

  • keep alive

  • tcp no delay

  • so linger

  • so timeout

  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);
      }
    }
  }

Input, output stream

Protocol

Socket connection establishes a communication channel between client and server. Protocol specifies the data transmission format. For Redis, a service using long socket connection, the protocol is usually customized, so the protocol should be abstracted and encapsulated next.

summary

Posted by divadiva on Sun, 21 Apr 2019 17:33:33 -0700