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.