Redis er designet til at fungere på et sikkert netværk bag en backend-applikation. Klientapplikationer formodes ikke at oprette forbindelse direkte til Redis. Det gør Redis til et dårligt valg for en 2-lags applikation.
Hvis du nu stadig vil bruge Redis til dette, har du flere muligheder. Du kan indkapsle Redis-serveren i en HTTP-grænseflade. Dette er, hvad nginx redis2-modulet giver. Du vil måske også tage et kig på webdis, som ligner (og ikke afhænger af nginx). Webdis tilbyder nogle adgangskontrolmekanismer. Se dokumentationen.
En anden løsning er at etablere en tunnel, som du foreslog. Jeg ville ikke bruge nginx til dette, men bare almindelig gammel SSH. Lad os antage, at Redis-serveren kører på maskine B (port 6379), og klienten kører på maskine A.
På maskine A kan jeg køre:
ssh [email protected]_B -L 7008:host_B:6379 -N
Det vil åbne en tunnel fra A til B fra lokal havn 7008 (vilkårligt valg), og venter. Brugeren skal angives på vært B, og dens adgangskode er kendt. I en anden session, stadig på vært A, kan vi nu køre:
redis-cli -p 7008 ping
Bemærk venligst, at der bruges en standard Redis-klient. Tunnelen håndterer autentificering, kryptering og eventuelt komprimering på en gennemsigtig måde for klienten.
Nu er din klient en Java-applikation, og du vil sandsynligvis ikke køre SSH-kommandoer for at konfigurere tunnelen. Forhåbentlig kan du bruge Jsch-pakken til at åbne tunnelen direkte fra Java. Her er et eksempel med 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();
}
}
Det fungerer fint, men vær opmærksom på, at der er en overhead på grund af tunnelen. Overhead er meget lavt, når netværket er langsomt (f.eks. internettet). På et hurtigt LAN (1 GbE) er det meget mere mærkbart:latenstiden kan ganges med op til 3, når tunnelen bruges. Den maksimale gennemstrømning, Redis-serveren kan opretholde, påvirkes også. På serversiden tager sshd-dæmonen noget CPU (mere end Redis selv).
Når det er sagt, tror jeg ikke, at rå ydeevne betyder meget for en 2-lags applikation.