java - 从 java 使用 nginx 进行端口转发

标签 java ssl https nginx redis

我正在尝试创建一个使用redis作为后端的java应用程序。由于 Redis 是一个非常快速的键值存储,我想使用它,但是 redis 是为与 1 个客户端一起使用而设计的,因此它没有选项对于用户:通过身份验证。我想找到一种方法来实现某种身份验证,因此我尝试了带有 redis2 扩展的 nginx 。我这样做是因为我可以使用客户端证书和 HTTPS。但这使我的应用程序变得非常慢。

我正在考虑使用某种通过nginx代理连接到redis的隧道。对于这个redis,将在本地主机上监听,并且会有一个我想用来访问redis的地址,但使用https身份验证。所以基本上是我当前的方法

JAVA - Jedis - LAN - REDIS ,would be 
JAVA - Jedis(with localhost as the tunnel entrance?)-
-SSL LAN - Nginx(tunnel exit) - Redis

有什么技巧可以实现这一目标吗?最近几天我一直在网络上搜索,但我找不到任何只会给 native 连接增加一点开销的内容。

最佳答案

Redis 设计用于在后端应用程序后面的安全网络上工作。客户端应用程序不应直接连接到 Redis。这使得 Redis 成为 2 层应用程序的糟糕选择。

现在,如果您仍然想使用 Redis 来实现此目的,您有多种选择。您可以将 Redis 服务器封装在 HTTP 接口(interface)中。这就是 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 上声明该用户,并且其密码已知。在另一个 session 中,仍在主机 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();
    }
 }

它工作正常,但请注意,由于隧道的存在,会产生开销。当网络速度较慢时(例如互联网),开销非常低。在快速 LAN (1 GbE) 上,这一点更为明显:使用隧道时,延迟最多可增加 3 倍。 Redis 服务器可以维持的最大吞吐量也会受到影响。在服务器端,sshd 守护进程占用一些 CPU(比 Redis 本身更多)。

也就是说,我认为原始性能对于 2 层应用程序来说并不重要。

关于java - 从 java 使用 nginx 进行端口转发,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16789727/

相关文章:

amazon-web-services - 默认 Elastic Load Balancer DNS 与 Amazon Certificate Manager 一起使用?

apache - mod_rewrite 在 apache24 中强制使用 ssl

perl - 如何将证书安装到 Perl 证书库? 401未经授权

java - 如何用公共(public) CA 机构签署的服务器公共(public)证书解决 "unable to find valid certification path to requested target"?

java - 如何在不继续不受信任的证书页面的情况下从 Angular2 发出 https 请求

java - Android 使用证书建立 HTTPSConnection

java - 在android中将资源读取为InputStream

java - 面向方面的编程 - 什么是 'cflow' ?

java - 在 Geany 中导入外部 jar

java - 运行按钮呈灰色 - intellij