Redis
 sql >> Database >  >> NoSQL >> Redis

Port forwarding con nginx da java

Redis è progettato per funzionare su una rete sicura, dietro un'applicazione back-end. Le applicazioni client non dovrebbero connettersi direttamente a Redis. Rende Redis una scelta sbagliata per un'applicazione a 2 livelli.

Ora, se vuoi ancora usare Redis per questo, hai diverse opzioni. È possibile incapsulare il server Redis in un'interfaccia HTTP. Questo è ciò che fornisce il modulo nginx redis2. Potresti anche dare un'occhiata a webdis, che è simile (e non dipende da nginx). Webdis offre alcuni meccanismi di controllo degli accessi. Consulta la documentazione.

Un'altra soluzione è creare un tunnel, come hai proposto. Non userei nginx per questo, ma semplicemente il vecchio SSH. Supponiamo che il server Redis venga eseguito sulla macchina B (porta 6379) e il client venga eseguito sulla macchina A.

Sulla macchina A, posso eseguire:

ssh [email protected]_B -L 7008:host_B:6379 -N

Aprirà un tunnel da A a B dalla porta locale 7008 (scelta arbitraria) e attende. L'utente deve essere dichiarato sull'host B e la relativa password nota. In un'altra sessione, sempre sull'host A, possiamo ora eseguire:

redis-cli -p 7008 ping

Si prega di notare che viene utilizzato un client Redis standard. Il tunnel gestisce l'autenticazione, la crittografia e, facoltativamente, la compressione in modo trasparente per il client.

Ora, il tuo client è un'applicazione Java e probabilmente non vuoi eseguire comandi SSH per configurare il tunnel. Si spera che tu possa usare il pacchetto Jsch per aprire il tunnel direttamente da Java. Ecco un esempio con 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();
    }
 }

Funziona bene, ma tieni presente che c'è un sovraccarico a causa del tunnel. L'overhead è molto basso quando la rete è lenta (Internet per esempio). Su una LAN veloce (1 GbE), è molto più evidente:la latenza può essere moltiplicata fino a 3 quando si utilizza il tunnel. Anche il throughput massimo che il server Redis può sostenere è influenzato. Sul lato server, il demone sshd richiede un po' di CPU (più dello stesso Redis).

Detto questo, non credo che le prestazioni grezze siano molto importanti per un'applicazione a 2 livelli.