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.