Redis is ontworpen om te werken op een beveiligd netwerk, achter een backend-applicatie. Het is niet de bedoeling dat clienttoepassingen rechtstreeks verbinding maken met Redis. Het maakt Redis een slechte keuze voor een toepassing met twee niveaus.
Als je nu Redis hiervoor toch wilt gebruiken, heb je verschillende opties. U kunt de Redis-server inkapselen in een HTTP-interface. Dit is wat de nginx redis2-module biedt. Je zou ook eens kunnen kijken naar webdis, dat vergelijkbaar is (en niet afhankelijk is van nginx). Webdis biedt enkele toegangscontrolemechanismen. Zie de documentatie.
Een andere oplossing is om een tunnel aan te leggen, zoals u voorstelde. Ik zou hier geen nginx voor gebruiken, maar gewoon oude SSH. Laten we aannemen dat de Redis-server op machine B (poort 6379) draait en de client op machine A.
Op machine A kan ik uitvoeren:
ssh [email protected]_B -L 7008:host_B:6379 -N
Het opent een tunnel van A naar B vanaf lokale poort 7008 (willekeurige keuze), en wacht. De gebruiker moet op host B zijn gedeclareerd en het wachtwoord moet bekend zijn. In een andere sessie, nog steeds op host A, kunnen we nu uitvoeren:
redis-cli -p 7008 ping
Let op:er wordt een standaard Redis-client gebruikt. De tunnel zorgt voor authenticatie, encryptie en eventueel compressie op een transparante manier voor de klant.
Uw client is nu een Java-toepassing en u wilt waarschijnlijk geen SSH-commando's uitvoeren om de tunnel in te stellen. Hopelijk kunt u het Jsch-pakket gebruiken om de tunnel rechtstreeks vanuit Java te openen. Hier is een voorbeeld met 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();
}
}
Het werkt prima, maar houd er rekening mee dat er een overhead is vanwege de tunnel. De overhead is erg laag als het netwerk traag is (bijvoorbeeld internet). Op een snel LAN (1 GbE) valt het veel meer op:de latency kan bij gebruik van de tunnel met maximaal 3 worden vermenigvuldigd. De maximale doorvoer die de Redis-server kan ondersteunen, wordt ook beïnvloed. Aan de serverkant neemt de sshd-daemon wat CPU in beslag (meer dan Redis zelf).
Dat gezegd hebbende, denk ik niet dat onbewerkte prestaties er veel toe doen voor een toepassing met twee niveaus.