java连接虚拟机中的redis服务

  • Post author:
  • Post category:java


环境

java:1.7

redis: 4.0.1 64 bit

jedis: 2.6

代码

package jedis;

import redis.clients.jedis.Jedis;

public class JedisTest {


    public static void main(String[] args) {
        Jedis jedis = new Jedis("192.168.116.19", 6379);

        System.out.println("Connection to server sucessfully");
          //查看服务是否运行
        System.out.println("Server is running: "+jedis.ping());
    }
}

错误1 连接超时

Exception in thread "main" redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketTimeoutException: connect timed out
    at redis.clients.jedis.Connection.connect(Connection.java:150)
    at redis.clients.jedis.BinaryClient.connect(BinaryClient.java:75)
    at redis.clients.jedis.Connection.sendCommand(Connection.java:92)
    at redis.clients.jedis.BinaryClient.ping(BinaryClient.java:88)
    at redis.clients.jedis.BinaryJedis.ping(BinaryJedis.java:79)
    at jedis.JedisTest.main(JedisTest.java:13)
Caused by: java.net.SocketTimeoutException: connect timed out
    at java.net.DualStackPlainSocketImpl.waitForConnect(Native Method)
    at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:85)
    at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:339)
    at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:200)
    at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:182)
    at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172)
    at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
    at java.net.Socket.connect(Socket.java:579)
    at redis.clients.jedis.Connection.connect(Connection.java:144)
    ... 5 more

这个错误就表示虚拟机的

防火墙

没有开放端口

6379



步骤:



sudo firewall-cmd --permanent --add-port=6379/tcp


(如果想删除的话:

sudo firewall-cmd --permanent --remove-port=6379/tcp




--zone= public

不写也行,默认就是。

②重启防火墙:

firewall-cmd --reload


③查看目前的设置:

firewall-cmd --list-all

错误2 protected-mode

因为

redis

默认开启保护模式,也就是只允许

Exception in thread "main" redis.clients.jedis.exceptions.JedisDataException: DENIED Redis is running in protected mode because protected mode is enabled, no bind address was specified, no authentication password is requested to clients. In this mode connections are only accepted from the loopback interface. If you want to connect from external computers to Redis you may adopt one of the following solutions: 1) Just disable protected mode sending the command 'CONFIG SET protected-mode no' from the loopback interface by connecting to Redis from the same host the server is running, however MAKE SURE Redis is not publicly accessible from internet if you do so. Use CONFIG REWRITE to make this change permanent. 2) Alternatively you can just disable the protected mode by editing the Redis configuration file, and setting the protected mode option to 'no', and then restarting the server. 3) If you started the server manually just for testing, restart it with the '--protected-mode no' option. 4) Setup a bind address or an authentication password. NOTE: You only need to do one of the above things in order for the server to start accepting connections from the outside.
    at redis.clients.jedis.Protocol.processError(Protocol.java:115)
    at redis.clients.jedis.Protocol.process(Protocol.java:133)
    at redis.clients.jedis.Protocol.read(Protocol.java:202)
    at redis.clients.jedis.Connection.readProtocolWithCheckingBroken(Connection.java:285)
    at redis.clients.jedis.Connection.getStatusCodeReply(Connection.java:184)
    at redis.clients.jedis.BinaryJedis.ping(BinaryJedis.java:80)
    at jedis.JedisTest.main(JedisTest.java:13)

这里我们重点看到错误提示:

In this mode connections are only accepted from the loopback interface. If you want to connect from external computers to Redis you may adopt one of the following solutions: 
1) Just disable protected mode sending the command 'CONFIG SET protected-mode no' from the loopback interface by connecting to Redis from the same host the server is running, however MAKE SURE Redis is not publicly accessible from internet if you do so. Use CONFIG REWRITE to make this change permanent. 
2) Alternatively you can just disable the protected mode by editing the Redis configuration file, and setting the protected mode option to 'no', and then restarting the server. 
3) If you started the server manually just for testing, restart it with the '--protected-mode no' option. 
4) Setup a bind address or an authentication password. NOTE: You only need to do one of the above things in order for the server to start accepting connections from the outside.

因为是说

redis

默认启用保护模式,所以只能在本机上连接。要想外机连接可以采用4种方式:

通过命令把protected-mode 设置为no

①:利用

redis

自带的接口,执行:

CONFIG SET protected-mode no

通过修改配置文件将protected-mode 设置为no

②:通过修改

redis.conf

配置文件:

protected-mode no

然后重启服务。

(不过在启动服务时,需要明确指定配置文件,因为redis默认是不会加载

redis.conf

③启动

redis

服务器的命令添加参数:

src/redis-server --protected-mode no

我用的就是这种方式,也就是临时测试用

④ 设置一个绑定的地址或身份验证密码

这个是推荐方法。

对于我的情况而言,我是需要用

java

代码去连接虚拟机中的

redis



1、先说绑定地址的方式:

①绑定

redis

服务器的地址:

# bind 127.0.0.1
bind 192.168.116.131
#192.168.116.131 这个是我虚拟机的地址

②重启服务器:

src/redis-server redis.conf

这里一定要注意,修改

redis.conf

后,启动

redis

一定要带上这个配置文件。

(稍微提下,这时

protected-mode yes

不需要改为no)

2、设置密码

①通过修改配置文件的方式:

# requirepass foobared
requirepass yutao

重启服务后,连接客户端(cli)有两种方式:

方法一:

# 端口号也可以不写
src/redis-cli -h 192.168.116.131 -p 6379

这时假设我们直接

ping

会报错:

[yutao@localhost redis-4.0.1]$ src/redis-cli -h 192.168.116.131
192.168.116.131:6379> ping
(error) NOAUTH Authentication required.

需要执行

auth

命令来验证密码:

192.168.116.131:6379> auth yutao
OK
192.168.116.131:6379> 

方法二:

就是在连接时通过参数

-a

来指定密码:

[yutao@localhost redis-4.0.1]$ src/redis-cli -h 192.168.116.131 -p 6379 -a yutao
192.168.116.131:6379> ping
PONG

上面是在命令行敲命令的方式进行连接。

java代码连接如下:

public static void main(String[] args) {
        Jedis jedis = new Jedis("192.168.116.131", 6379);
        //添加这句代码
        jedis.auth("yutao");
        System.out.println("Connection to server sucessfully");
        //查看服务是否运行
        System.out.println("Server is running: "+jedis.ping());
    }

结果如下:

Connection to server sucessfully
Server is running: PONG

redis集群设置

如果Redis服务器,使用了集群。除了在master中配置密码外,也需要在slave中进行相应配置。在slave的配置文件中找到如下行,去掉注释并修改与master相同的密码即可:

# masterauth master-password
masterauth yutao

将redis服务器变成守护进程

#daemonize no
daemonize yes

总结

1、修改配置文件

redis.conf

后,启动

redis

服务时,一定要指明配置文件。即:

src/redis-server redis.conf

。否则修改的配置不会生效。

2、

bind

绑定的是

redis

所在的服务器

IP

地址,而不是客户端地址。文档的说明中还可以配置多个

IP

,这是针对多个网卡的情况。

3、之前我一直卡在修改

redis.conf

文件后,为什么没有生效;后来才知道其默认不加载配置文件。那它的默认值是哪里来的呢?其实是读取代码中

static

声明的变量。说白了就是代码里写死啦(硬编码)!下面列出

redis

启动步骤:

1、初始化Redis服务器全局配置
2、重置服务器Save参数(具体下文详解)和加载配置文件
3、初始化服务器
4、加载数据库
5、开始网络监听

1、就是根据

Redis.h

中设置的

Static

值来初始化

Redis

服务器配置,这里设置是

Redis

服务器的默认配置:

TCP Port,Redis Client的缺省Timeout;
Redis缺省的数据库数目;
Redis Append 持久化方式的参数设置;
Redis的所支持的各种数据结构的缺省值的设置;
Redis内存Swap相关设置;
Redis Master & Slave相关的配置;
Redis Command Table初始化。

2、加载配置文件

这一步是通过读取的配置文件来对Redis服务器进行设置,将会覆盖上一步的某些缺省设置。

需要注意的是,如果在启动Redis的时候没有指定配置文件,则Redis服务器在启动的时候是不会加载这个默认的配置文件进行配置的。

而且这个默认的配置文件和第一步中得全局默认缺省配置不尽相同,比如针对Redis的Append模式的数据保存策略的配置:

redis.conf里面的设置是:
save 900 1 -------15分钟内一次更新
save 300 10 ------5分钟内10次更新
save 60 10000 ---1分钟内10000次更新。
而上一步里面的默认缺省配置确实:
save 60*60 1 -------一个小时内1次更新
save 300 100 ------5分钟内100次更新
save 60 10000 ---1分钟内10000次更新。
因此我们在启动Redis的时候如果默认配置不能满足要求,则需要指明配置文件进行配置。

3、初始化服务器

初始化服务器是在initServer()方法中完成的,次方法利用上两步设置的参数进一步初始化服务器:

  • 创建用来维护clients和slaves的list
  • 创建共享对象。

    redisObject

    这个

    struct

    里有个变量叫做

    refcount

    ,这个变量就是用来实现共享的。Redis的对象目前Redis只支持共享

    StringObject



    Redis

    的共享对象有两大类比:第一类:

    Redis server

    的各种操作需要经常用到的各类对象,如:

    Redis Command

    的分隔符

    "\r\n"

    ,用于

    Redis command



    reply

    的”+OK\r\n”或者”-ERR\r\n”等对象,因为在

    Redis

    的各种操作这类对象要被频繁使用,所以就在启动Redis的时候创建好,然后共用这些对象,减少时间成本和空间成本;第二,类的共享对象就是对应于数字的

    StringObject

    ,如:

    Set "olylakers1" 1234; Set "olylakes2" 1234;在Redis内部,"olylakers1"和"olylakers2"

    这两个

    key

    都指向由数字1234转化的

    StringObject

    。这样在海量数据和特定存储内容下,可以节省大量的内存空间。可用通过

    REDIS_SHARED_INTEGERS

    这个参数来指定Redis启动的时候创建多少个第二类共享对象,默认的参数是10000,即创建的

    StrongObject

    个取值范围是0-9999之间。
  • 创建

    Pub/Sub

    通道
  • 初始化网络监听

    EventLoop

    的相关内容,如

    eventLoop



    timeEvent



    fileEvent

  • 如果开启了

    VM

    ,则初始化虚拟内存相关的

    IO/Thread

4、加载数据

根据配置的不同,Redis加载数据的源也不一样,如果在配置文件里设置了appendonly yes(默认是no),那么就从appendfile加载数据,反之则从RedisDb加载数据

  • 从appendfile加载数据:我们先来看一下appendfile的内容是什么。下面的一条记录摘取自appendfile:SET








    9


    o


    l


    y




    l


    a


    k


    e


    r


    s











    3 oly。很显,appendfile保存的就是redis server接收到的各种命令,那么从appendfile加载数据就是redis server从appenfile里面读取这些命令的记录,然后重新把这些命令执行一遍即可。需要注意的是,如果开启了VM,那么在从appendfile加载数据的时候可能要涉及swap操作。
  • 从redisdb加载数据:如果没有开启appendonly,那么则需要从db file加载数据到内存,其过程是:

    1、通过处理select命令,选择DB

    2、然后从db file读取key和value

    3、检查key是否过期,如果过期则跳过这个key,如果不过期,则把数据Add到对应的db的dict中

    4、如果开启了VM,则从db file中load数据,也可能涉及到swap操作

5、开始网络监听

Redis的网络监听没有采用libevent等,而是自己实现了一套简单的机遇event驱动的API,具体见ae.c

参考链接:


Redis代码阅读1–Redis启动原理



Redis 命令参考AUTH



Redis设置认证密码 Redis使用认证密码登录 在Redis集群中使用认证密码


http://blog.csdn.net/bug_moving/article/details/54907725



版权声明:本文为u013066244原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。