使用java中的nginx进行端口转发 [英] Port forwarding with nginx from java

查看:1509
本文介绍了使用java中的nginx进行端口转发的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm trying to make a java application which uses redis as a backend. Since Redis is a really fast key-value store which I'd like to use, but redis is made to be used with 1 client so it doesn't have an option for user:pass authentication. I'd like to find a way to implement some kind of authentication, so I tried nginx with the redis2 extension. I did this because I could use client-side certficates and HTTPS. But it's making my application really slow.

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

I'm thinking about using some kind of tunnel which connects to redis via nginx proxy. For this redis would be listen on localhost and there would be an address which I'd like to use to reach redis, but with https authentication. So basically my current method

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

实现这一目标的任何提示?我已经在网上搜索了最后几天,但我无法提出任何只增加本地连接的开销。

Any tip for achieving this? I've been googled the web for the last days but i couldn't come up anything that adds only a little overhead to the native connection.

推荐答案

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

Redis is designed to work on a secure network, behind a backend application. Client applications are not supposed to connect directly to Redis. It makes Redis a poor choice for a 2-tier application.

现在,如果您仍想使用Redis,您可以选择多种方式。您可以将Redis服务器封装在HTTP接口中。这就是nginx redis2模块提供的功能。您可能还想查看 webdis ,它类似(并且不依赖于nginx)。 Webdis提供了一些访问控制机制。请参阅文档。

Now if you still want to use Redis for this, you have several options. You can encapsulate the Redis server in a HTTP interface. This is what the nginx redis2 module provide. You might also want to have a look at webdis, which is similar (and does not depend on nginx). Webdis offers some access control mechanisms. See the documentation.

另一种解决方案是按照您的建议建立隧道。我不会使用nginx,但只是普通的旧SSH。我们假设Redis服务器在机器B(端口6379)上运行,客户端在机器A上运行。

Another solution is to establish a tunnel, as you proposed. I would not use nginx for this, but just plain old SSH. Let's suppose Redis server runs on machine B (port 6379) and client runs on machine A.

在机器A上,我可以运行:

On machine A, I can run:

ssh user@host_B -L 7008:host_B:6379 -N

它将从本地端口7008(任意选择)打开从A到B的隧道,并等待。用户应在主机B上声明,并且密码已知。在另一个会话中,仍然在主持人A上,我们现在可以运行:

It will open a tunnel from A to B from local port 7008 (arbitrary choice), and waits. The user should be declared on host B, and its password known. In another session, still on host A, we can now run:

redis-cli -p 7008 ping

请注意使用标准的Redis客户端。隧道以透明的方式为客户端处理身份验证,加密和可选的压缩。

Please note a standard Redis client is used. The tunnel handles authentication, encryption and optionally compression in a transparent way for the client.

现在,您的客户端是Java应用程序,您可能不想运行SSH用于设置隧道的命令。希望您可以使用 Jsch 包直接从Java打开隧道。以下是Jedis的示例:

Now, your client is a Java application, and you probably do not want to run SSH commands to setup the tunnel. Hopefully, you can use the Jsch package to open the tunnel directly from Java. Here is an example with 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本身)。

It works fine, but please note there is an overhead due to the tunnel. The overhead is very low when the network is slow (the Internet for instance). On a fast LAN (1 GbE), it is much more noticeable: the latency can be multiplied by up to 3 when the tunnel is used. The maximum throughput the Redis server can sustain is also impacted. On server-side, the sshd daemon takes some CPU (more than Redis itself).

这就是说,我不认为原始性能对于2层很重要申请。

That said, I don't think raw performance matters much for a 2-tier application.

这篇关于使用java中的nginx进行端口转发的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆