Redis
 sql >> Base de Dados >  >> NoSQL >> Redis

Encaminhamento de porta com nginx de java


O Redis foi projetado para funcionar em uma rede segura, por trás de um aplicativo de back-end. Os aplicativos cliente não devem se conectar diretamente ao Redis. Isso torna o Redis uma má escolha para um aplicativo de 2 camadas.

Agora, se você ainda deseja usar o Redis para isso, tem várias opções. Você pode encapsular o servidor Redis em uma interface HTTP. Isso é o que o módulo nginx redis2 fornece. Você também pode querer dar uma olhada no webdis, que é semelhante (e não depende do nginx). Webdis oferece alguns mecanismos de controle de acesso. Consulte a documentação.

Outra solução é estabelecer um túnel, como você propôs. Eu não usaria o nginx para isso, mas apenas o velho SSH. Vamos supor que o servidor Redis seja executado na máquina B (porta 6379) e o cliente seja executado na máquina A.

Na máquina A, posso executar:
ssh [email protected]_B -L 7008:host_B:6379 -N

Ele abrirá um túnel de A para B da porta local 7008 (escolha arbitrária) e aguardará. O usuário deve ser declarado no host B e sua senha conhecida. Em outra sessão, ainda no host A, podemos agora executar:
redis-cli -p 7008 ping

Observe que um cliente Redis padrão é usado. O túnel lida com autenticação, criptografia e, opcionalmente, compactação de forma transparente para o cliente.

Agora, seu cliente é um aplicativo Java e você provavelmente não deseja executar comandos SSH para configurar o túnel. Espero que você possa usar o pacote Jsch para abrir o túnel diretamente do Java. Aqui está um exemplo com Jedis:
import redis.clients.jedis.*;
import java.util.*;
import com.jcraft.jsch.*;

public class TestTunnel {

    Jedis jedis;  
    Session session;
    JSch jsch = new JSch(); 
    int port;

    // None of the following should be hardcoded
    static String USER = "user";          // SSH user on the redis server host
    static String PASSWD = "XXXXXXXX";    // SSH user password
    static String HOST = "192.168.1.62";  // Redis server host
    static int PORT = 6379;               // Redis server port

    public TestTunnel() {
      try {
        // Open the SSH session
        session = jsch.getSession( USER, HOST, 22 );
        session.setPassword( PASSWD );
        java.util.Properties config = new java.util.Properties();
        config.put("StrictHostKeyChecking", "no");
        config.put("Compression", "yes");
        config.put("ConnectionAttempts","3");
        session.setConfig(config);
        session.connect();
        // Setup port forwarding from localhost to the Redis server
        // Local port is ephemeral (given by the OS)
        // Jedis connects to localhost using the local port
        port = session.setPortForwardingL( 0, HOST, PORT );
        jedis = new Jedis( "127.0.0.1", port );
      } catch ( JSchException e ) {
        // Proper error handling omitted
        System.out.println(e);
      }
    } 

    public void disconnect() {
      jedis.disconnect();
      try {
        session.delPortForwardingL( port );
        session.disconnect();            
      } catch ( JSchException e ) {
        // Proper error handling omitted
        System.out.println(e);
      } 
    }

    public void mytest( int n ) {
     for ( int k = 0; k < n; k++) {
      jedis.set("k" + k, "value"+k);
     }
     System.out.println("Read: "+jedis.get("k0") );
    }

    public static void main(String[] args) {
      TestTunnel obj = new TestTunnel();
      obj.mytest(10);
      obj.disconnect();
    }
 }

Funciona bem, mas observe que há uma sobrecarga devido ao túnel. A sobrecarga é muito baixa quando a rede é lenta (a Internet, por exemplo). Em uma LAN rápida (1 GbE), é muito mais perceptível:a latência pode ser multiplicada por até 3 quando o túnel é usado. A taxa de transferência máxima que o servidor Redis pode sustentar também é afetada. No lado do servidor, o daemon sshd consome alguma CPU (mais do que o próprio Redis).

Dito isso, não acho que o desempenho bruto seja muito importante para um aplicativo de 2 camadas.