Redis 旨在在后端应用程序后面的安全网络上工作。客户端应用程序不应该直接连接到 Redis。它使 Redis 成为 2 层应用程序的糟糕选择。
现在,如果您仍想为此使用 Redis,您有多种选择。您可以将 Redis 服务器封装在 HTTP 接口中。这是 nginx redis2 模块提供的。您可能还想看看类似的webdis(并且不依赖于 nginx)。Webdis 提供了一些访问控制机制。请参阅文档。
另一种解决方案是按照您的建议建立隧道。我不会为此使用 nginx,而只是使用普通的旧 SSH。假设 Redis 服务器运行在机器 B(端口 6379)上,客户端运行在机器 A 上。
在机器 A 上,我可以运行:
ssh user@host_B -L 7008:host_B:6379 -N
它将从本地端口 7008(任意选择)打开从 A 到 B 的隧道,然后等待。应该在主机 B 上声明用户,并且知道其密码。在另一个会话中,仍然在主机 A 上,我们现在可以运行:
redis-cli -p 7008 ping
请注意,使用的是标准 Redis 客户端。隧道以透明的方式为客户端处理身份验证、加密和可选压缩。
现在,您的客户端是一个 Java 应用程序,您可能不想运行 SSH 命令来设置隧道。希望您可以使用Jsch包直接从 Java 打开隧道。以下是 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();
}
}
它工作正常,但请注意由于隧道而产生的开销。当网络速度较慢时(例如 Internet),开销非常低。在快速 LAN (1 GbE) 上,这一点更为明显:使用隧道时,延迟最多可增加 3 倍。Redis 服务器可以维持的最大吞吐量也会受到影响。在服务器端,sshd 守护进程占用一些 CPU(比 Redis 本身还多)。
也就是说,我认为原始性能对于 2 层应用程序来说并不重要。