8

Redis 部署笔记(单机 + 主从 + 哨兵 + 集群)

 2 years ago
source link: https://exp-blog.com/db/redis-bu-shu-bi-ji/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Redis是一个开源,高级的键值存储和一个适用的解决方案,用于构建高性能,可扩展的Web应用程序。它有三个主要特点,使其优越于其它键值数据存储系统:

  • Redis将其数据库完全保存在内存中,仅使用磁盘进行持久化。
  • 与其它键值数据存储相比,Redis有一组相对丰富的数据类型。
  • Redis可以将数据复制到任意数量的从机中。

2. 部署声明

本文基于Centos7系统,由浅入深讲解如何部署Redis的四种模式,分别是:单机模式、主从模式、哨兵模式、集群模式

需注意,这里因为只用于教学演示,所以这四种模式都是部署在同一台Centos机器上的(通过不同的服务端口区分不同的Redis实例)。实际使用时,一般会使用多台机器部署,此时只需要对应修改IP即可,部署过程是一样的。

3. 前置环境部署

如果只是部署Redis【单机模式/主从模式/哨兵模式】,是不需要安装这个前置环境的。

如果要部署Redis【集群模式(Redis Cluster)】,建议先装完这个前置环境才往下阅读。

这是因为Redis Cluster需要使用ruby脚本构建。虽然Centos7自带了ruby支持库的安装源,但是版本过低(只是2.0.0版本),Redis要求ruby的版本至少为2.2.2。安装方法如下:

yum install centos-release-scl-rh     # 会在/etc/yum.repos.d/目录多出一个CentOS-SCLo-scl-rh.repo源

先更换yum源安装2.3版本的ruby:

yum install rh-ruby23 -y
scl enable rh-ruby23 bash     # 临时变更当前环境变量的ruby版本为2.3(重启后失效)

这种安装方式是使得ruby2.0和2.3版本并存,并非升级ruby。 之后若要再使用2.3版本的ruby,需再次执行scl enable rh-ruby23 bash命令。

查看ruby版本:

ruby -v
# ruby 2.3.6p384 (2017-12-14 revision 61254) [x86_64-linux]

安装gem:

yum install rubygems -y

安装ruby的redis包(用于redis通讯):

gem install redis

# 若前面安装ruby版本过低就会报错:
# ERROR:  Error installing redis:
#         redis requires Ruby version >= 2.2.2.

查看gem版本:

gem -v

至此前置环境就安装完成了,下面开始讲述Redis四种模式的部署。

4. 单机模式

4.1. 简介

单机模式是Redis最基本的模式,之后的主从、哨兵、集群模式都是据此扩展而来。而且在开发环境下,出于方便起见,一般部署单机模式即可满足调试要求。

4.2. 安装

到官网下载最新版,本文下载的版本是redis-4.0.10.tar.gz :

中文官网:http://www.redis.cn/
英文官网(需梯子):https://redis.io/

上传到Centos服务器,本文上传位置为:

/usr/local/redis-4.0.10.tar.gz

解压安装包:

tar -zxvf redis-4.0.10.tar.gz

由于Redis需要编译安装,先安装gcc编译环境:

yum install gcc

进入Redis安装目录:

cd /usr/local/redis-4.0.10/

make MALLOC=libc

编译完成后,进入src目录:

cd /usr/local/redis-4.0.10/src/

把 src 目录下的文件安装到 /usr/local/bin :

make install

4.3. 部署

默认情况下,Redis是通过以下方式启动/停止的:

cd /usr/local/redis-4.0.10/src/  # 切换到启动脚本目录
./redis-server ../redis.conf    # 启动Redis
Ctrl + C                # 停止Redis

这种启动方式非但无法在后台运行,而且也不符合使用习惯。
另外默认情况下Redis也不直接支持开机自启,为此要对其进行改造。

通过命令vi /usr/local/redis-4.0.10/redis.conf编辑Redis配置文件,为支持后台启动:

daemonize yes      # 后台启动模式

# 顺便修改一下其他配置项
maxmemory 536870912  # 最大内存(单位byte),需根据实际配置,建议为当前空闲内存的50%左右
dir /tmp/redis     # Redis的工作目录(若不存在需手建否则无法启动),默认值为[./],logfile与dbfilename受其影响
logfile "6379.log"    # Redis日志名称(默认不配置,表示输出到stdout),正式部署请设置为合适的名称
dbfilename dump.rdb  # Redis数据持久化时的存储位置,正式部署请设置为合适的名称

● 单机模式配置redis.conf下载:https://share.weiyun.com/5ZhIKTe 密码:nppwyt ●

新建上面配置的Redis工作目录:

mkdir /tmp/redis

然后在/etc目录下新建redis目录:

mkdir /etc/redis

拷贝redis.conf配置文件到/etc/redis目录下,并重命名为6379.conf(取的是Redis默认端口名称,Redis启动脚本里的变量会读取这个名称,因此若redis的端口号改了,这个文件名也要修改):

cp /usr/local/redis-4.0.10/redis.conf /etc/redis/6379.conf

拷贝Redis的启动脚本到/etc/init.d目录下,并重命名为redisd:

cp /usr/local/redis-4.0.10/utils/redis_init_script /etc/init.d/redisd

通过vi /etc/init.d/redisd命令修改redisd文件,在首行#!/bin/sh下面添加两行(其含义是Redis服务必须在运行级2,3,4,5下被启动或关闭,启动的优先级是90,关闭的优先级是10):

#!/bin/sh
# chkconfig:   2345 90 10
# description:  Redis is a persistent key-value database

切换到/etc/init.d目录:

cd /etc/init.d

设置为开机自启:

chkconfig redisd on   # 若不需要自启则执行 chkconfig redisd off

现在可以直接以服务的形式启动Redis了:

service redisd start

4.4. 测试

然后通过Redis测试客户端命令redis-cli连接到Redis实例:

cd /usr/local/redis-4.0.10/src/         # 切换到启动脚本目录
./redis-cli -h 127.0.0.1 -p 6379        # 连接到Redis
172.168.10.63:6379> info                # 查看Redis信息

# Server
redis_version:4.0.10
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:a5e228e715215d35
redis_mode:standalone
os:Linux 2.6.32-358.el6.x86_64 x86_64
arch_bits:64
multiplexing_api:epoll
atomicvar_api:sync-builtin
gcc_version:4.4.7
process_id:26027
run_id:d5f3dd33bb6b52f9b82927992251e21b3a68432e
tcp_port:6379
uptime_in_seconds:1806685
uptime_in_days:20
hz:10
lru_clock:9988483
executable:/usr/local/bin/redis-server
config_file:/etc/redis/6379.conf

至此Redis单机模式部署完成。

为了开始下一阶段部署,现在先停止这个Redis进程:

service redisd stop

5. 主从模式

5.1. 简介

在实际生产环境下,Redis基本上是不可能部署成单机模式的。一般都需要部署Redis集群实现高可用,以保障业务的稳定运行。

要学会部署Redis集群,那就先从Redis集群中最简单的主从模式说起。

在一些简单小型的应用中,我们可能会看到类似于下图的Redis部署架构。其中Master是主机,Slave是从机,而这种架构方式就是所谓的一主多从

01.png

在这种架构模式下,主机和从机的数据完全一致,主机支持数据的写入和读取等各项操作,而从机则只支持与主机数据的同步和读取。也就是说,客户端可以将数据写入到主机,由主机自动将数据的写入操作同步到从机。

主从模式很好的解决了数据备份问题,并且由于主从服务数据几乎是一致的,因而可以将写入数据的命令发送给主机执行,而读取数据的命令发送给不同的从机执行,从而达到读写分离的目的。

5.2. 部署

下面演示如何部署一个一主三从的主从模式

为了区分单机模式的部署位置,这里拷贝一下Redis的目录:

cp -r /usr/local/redis-4.0.10 /usr/local/redis-ms

下文会基于于/usr/local/redis-ms目录部署主从模式。

由于每个Redis实例都是一个单独的进程,所以需要在每个Redis实例启动时为其分配一个独立的配置文件就能使他们区分开来(同时由于本文是部署在同一台机器,需为每个实例指定不同的服务端口)。

为了在同一台机器上部署一主三从的Redis,准备以下四份配置文件:

角色 配置文件 服务端口

主机 redis-6379.conf 6379

从机 redis-6380.conf 6380

从机 redis-6381.conf 6381

从机 redis-6382.conf 6382

这四份配置文件均拷贝自 /usr/local/redis-ms/redis.conf ,拷贝到 /usr/local/redis-ms/ 目录再修改即可。

主机redis-6379.conf配置文件内容如下:

bind 127.0.0.1            # 正式部署请设为合适的IP
port 6379
daemonize yes
pidfile /var/run/redis_6379.pid
dir /tmp/redis-ms         # Redis的工作目录(若不存在需手建否则无法启动),logfile与dbfilename受其影响
logfile "6379.log"        # Redis日志名称(默认不配置,表示输出到stdout),正式部署请设置为合适的名称
dbfilename dump-6379.rdb  # Redis数据持久化时的存储位置,正式部署请设置为合适的名称

● 主从模式配置redis-6379.conf下载:https://share.weiyun.com/5JOX4Nd 密码:qdcfie ●

从机redis-6380.conf配置文件内容如下:

bind 127.0.0.1            # 正式部署请设为合适的IP
port 6380
daemonize yes
pidfile /var/run/redis_6380.pid
dir /tmp/redis-ms         # Redis的工作目录(若不存在需手建否则无法启动),logfile与dbfilename受其影响
logfile "6380.log"        # Redis日志名称(默认不配置,表示输出到stdout),正式部署请设置为合适的名称
dbfilename dump-6380.rdb  # Redis数据持久化时的存储位置,正式部署请设置为合适的名称
slaveof 127.0.0.1 6379    # 标注所从属的主机

● 主从模式配置redis-6380.conf下载:https://share.weiyun.com/5SCapFt 密码:4sibg2 ●

从机redis-6381.conf配置文件内容如下:

bind 127.0.0.1            # 正式部署请设为合适的IP
port 6381
daemonize yes
pidfile /var/run/redis_6381.pid
dir /tmp/redis-ms         # Redis的工作目录(若不存在需手建否则无法启动),logfile与dbfilename受其影响
logfile "6381.log"        # Redis日志名称(默认不配置,表示输出到stdout),正式部署请设置为合适的名称
dbfilename dump-6381.rdb  # Redis数据持久化时的存储位置,正式部署请设置为合适的名称
slaveof 127.0.0.1 6379    # 标注所从属的主机

● 主从模式配置redis-6381.conf下载:https://share.weiyun.com/5pZ7hup 密码:jiw8gm ●

从机redis-6382.conf配置文件内容如下:

bind 127.0.0.1            # 正式部署请设为合适的IP
port 6382
daemonize yes
pidfile /var/run/redis_6382.pid
dir /tmp/redis-ms         # Redis的工作目录(若不存在需手建否则无法启动),logfile与dbfilename受其影响
logfile "6382.log"        # Redis日志名称(默认不配置,表示输出到stdout),正式部署请设置为合适的名称
dbfilename dump-6382.rdb  # Redis数据持久化时的存储位置,正式部署请设置为合适的名称
slaveof 127.0.0.1 6379    # 标注所从属的主机

● 主从模式配置redis-6382.conf下载:https://share.weiyun.com/5rlib8O 密码:xf6qkn ●

新建上面配置的Redis工作目录:

mkdir /tmp/redis-ms

然后使用redis-server命令启动Redis主从实例:

cd /usr/local/redis-ms/src/           # 切换到启动脚本目录
./redis-server ../redis-6379.conf     # 启动Redis主机,必须先启动
./redis-server ../redis-6380.conf     # 启动Redis从机
./redis-server ../redis-6381.conf     # 启动Redis从机
./redis-server ../redis-6382.conf     # 启动Redis从机

5.3. 测试

现在测试Redis主从模式是否能正常工作。

可先通过ps -ef|grep redis命令可查看四个主从进程是否正常启动:

root 3919 1 0 22:08 ? 00:00:02 ./redis-server 127.0.0.1:6379
root 3924 1 0 22:08 ? 00:00:02 ./redis-server 127.0.0.1:6380
root 3930 1 0 22:08 ? 00:00:02 ./redis-server 127.0.0.1:6381
root 3936 1 0 22:08 ? 00:00:02 ./redis-server 127.0.0.1:6382

然后通过Redis测试客户端命令redis-cli分别连接到四台机器:

cd /usr/local/redis-ms/src/          # 切换到启动脚本目录
./redis-cli -h 127.0.0.1 -p 6379     # 连接到Redis主机
./redis-cli -h 127.0.0.1 -p 6380     # 连接到Redis从机
./redis-cli -h 127.0.0.1 -p 6381     # 连接到Redis从机
./redis-cli -h 127.0.0.1 -p 6382     # 连接到Redis从机

分别在四个Redis测试客户端执行get命令,获取键名为site的数据:

127.0.0.1:6379> get site
(nil)                  # 由于是新部署的Redis集群,该键值必定不存在
127.0.0.1:6380> get site
(nil)                  # 由于是新部署的Redis集群,该键值必定不存在
127.0.0.1:6381> get site
(nil)                  # 由于是新部署的Redis集群,该键值必定不存在
127.0.0.1:6382> get site
(nil)                  # 由于是新部署的Redis集群,该键值必定不存在

现在在Redis主机6379的客户端写入数据(执行set命令,为键site设置数据):

127.0.0.1:6379> set site http://exp-blog.com

再在三台Redis从机 6380 ~ 6382 的客户端读取数据(执行get命令,获取键名为site的数据)。由于经过主从数据同步,此时三台从机都能取到值:

127.0.0.1:6380> get site
"http://exp-blog.com"
127.0.0.1:6381> get site
"http://exp-blog.com"
127.0.0.1:6382> get site
"http://exp-blog.com"

至此Redis主从模式部署完成。

下一阶段哨兵模式的部署是基于主从模式的,可以暂且不用停止Redis进程。

6. 哨兵模式

6.1. 简介

前面所配置的主从模式,虽然实现了读写分离,解决了数据备份问题和单机模式可能存在的性能问题,但是也引入了新的问题:

由于主从模式下可以将读写操作分配给不同的Redis节点,从而达到提高系统吞吐量的目的,但也正是因为这种方式造成了使用上的不便。因为客户端连接到不同的Redis节点时,都需要指定特定的IP端口,若所连接的节点因为故障下线了,主从模式便无法通知客户端切换到另一个可用节点,只能靠手动更改客户端配置并重连。

尤其是如果故障下线的是主节点,那么所有的从节点便会因为没有主节点而同步中断,整个集群会陷入瘫痪(严格来说是所有从节点变成独立节点,再无关联性),直至人工重新指定新的主节点。

为了解决上面的问题,Redis在2.8版本后开始支持哨兵模式,其架构模式如下图:

02.png

Redis的Sentinel系统(即哨兵系统)可用于管理多组Redis主从实例,它是Redis的高可用性解决方案。这个系统主要执行以下三个任务:

  • 监控(Monitoring):Sentinel会不断地定期检查主/从节点服务器是否运作正常
  • 提醒(Notification):当被监控的某个节点服务器出现问题时,Sentinel可以通过API向管理员或者其他应用程序发送通知
  • 自动故障迁移(Automaticfailover):当一个主节点不能正常工作时,Sentinel会开始一次自动故障迁移操作,它会将失效主节点下的其中一个从节点升级为新的主节点,并让失效主主节点的其他从节点改为复制新的主节点。当Redis客户端试图连接失效的主节点时,集群也会向客户端返回新主节点的地址,使得集群可以使用新主节点代替失效主节点。

6.2. 部署

下面演示如何在上一阶段的主从模式基础上,增加部署一套哨兵系统

先准备好三份配置文件:

角色 配置文件 监听端口

哨兵 sentinel-26380.conf 26380

哨兵 sentinel-26381.conf 26381

哨兵 sentinel-26382.conf 26382

① 这三份配置文件均拷贝自/usr/local/redis-ms/sentinel.conf ,拷贝到 /usr/local/redis-ms/ 目录再修改即可。
② 建议哨兵至少部署3个,并且哨兵节点数量要满足2n+1(n>=1),即奇数个。

哨兵sentinel-26380.conf配置文件内容如下:

bind 127.0.0.1                   # 正式部署请设为合适的IP
port 26380
daemonize yes                    # 后台启动模式(若无配置项则添加)
dir /tmp/redis-ms                # Redis的工作目录(若不存在需手建否则无法启动),logfile受其影响
logfile "sentinel-26380.log"     # 哨兵日志名称(若无配置项则添加),正式部署请设置为合适的名称
sentinel monitor exp-blog.com 127.0.0.1 6379 2    # 标注所监视的主机(其下的从机会被自动拉取,无需配置)
sentinel down-after-milliseconds exp-blog.com 30000
sentinel parallel-syncs exp-blog.com 1
sentinel failover-timeout exp-blog.com 180000

● 哨兵模式配置sentinel-26380.conf下载:https://share.weiyun.com/52UsmNu 密码:fyrtmn ●

哨兵sentinel-26381.conf配置文件内容如下:

bind 127.0.0.1                   # 正式部署请设为合适的IP
port 26381
daemonize yes                    # 后台启动模式(若无配置项则添加)
dir /tmp/redis-ms                # Redis的工作目录(若不存在需手建否则无法启动),logfile受其影响
logfile "sentinel-26381.log"     # 哨兵日志名称(若无配置项则添加),正式部署请设置为合适的名称
sentinel monitor exp-blog.com 127.0.0.1 6379 2    # 标注所监视的主机(其下的从机会被自动拉取,无需配置)
sentinel down-after-milliseconds exp-blog.com 30000
sentinel parallel-syncs exp-blog.com 1
sentinel failover-timeout exp-blog.com 180000

● 哨兵模式配置sentinel-26381.conf下载:https://share.weiyun.com/5muO7vd 密码:8i72bw ●

哨兵sentinel-26382.conf配置文件内容如下:

bind 127.0.0.1                   # 正式部署请设为合适的IP
port 26382
daemonize yes                    # 后台启动模式(若无配置项则添加)
dir /tmp/redis-ms                # Redis的工作目录(若不存在需手建否则无法启动),logfile受其影响
logfile "sentinel-26382.log"     # 哨兵日志名称(若无配置项则添加),正式部署请设置为合适的名称
sentinel monitor exp-blog.com 127.0.0.1 6379 2    # 标注所监视的主机(其下的从机会被自动拉取,无需配置)
sentinel down-after-milliseconds exp-blog.com 30000
sentinel parallel-syncs exp-blog.com 1
sentinel failover-timeout exp-blog.com 180000

● 哨兵模式配置sentinel-26382.conf下载:https://share.weiyun.com/5g6NMkM 密码:db6ugw ●

针对上面几个sentinel-xxxxx.conf配置中的几个关键配置项说明如下:

  • sentinel monitor exp-blog.com 127.0.0.1 6379 2
      监控的主节点的名字为exp-blog.com(这个名字任意的,有效字符为[A-Z] [a-z] [0-9] [._-])
      监控的主节点服务地址127.0.0.1:6379
      行尾最后的2表示当集群中有2个以上sentinel认为主节点下线时,才认为其客观下线
  • sentinel down-after-milliseconds exp-blog.com 30000
      主节点在30000 ms内无反应,哨兵会开始使用“选举机制”进行主从切换
  • sentinel parallel-syncs exp-blog.com 1
      在因主节点失效而发生故障转移(即主从切换)时,最多可以有多少个从节点同时对新的主节点进行并发同步。
      这个数字越小,完成故障转移所需的时间就越长(余下的从节点需要排队等待同步);
      但这个数字越大,就意味着越多的从节点因为正在对新的主节点进行同步而不可用。
      当从节点只用于查询服务时,可将此值设为1确保最多只有一个从节点因同步而不可用。
  • sentinel failover-timeout exp-blog.com 180000
      如果在该180000 ms内未能完成故障转移,则认这次故障转移超时失败。
      不过即使超时,从节点也会正确指向新主节点,但不会按照parallel-syncs规则进行同步

接下来就可以启动Redis主从服务和Sentinel系统了。

启动顺序必须严格按照:

Redis Master(主节点) -> Redis Slave(从节点) -> Redis Sentinel(哨兵节点)

主从服务的启动在上一阶段已经做过了,此处就不重述了。

Sentinel系统需要使用redis-sentinel命令启动:

cd /usr/local/redis-ms/src/                # 切换到启动脚本目录
./redis-sentinel ../sentinel-26380.conf    # 启动Redis哨兵节点
./redis-sentinel ../sentinel-26381.conf    # 启动Redis哨兵节点
./redis-sentinel ../sentinel-26382.conf    # 启动Redis哨兵节点

6.3. 测试

现在测试Sentinel系统是否能正常工作。

可先通过ps -ef|grep redis命令可查看四个主从进程和三个监控进程是否正常启动:

root 3919 1 0 22:08 ? 00:00:02 ./redis-server 127.0.0.1:6379
root 3924 1 0 22:08 ? 00:00:02 ./redis-server 127.0.0.1:6380
root 3930 1 0 22:08 ? 00:00:02 ./redis-server 127.0.0.1:6381
root 3936 1 0 22:08 ? 00:00:02 ./redis-server 127.0.0.1:6382
root 4342 1 0 22:37 ? 00:00:00 ./redis-sentinel 127.0.0.1:26380 [sentinel]
root 4347 1 0 22:37 ? 00:00:00 ./redis-sentinel 127.0.0.1:26381 [sentinel]
root 4383 1 0 22:38 ? 00:00:00 ./redis-sentinel 127.0.0.1:26382 [sentinel]

然后通过Redis测试客户端命令redis-cli连接到任意一台Sentinel机器查看监控信息(实际生产环境中,一般是不需要连接Sentinel机器的):

cd /usr/local/redis-ms/src/             # 切换到启动脚本目录

./redis-cli -h 127.0.0.1 -p 26380        # 连接到哨兵机26380
127.0.0.1:26380> info sentinel           # 查看监控信息

./redis-cli -h 127.0.0.1 -p 26381        # 连接到哨兵机26381
127.0.0.1:26381> info sentinel           # 查看监控信息

./redis-cli -h 127.0.0.1 -p 26382        # 连接到哨兵机26382
127.0.0.1:26382> info sentinel           # 查看监控信息


# 三台哨兵的返回信息是一致的:
sentinel_masters:1     # 监控主机1台
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
# 0号主机名称为exp-blog.com,地址为127.0.0.1:6379,共有三台从机,三台哨兵机
master0:name=exp-blog.com,status=ok,address=127.0.0.1:6379,slaves=3,sentinels=3

现在尝试终止Redis主机进程(6379端口节点)来模拟主机下线:

cd /usr/local/redis-ms/src/             # 切换到启动脚本目录
./redis-cli -h 127.0.0.1 -p 6379        # 连接到Redis主机
127.0.0.1:6379> shutdown                # 终止Redis服务

然后连接到任意一台哨兵机,查看当前的监控信息:

cd /usr/local/redis-ms/src/             # 切换到启动脚本目录
./redis-cli -h 127.0.0.1 -p 26380       # 连接到哨兵机26380
127.0.0.1:26380> info sentinel          # 查看监控信息

# 返回监控信息
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=exp-blog.com,status=ok,address=127.0.0.1:6382,slaves=3,sentinels=3  # 主机地址发生变化了

不难发现主机变成了127.0.0.1:6382,登陆这台主机查看主从信息:

cd /usr/local/redis-ms/src/             # 切换到启动脚本目录
./redis-cli -h 127.0.0.1 -p 6382        # 连接到Redis主机
127.0.0.1:6382> info replication        # 查看主从信息

# 返回主从信息
role:master
connected_slaves:2      # 这台主机下有2台从机
slave0:ip=127.0.0.1,port=6381,state=online,offset=254791,lag=1  # 0号从机是 127.0.0.1:6381
slave1:ip=127.0.0.1,port=6380,state=online,offset=254791,lag=1  # 1号从机是 127.0.0.1:6380

由此可知,当原主机6379下线后,原从机6382被哨兵系统提升为新的主机,而其他的两台从机6380和6381变成新主机6382的从机。此时集群系统变成一主两从。

现在重新启动6379机器:

cd /usr/local/redis-ms/src/           # 切换到启动脚本目录
./redis-server ../redis-6379.conf     # 启动Redis机器

再登陆新主机127.0.0.1:6382查看主从信息:

cd /usr/local/redis-ms/src/             # 切换到启动脚本目录
./redis-cli -h 127.0.0.1 -p 6382        # 连接到Redis主机
127.0.0.1:6382> info replication        # 查看主从信息

# 返回主从信息
role:master
connected_slaves:3      # 这台主机下变成有3台从机
slave0:ip=127.0.0.1,port=6381,state=online,offset=254791,lag=1  # 0号从机是 127.0.0.1:6381
slave1:ip=127.0.0.1,port=6380,state=online,offset=254791,lag=1  # 1号从机是 127.0.0.1:6380
slave2:ip=127.0.0.1,port=6379,state=online,offset=365581,lag=1  # 新挂接的2号从机是 127.0.0.1:6379

由此可知,当6379机器重新上线后,并不会恢复原主机的身份,而是被哨兵系统挂接到新主机6382下,成为其从机。此时集群系统重新变成一主三从。

至此Redis哨兵模式部署完成。

为了开始下一阶段部署,现在先停止前面部署的所有Redis进程:

pkill redis

6.4. 附:哨兵模式一键启动/停止/重启脚本

● 脚本下载:https://share.weiyun.com/5hLLA40 密码:qiwc5g ●

此脚本是根据上文的部署方式和位置编写的,仅适用于Redis节点均在同一台机器的场景。

若要移植到其他地方使用,需要根据实际情况修改。

脚本内容如下:

#!/bin/bash
# 根据主从/哨兵模式的部署目录对应修改
cd /usr/local/redis-ms/src/

# 启动函数
start()
{
  ./redis-server ../redis-6379.conf  &
  ./redis-server ../redis-6380.conf  &
  ./redis-server ../redis-6381.conf  &
  ./redis-server ../redis-6382.conf  &
  ./redis-sentinel ../sentinel-26380.conf  &
  ./redis-sentinel ../sentinel-26381.conf  &
  ./redis-sentinel ../sentinel-26382.conf  &
  echo "all running"
}

# 停止函数
stop()
{
 ps -ef | grep "redis" | grep -v "grep" |awk '{print $2}'| while read pid 
 do
    C_PID=$(ps --no-heading $pid | wc -l)
    if [[ $C_PID == "1" ]]; then
        kill -9 $pid
        echo "PID=$pid is dead"
    else
        echo "PID=$pid not exists"
    fi
 done
 echo "all dead"
}

# 脚本入口参数 start|stop|restart
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
*)
printf 'Usage: %s {start|stop|restart}\n'"$prog"
exit 1
;;
esac

这是shell脚本,保存为redis-mss.sh(文件名任意)即可执行(若无法执行可能是换行符非Linux格式的问题,可尝试通过dos2unix命令修正换行符)。

使用方式如下:

sh redis-mss.sh start    # 启动
sh redis-mss.sh stop     # 停止
sh redis-mss.sh restart  # 重启

7. 集群模式

7.1. 简介

Redis在3.0版本后开始支持集群模式(Redis Cluster),目前官方一直都在维护中,具有代表性,建议优先使用

Redis Cluster是一种服务器Sharding技术,只要将查询请求发送到Redis Cluster中的任意节点,接收到请求的节点会就将查询请求发送到正确的节点上执行:

当Redis客户端操作的key恰好在所查询的Redis节点上时,就像操作Redis单例一样。

当客户端操作的key没有分配到所查询的Redis节点上时,Redis会返回转向指令,指向正确的Redis节点,这类似于浏览器页面的302 重定向跳转

Redis Cluster并没有使用一致性Hash,而是采用slot(槽)的概念,一共分成16384个槽。Redis Cluster要保证16384个槽对应的Redis节点都正常工作,否则一旦某个Redis节点发生故障,那它负责的slots也就失效,整个集群将不能工作。

为了增加集群的高可用性,官方推荐的方案是将Redis节点配置成主从结构,即一个主节点,挂N个从节点。这时,如果主节点失效,Redis Cluster会根据选举算法在从节点中选择一个上升为主节点,整个集群继续对外提供服务。

Redis Cluster的架构模式如下图:

03.png

上图描述的是六个redis实例构成的集群(三主三从),其中:

  • 6379端口为客户端通讯端口
  • 16379端口为集群总线端口
  • 集群内部划分为16384个数据分槽,分布在三个主节点中
  • 从节点没有分槽,不会参与集群投票,也不会提供数据读取服务,仅作为主节点的备份
  • 三个主节点中平均分布着16384数据分槽的三分之一,每个节点中不会存在重复数据,仅仅使用自己的从机帮忙冗余

Redis Cluster具有以下优点

  • 无中心架构,支持动态扩容,对业务透明
  • 具备Sentinel的监控和自动故障迁移能力
  • 高性能,客户端直连Redis服务,免去了Proxy代理的损耗
  • 客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可(实际上是必须连接整个集群的,避免单点故障导致客户端不可用)

Redis Cluster同时也具有以下缺点

  • 部署和运维复杂
  • 数据迁移需要人工干预
  • 只能使用0号数据库
  • 不支持批量操作
  • 分布式逻辑和存储模块耦合

7.2. 部署

下面演示如何部署集群模式

官方推荐Redis Cluster至少需要六个节点,即三主三从

这里准备六个Redis节点,同时为了区分主从/哨兵模式的部署位置,顺便拷贝一下Redis集群节点的目录(以节点端口号区分):

mkdir /usr/local/redis-cluster                                          # 创建Redis集群目录
cp /usr/local/redis-4.0.10/src/redis-trib.rb /usr/local/redis-cluster/  # 集群构建脚本
cp -r /usr/local/redis-4.0.10 /usr/local/redis-cluster/redis-6390       # Redis集群节点目录
cp -r /usr/local/redis-4.0.10 /usr/local/redis-cluster/redis-6391       # Redis集群节点目录
cp -r /usr/local/redis-4.0.10 /usr/local/redis-cluster/redis-6392       # Redis集群节点目录
cp -r /usr/local/redis-4.0.10 /usr/local/redis-cluster/redis-6393       # Redis集群节点目录
cp -r /usr/local/redis-4.0.10 /usr/local/redis-cluster/redis-6394       # Redis集群节点目录
cp -r /usr/local/redis-4.0.10 /usr/local/redis-cluster/redis-6395       # Redis集群节点目录

下文会基于/usr/local/redis-cluster/redis-xxxx目录部署集群模式。

然后配置这六个Redis节点的配置文件,其配置基本相同(主从无需配置,在后面初次构建集群时会自动分配;尔后若添加新节点,可人工指定是主节点还是从节点):

角色 配置文件 服务端口

集群节点 /usr/local/redis-cluster/redis-6390/redis.conf 6390

集群节点 /usr/local/redis-cluster/redis-6391/redis.conf 6391

集群节点 /usr/local/redis-cluster/redis-6392/redis.conf 6392

集群节点 /usr/local/redis-cluster/redis-6393/redis.conf 6393

集群节点 /usr/local/redis-cluster/redis-6394/redis.conf 6394

集群节点 /usr/local/redis-cluster/redis-6395/redis.conf 6395

配置文件/usr/local/redis-cluster/redis-639x/redis.conf的内容如下(仅端口号不同):

bind 127.0.0.1             # 正式部署请设为合适的IP
port 639x
daemonize yes
pidfile /var/run/redis_639x.pid
dir /tmp/redis-cluster      # Redis的工作目录(若不存在需手建否则无法启动),logfile与dbfilename受其影响
logfile "639x.log"          # Redis日志名称(默认不配置,表示输出到stdout),正式部署请设置为合适的名称
dbfilename dump-639x.rdb    # Redis数据持久化时的存储位置,正式部署请设置为合适的名称
cluster-enabled yes                  # 启用集群模式
cluster-config-file nodes-639x.conf  # 集群节点的配置文件,由集群创建,但若同一台主机上的名称需唯一
cluster-node-timeout 15000

● 集群模式配置redis-639x.conf下载:链接:https://share.weiyun.com/5YJ5V6S 密码:2fha9v ●

新建上面配置的Redis集群工作目录:

mkdir /tmp/redis-cluster

然后使用redis-server命令启动六个Redis节点:

cd /usr/local/redis-cluster/redis-6390/src/   # 切换到Redis-6390节点的启动脚本目录
./redis-server ../redis.conf                  # 启动Redis节点

cd /usr/local/redis-cluster/redis-6391/src/   # 切换到Redis-6391节点的启动脚本目录
./redis-server ../redis.conf                  # 启动Redis节点

cd /usr/local/redis-cluster/redis-6392/src/   # 切换到Redis-6392节点的启动脚本目录
./redis-server ../redis.conf                  # 启动Redis节点

cd /usr/local/redis-cluster/redis-6393/src/   # 切换到Redis-6393节点的启动脚本目录
./redis-server ../redis.conf                  # 启动Redis节点

cd /usr/local/redis-cluster/redis-6394/src/   # 切换到Redis-6394节点的启动脚本目录
./redis-server ../redis.conf                  # 启动Redis节点

cd /usr/local/redis-cluster/redis-6395/src/   # 切换到Redis-6395节点的启动脚本目录
./redis-server ../redis.conf                  # 启动Redis节点

先通过ps -ef|grep redis命令可查看六个节点进程是否正常启动:

root 20305 1 0 01:41 ? 00:00:00 ./redis-server 127.0.0.1:6390 [cluster]
root 20320 1 0 01:43 ? 00:00:00 ./redis-server 127.0.0.1:6391 [cluster]
root 20325 1 0 01:43 ? 00:00:00 ./redis-server 127.0.0.1:6392 [cluster]
root 20330 1 0 01:43 ? 00:00:00 ./redis-server 127.0.0.1:6393 [cluster]
root 20335 1 0 01:43 ? 00:00:00 ./redis-server 127.0.0.1:6394 [cluster]
root 20340 1 0 01:43 ? 00:00:00 ./redis-server 127.0.0.1:6395 [cluster]

然后使用Redis官方提供的工具redis-trib.rb(注意:这个是ruby脚本,需要安装相关支持库,否则无法运行)把这6个节点组建成集群(注意:若集群节点分布在多台不同的机器上,只需其中一个机器执行这条命令即可,但要包含所有机器的集群节点):

cd /usr/local/redis-cluster/         # 切换到集群构建脚本目录
./redis-trib.rb create --replicas 1 127.0.0.1:6390 127.0.0.1:6391 127.0.0.1:6392 127.0.0.1:6393 127.0.0.1:6394 127.0.0.1:6395

若以后机器IP发生变更,需要重新执行此命令重建集群(重建集群需要先停止集群中所有节点进程,然后删除原集群中所有节点的node.conf文件,最后按照上文步骤构建集群即可)。

此时Redis会返回正在构建的集群信息,返回的信息大概意思是“正在把slots槽位分配到6个节点的集群,其中6390、6391、6392是主节点,6394是6390的从节点,6395是6391的从节点,6393是6392的从节点”。

这里的主从分配是自动的,若确认无误则输入yes:

>>> Creating cluster
>>> Performing hash slots allocation on 6 nodes…
Using 3 masters:     # 三主
127.0.0.1:6390
127.0.0.1:6391
127.0.0.1:6392
Adding replica 127.0.0.1:6394 to 127.0.0.1:6390    # 三从
Adding replica 127.0.0.1:6395 to 127.0.0.1:6391
Adding replica 127.0.0.1:6393 to 127.0.0.1:6392
>>> Trying to optimize slaves allocation for anti-affinity
[WARNING] Some slaves are in the same host as their master
M: ac2520bab97d151897afb5e6f3ca60a673010227 127.0.0.1:6390
slots:0-5460 (5461 slots) master
M: 3768ff79e3e58a0ee9c1fef1ab04e7e395196fa8 127.0.0.1:6391
slots:5461-10922 (5462 slots) master
M: ac19a87740dc0f0559f10cd1eae617cfcd51b04a 127.0.0.1:6392
slots:10923-16383 (5461 slots) master
S: d93d05facb7db5c223d0959a0e58d232334057e4 127.0.0.1:6393
replicates 3768ff79e3e58a0ee9c1fef1ab04e7e395196fa8
S: 69546e0a773b6548a37c5d55329eac575c5d7cca 127.0.0.1:6394
replicates ac19a87740dc0f0559f10cd1eae617cfcd51b04a
S: ab7405fc14dbc4e883644bccc6d8602992780b44 127.0.0.1:6395
replicates ac2520bab97d151897afb5e6f3ca60a673010227
Can I set the above configuration? (type "yes" to accept): yes    # 若确认无误则输入yes

若构建集群成功,则会返回集群内这6个节点的信息:

>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join….
>>> Performing Cluster Check (using node 127.0.0.1:6390)
M: ac2520bab97d151897afb5e6f3ca60a673010227 127.0.0.1:6390
slots:0-5460 (5461 slots) master
1 additional replica(s)
M: 3768ff79e3e58a0ee9c1fef1ab04e7e395196fa8 127.0.0.1:6391
slots:5461-10922 (5462 slots) master
1 additional replica(s)
S: 69546e0a773b6548a37c5d55329eac575c5d7cca 127.0.0.1:6394
slots: (0 slots) slave
replicates ac19a87740dc0f0559f10cd1eae617cfcd51b04a
M: ac19a87740dc0f0559f10cd1eae617cfcd51b04a 127.0.0.1:6392
slots:10923-16383 (5461 slots) master
1 additional replica(s)
S: ab7405fc14dbc4e883644bccc6d8602992780b44 127.0.0.1:6395
slots: (0 slots) slave
replicates ac2520bab97d151897afb5e6f3ca60a673010227
S: d93d05facb7db5c223d0959a0e58d232334057e4 127.0.0.1:6393
slots: (0 slots) slave
replicates 3768ff79e3e58a0ee9c1fef1ab04e7e395196fa8
[OK] All nodes agree about slots configuration.
>>> Check for open slots…
>>> Check slots coverage…
[OK] All 16384 slots covered.

7.3. 测试

现在测试Redis Cluster是否能正常工作。

通过Redis测试客户端命令redis-cli连接到集群任意一个节点:

cd /usr/local/redis-4.0.10/src/           # 切换到启动脚本目录
./redis-cli -c -h 127.0.0.1 -p 6390       # 以集群方式连接到Redis-6390节点

这里需要注意,与前面单机/主从/哨兵模式不同的是,客户端命令redis-cli需要增加一个-c参数,表示是连接到集群,这样客户端的读写行为才是在整个集群中可见的。

若不加-c参数虽然也可连接,但是仅仅是连接到当前的节点,是无法进行数据读写的(除非所读写的数据的键值,经过Hash计算得到的slot槽号,刚好在这个节点里面)。

现在在6390节点执行get命令,获取键名为site的数据:

127.0.0.1:6390> get site
(nil)                  # 由于是新部署的Redis集群,该键值必定不存在

然后在6390节点写入数据(执行set命令,为键site设置数据):

127.0.0.1:6390> set site http://exp-blog.com

再通过Redis测试客户端命令redis-cli连接到集群另一个节点:

cd /usr/local/redis-4.0.10/src/           # 切换到启动脚本目录
./redis-cli -c -h 127.0.0.1 -p 6395       # 以集群方式连接到Redis-6395节点

在6395节点执行get命令,获取键名为site的数据(经过集群节点转发请求,可以取到数据):

127.0.0.1:6395> get site
"http://exp-blog.com"

现在尝试一下不以集群方式连接到节点6395,会发生什么:

cd /usr/local/redis-4.0.10/src/               # 切换到启动脚本目录
./redis-cli -h 127.0.0.1 -p 6395              # 以单点方式连接到Redis-6395节点(无-c参数)

127.0.0.1:6395> get site                      # 获取键值为site的数据
(error) MOVED 9421 127.0.0.1:6392             # 报错:该数据在6392节点的9421槽位

127.0.0.1:6395> set site http://exp-blog.com  # 设置键为site的值
(error) MOVED 9421 127.0.0.1:6392             # 报错:该键应该设置到6392节点的9421槽位

# 有些版本的报错信息是这样的,意思是相同的:
# -> Redirected to slot [9421] located at 127.0.0.1:6392

之所以会发生这种情况,其实最开始的Redis Cluster架构介绍的时候就已经解释了原因了:

Redis Cluster没有使用一致性Hash,而是采用slot(槽)的概念,一共分成16384个槽。在构建集群时,这些槽会不重复地平均被分配到集群中的主节点。

在读写数据时,Redis Cluster会先计算该数据的键值的slot号,然后再把读写请求分配到该slot号所属的Redis节点。

而当不以集群方式连接到集群节点时,在计算slot号后,读写请求的分配工作却无法执行,就会出现上述报错。

7.4. 集群的关闭/重启

Redis Cluster的官方文档并没有提供整个集群的关闭与重启的方法。推测可能是由于集群所有节点同时挂掉的可能性不高,毕竟即使偶尔集群中某个节点挂掉了,待其重启后又会自动重新加入集群,并不会带来太大影响。

但是可能性不高并不代表不会发生,如何关闭/重启整个集群的方式还是需要知道的。

集群的关闭,执行这个命令即可(如果是部署到多台IP机器,需要登陆到每一台机器执行):

pkill redis        # 是的,直接杀掉集群的全部节点进程就可以了

集群的重启,只需要重新启动原集群中每一个节点就可以了,集群会自动恢复到关闭之前的状态(前提是不能删除node-*.conf、*.aof、*.rdb文件,否则会造成集群数据丢失)。

至此Redis Cluster集群模式部署完成。

7.5. 附:集群模式一键启动/停止/重启脚本

● 脚本下载:https://share.weiyun.com/5Q9lCkE 密码:aby4vq ●

此脚本是根据上文的部署方式和位置编写的,仅适用于Redis节点均在同一台机器的场景。

若要移植到其他地方使用,需要根据实际情况修改。

脚本内容如下:

#!/bin/bash
# 根据主从/哨兵模式的部署目录对应修改
export cluster_path=/usr/local/redis-cluster

# 启动函数
start()
{
  ${cluster_path}/redis-6390/src/redis-server ${cluster_path}/redis-6390/redis.conf  &
  ${cluster_path}/redis-6391/src/redis-server ${cluster_path}/redis-6391/redis.conf  &
  ${cluster_path}/redis-6392/src/redis-server ${cluster_path}/redis-6392/redis.conf  &
  ${cluster_path}/redis-6393/src/redis-server ${cluster_path}/redis-6393/redis.conf  &
  ${cluster_path}/redis-6394/src/redis-server ${cluster_path}/redis-6394/redis.conf  &
  ${cluster_path}/redis-6395/src/redis-server ${cluster_path}/redis-6395/redis.conf  &
  echo "all running"
}

# 停止函数
stop()
{
 ps -ef | grep "redis" | grep -v "grep" |awk '{print $2}'| while read pid 
 do
    C_PID=$(ps --no-heading $pid | wc -l)
    if [[ $C_PID == "1" ]]; then
        kill -9 $pid
        echo "PID=$pid is dead"
    else
        echo "PID=$pid not exists"
    fi
 done
 echo "all dead"
}

# 脚本入口参数 start|stop|restart
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
*)
printf 'Usage: %s {start|stop|restart}\n'"$prog"
exit 1
;;
esac

这是shell脚本,保存为redis-cluster.sh(文件名任意)即可执行(若无法执行可能是换行符问题,可尝试通过dos2unix命令修正换行符)。

使用方式如下:

sh redis-cluster.sh start    # 启动
sh redis-cluster.sh stop     # 停止
sh redis-cluster.sh restart  # 重启

8. 附:Redis核心配置文件汉化版注释

8.1. 服务配置redis.conf

● 汉化配置文件redis-chs.conf下载:https://share.weiyun.com/57e0NrS 密码:m48s6g ●

8.2. 哨兵配置sentinel.conf

● 汉化配置文件sentinel-chs.conf下载:https://share.weiyun.com/5eFlsU6 密码:4vr68i ●

9. 附:Jedis客户端封装

官方提供的Jedis的POM如下:

<dependency>
  <groupId>redis.clients</groupId>
  <artifactId>jedis</artifactId>
  <version>2.9.0</version>
</dependency>

Jedis是在Java中比较强大的Redis客户端连接工具,暴露了很多Redis的API接口,能够很灵活地操作Redis。但是也正由于暴露了太多Redis的连接细节、过份灵活,在生产环境中使用并不方便。

为了解决这些缺点,使之更易于使用,我在2.9.0版本之上做了封装,其主要特点有:

  • 屏蔽Jedis与JedisCluster的连接细节和差异,统一封装成RedisClient类,并内置连接池
  • 统一Jedis与JedisCluster连接的配置项,封装成RedisBean类,主要供RedisClient使用
  • 屏蔽byte[]数据类型,所有实现了序列化接口的对象均可直接在Redis进行读写
  • 保留String数据类型(并不会序列化成byte[],目的是保留与其他程序交互数据的方式)
  • 把Redis的Map封装成RedisMap<T>类(key强制为String),暴露API模仿Java的Map
  • 把Redis的Set封装成RedisSet<T>类,暴露API模仿Java的Set
  • 把Redis的List封装成RedisList<T>类,暴露API模仿Java的List
  • 把Redis的单键值对封装成RedisObj<T>类

下面是各个场景的使用样例演示(源码见Github):

import exp.libs.warp.db.redis.RedisClient;
import exp.libs.warp.db.redis.bean.RedisList;
import exp.libs.warp.db.redis.bean.RedisMap;
import exp.libs.warp.db.redis.bean.RedisObj;
import exp.libs.warp.db.redis.bean.RedisSet;

/**
 * <PRE>
 * RedisClient测试/场景演示.
 * </PRE>
 * <B>PROJECT : </B> exp-libs
 * <B>SUPPORT : </B> <a href="http://www.exp-blog.com" target="_blank">www.exp-blog.com</a> 
 * @version   2018-07-31
 * @author    EXP: [email protected]
 * @since     jdk版本:jdk1.6
 */
public class TestRedisClient {

    public static void main(String[] args) {

        /*********************** Redis连接样例 ***********************/

        // 场景1  -  Redis 单机模式
        // 127.0.0.1:6379
        RedisClient redis = new RedisClient("127.0.0.1", 6379);

        // 场景2  -  Redis 主从模式 
        // (若用于[读写]只能连接主机,若仅[读]则可连接主/从,但无论如何只能连接其中一台)
        // 主机: 127.0.0.1:6379
        // 从机: 127.0.0.1:6380, 127.0.0.1:6381, 127.0.0.1:6382
        redis = new RedisClient("127.0.0.1", 6379);

        // 场景3  -  Redis 哨兵模式 
        // (若用于[读写]只能连接主机,若仅[读]则可连接主/从,但无论如何只能连接其中一台,哨兵不允许连接)
        // 主机: 127.0.0.1:6379
        // 从机: 127.0.0.1:6380, 127.0.0.1:6381, 127.0.0.1:6382
        // 哨兵: 127.0.0.1:26380, 127.0.0.1:26381, 127.0.0.1:26382
        redis = new RedisClient("127.0.0.1", 6379);

        // 场景4  -  Redis 集群模式
        // 集群节点 (需同时连接所有节点):
        //   127.0.0.1:6390, 127.0.0.1:6391, 127.0.0.1:6392
        //   127.0.0.1:6393, 127.0.0.1:6394, 127.0.0.1:6395
        redis = new RedisClient(
                "127.0.0.1:6390", "127.0.0.1:6391", 
                "127.0.0.1:6392", "127.0.0.1:6393", 
                "127.0.0.1:6394", "127.0.0.1:6395"
        );

        /*********************** Redis操作样例 ***********************/

        // RedisMap示例
        final String REDIS_MAP_KEY = "REDIS_MAP_KEY";    // 这个Map对象在Redis中的键值
        RedisMap<SerialObject> map = new RedisMap<SerialObject>(REDIS_MAP_KEY, redis);
        map.put("site", new SerialObject(1, "http://exp-blog.com"));
        map.put("mail", new SerialObject(2, "[email protected]"));
        System.out.println(map.size());
        System.out.println(map.get("site"));
        System.out.println(map.get("mail"));
        map.clear();

        // RedisList示例
        final String REDIS_LIST_KEY = "REDIS_LIST_KEY";    // 这个List对象在Redis中的键值
        RedisList<SerialObject> list = new RedisList<SerialObject>(REDIS_LIST_KEY, redis);
        list.add(new SerialObject(3, "EXP-LIST"));
        System.out.println(list.size());
        System.out.println(list.get(0));
        list.clear();    

        // RedisSet示例
        final String REDIS_SET_KEY = "REDIS_SET_KEY";    // 这个Set对象在Redis中的键值
        RedisSet<SerialObject> set = new RedisSet<SerialObject>(REDIS_SET_KEY, redis);
        set.add(new SerialObject(4, "http://exp-blog.com"));
        set.add(new SerialObject(5, "[email protected]"));
        System.out.println(set.size());
        System.out.println(set.getRandom());
        set.clear();

        // RedisObj示例
        final String REDIS_OBJ_KEY = "REDIS_OBJ_KEY";    // 这个Obj对象在Redis中的键值
        RedisObj<SerialObject> obj = new RedisObj<SerialObject>(REDIS_OBJ_KEY, redis);
        obj.set(new SerialObject(6, "EXP-OBJ"));
        System.out.println(obj.exists());
        System.out.println(obj.get());
        obj.clear();


        // 断开redis连接
        redis.close();
    }


    /**
     * <pre>
     * 测试用的序列化对象.
     * 必须实现java.io.Serializable接口
     * </pre>
     */
    private static class SerialObject implements Serializable {

        private static final long serialVersionUID = -6911765769239092862L;

        private int id;

        private String value;

        private SerialObject(int id, String value) {
            this.id = id;
            this.value = value;
        }

        public String toString() {
            return id + ":" + value;
        }

    }

}

10. 资源下载


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK