Redis är designad för att fungera på ett säkert nätverk, bakom en backend-applikation. Klientapplikationer är inte tänkta att ansluta direkt till Redis. Det gör Redis till ett dåligt val för en applikation i två nivåer.
Om du nu fortfarande vill använda Redis för detta har du flera alternativ. Du kan kapsla in Redis-servern i ett HTTP-gränssnitt. Detta är vad nginx redis2-modulen tillhandahåller. Du kanske också vill ta en titt på webdis, som är liknande (och inte beror på nginx). Webdis erbjuder vissa åtkomstkontrollmekanismer. Se dokumentationen.
En annan lösning är att bygga en tunnel, som du föreslog. Jag skulle inte använda nginx för detta, utan bara vanlig gammal SSH. Låt oss anta att Redis-servern körs på maskin B (port 6379) och klienten körs på maskin A.
På maskin A kan jag köra:
ssh [email protected]_B -L 7008:host_B:6379 -N
Den kommer att öppna en tunnel från A till B från lokal hamn 7008 (godtyckligt val), och väntar. Användaren bör deklareras på värd B och dess lösenord är känt. I en annan session, fortfarande på värd A, kan vi nu köra:
redis-cli -p 7008 ping
Observera att en standard Redis-klient används. Tunneln hanterar autentisering, kryptering och eventuellt komprimering på ett transparent sätt för klienten.
Nu är din klient en Java-applikation, och du vill förmodligen inte köra SSH-kommandon för att ställa in tunneln. Förhoppningsvis kan du använda Jsch-paketet för att öppna tunneln direkt från Java. Här är ett exempel 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 fungerar bra, men observera att det finns en overhead på grund av tunneln. Omkostnaderna är mycket låga när nätverket är långsamt (till exempel Internet). På ett snabbt LAN (1 GbE) är det mycket mer märkbart:latensen kan multipliceras med upp till 3 när tunneln används. Den maximala genomströmningen som Redis-servern kan upprätthålla påverkas också. På serversidan tar sshd-demonen lite CPU (mer än Redis själv).
Som sagt, jag tror inte att rå prestanda spelar så stor roll för en applikation med två nivåer.