Redis je navržen pro práci v zabezpečené síti za backendovou aplikací. Klientské aplikace se nemají připojovat přímo k Redis. Díky tomu je Redis špatnou volbou pro 2vrstvé aplikace.
Nyní, pokud k tomu stále chcete používat Redis, máte několik možností. Server Redis můžete zapouzdřit do rozhraní HTTP. To poskytuje modul nginx redis2. Můžete se také podívat na webdis, který je podobný (a nezávisí na nginx). Webdis nabízí některé mechanismy řízení přístupu. Viz dokumentace.
Dalším řešením je zřízení tunelu, jak jste navrhoval. Na to bych nepoužil nginx, ale prostě staré SSH. Předpokládejme, že server Redis běží na počítači B (port 6379) a klient běží na počítači A.
Na počítači A mohu spustit:
ssh [email protected]_B -L 7008:host_B:6379 -N
Otevře tunel z A do B z místního portu 7008 (libovolná volba) a čeká. Uživatel by měl být deklarován na hostiteli B a jeho heslo by mělo být známé. V další relaci, stále na hostiteli A, nyní můžeme spustit:
redis-cli -p 7008 ping
Upozorňujeme, že se používá standardní klient Redis. Tunel zajišťuje autentizaci, šifrování a volitelně kompresi pro klienta transparentním způsobem.
Nyní je vaším klientem Java aplikace a pravděpodobně nebudete chtít spouštět příkazy SSH pro nastavení tunelu. Doufejme, že můžete použít balíček Jsch k otevření tunelu přímo z Javy. Zde je příklad s Jedisem:
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();
}
}
Funguje to dobře, ale mějte na paměti, že kvůli tunelu je režie. Režie je velmi nízká, když je síť pomalá (například Internet). Na rychlé LAN (1 GbE) je to mnohem znatelnější:při použití tunelu lze latenci znásobit až 3. Ovlivněna je také maximální propustnost, kterou může server Redis udržet. Na straně serveru zabírá démon sshd nějaké CPU (více než samotný Redis).
To znamená, že si nemyslím, že hrubý výkon u 2vrstvé aplikace příliš záleží.