1. 目标

  • 介绍Redis的主从部署、哨兵部署与多主集群部署模式
  • 实现Redis主从与哨兵集群部署,以及多主集群模式的搭建配置

2. 脉络

  • 介绍Redis的所有部署模式,特点与使用场景
  • 完成Redis主从与哨兵集群部署
  • 完成Redis多主集群模式部署
  • 应用项目与集群的连接配置

3. 知行

3.1 Redis部署模式简介

Redis部署模式有多种, 包括单节点模式, 主从模式, 主从+哨兵模式, 以及集群模式。

  • Redis单节点模式
    安装简单,客户端直连, 操作简便; 不存在多节点数据同步或脑裂问题, 在开发环境中可直接采用单节点模式, 简化维护。如果应用服务规模比较小, 可以直接采用单节点单机部署。
  • Another Redis Desktop Manager哨兵模式_IP

  • 主从模式
    单节点模式部署主要存在两个问题: 数据备份和数据体量较大造成的性能降低,主从模式指的是使用一个redis实例作为主机,其余的实例作为备份机, 主节点负责读写, 从节点专门负责数据的读取。
    主从同步机制: 从节点启动后, 主动向master发送SYNC命令, 主节点接收到SYNC命令后在后台保存快照, 将保存的快照文件和期间的缓存操作指令发送给从节点。
    如果具有一定数据规模和性能要求, 可以采用主从模式,
  • Another Redis Desktop Manager哨兵模式_IP_02

  • 哨兵模式

主从模式下, 如果主节点出现故障,从节点因为没有主节点同步而中断, 需要人工进行故障处理。Sentinel哨兵模式是Redis推出的原生高可用解决方案, 主要包括两部分, Sentinel集群和Redis主从集群。

哨兵的功能主要是监控主从节点运行是否正常, 当master主节点出现故障时, 会自动将slave从节点转化为主节点。 要求较高的稳定性和高可用性, 可采用哨兵模式。

Another Redis Desktop Manager哨兵模式_redis_03

  • 集群模式
    主从和哨兵模式虽然解决了一定的性能和数据瓶颈, 但是对于大量的写操作场景, 还是不能满足, 如果对于从节点出现故障, 哨兵模式是不会对其进行故障转移, 因此在Redis3.0版本推出了cluster集群功能, 能够有效解决这些问题。
    Cluster集群处理机制: 集群总共定义了16384个槽(slot),所有数据根据一致性哈希算法映射到某个槽中, 16384个槽根据Redis实例数量进行平均分配, 比如有A、B、C三个实例, 集群会将0-5460号槽分配给A,5461-10922号槽分配给B,10923-16383号槽分配给C。由于一致hash算法是一定的, 无论多少个redis实例,都可以将这16384个槽散列平均分配。Redis集群通过这种机制,来达到高性能和高可用性。
    在大型项目应用中,具有海量数据规模, 要求较高的稳定性和扩展性, 可以采用集群模式。
  • Another Redis Desktop Manager哨兵模式_Redis_04

3.2 Redis哨兵模式部署
3.2.1 部署规划

Redis主从部署:

20.20.50.26: Redis主节点, 端口6379

20.20.50.27: Redis从节点, 端口6379

20.20.50.28: Redis从节点, 端口6379

哨兵部署:

20.20.50.26: 哨兵节点一, 端口26379

20.20.50.27: 哨兵节点二, 端口26379

20.20.50.28: 哨兵节点三, 端口26379

3.2.2 Redis安装

先将Redis服务安装在三台节点上。

  1. 安装依赖组件
yum -y install tcl gcc
  1. 下载安装包
wget http://download.redis.io/releases/redis-4.0.2.tar.gz
  1. 解压
tar -xvf redis-4.0.2.tar.gz
  1. 编译安装
cd redis-4.0.2
make
make install

如果make 错误, 可以执行make distclean 清理, 再重新make编译。

安装成功, 可以看到以下提示:

Hint: It's a good idea to run 'make test' ;)
    INSTALL install
    INSTALL install
    INSTALL install
    INSTALL install
    INSTALL install
  1. 配置
  • 复制启动脚本
cp utils/redis_init_script /etc/init.d/redis_6379
  • 复制配置文件
mkdir -p /etc/redis
cp redis.conf /etc/redis/6379.conf
  • 修改配置文件:
vi /etc/redis/6379.conf
  • 修改内容:
# 后台方式运行
daemonize yes
# PID文件保存位置
pidfile /var/run/redis_6379.pid
# Redis服务监听端口
port 6379
# 持久化文件存储路径, 如果没有此目录, 则创建: make -p /var/redis/6379
dir /var/redis/6379
# 绑定IP地址, 如果要远程连接, 需要绑定外部IP地址, 可以绑定多个, 以空格分隔
bind 127.0.0.1
  • 设置开机启动
    修改启动脚本:
vi /etc/init.d/redis_6379

在头部增加:

#!/bin/sh
# chkconfig: 2345 90 10
  • 启动与关闭
/etc/init.d/redis_6379 start
/etc/init.d/redis_6379 stop
3.2.3 主从创建

这里20.20.50.26为主节点, 将20.20.50.27与20.20.50.28作为从节点, 纳入集群。

  1. 手动创建
  • 进入20.20.50.27
    执行以下命令:
[root@localhost local]# redis-cli  -p 6379
127.0.0.1:6379> slaveof 20.20.50.26 6379
OK Already connected to specified master
  • 进入20.20.50.28
    执行相同命令, 加入集群:
[root@localhost local]# redis-cli  -p 6379
127.0.0.1:6379> slaveof 20.20.50.26 6379
OK Already connected to specified master
  • 进入20.20.50.26主节点, 验证查看集群信息:
[root@localhost redis-4.0.2]# redis-cli 
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=20.20.50.28,port=6379,state=online,offset=2617,lag=0
slave1:ip=20.20.50.27,port=6379,state=online,offset=2617,lag=0
master_replid:c41563977b922b3877b4c470743efd1feb26099a
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:2617
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:2617

可以看到, connected_slaves显示连接的从节点数量为2, 三台节点成功组建主从集群。

  1. 配置自动创建
    通过配置方式, 自动创建, 不需每次重启后, 都执行加入命令。
vi /etc/redis/6379.conf

增加配置:

slaveof 20.20.50.26 6379
  1. 验证
    在从节点是无法写入数据:
[root@localhost redis-4.0.2]# redis-cli -h 20.20.50.28 -p 6379
20.20.50.28:6379> set test 123
(error) READONLY You can't write against a read only slave.

在20.20.50.26主节点, 可以写入数据:

127.0.0.1:6379> set test 123
OK

从节点查询是否能同步数据:

[root@localhost redis-4.0.2]# redis-cli -h 20.20.50.28 -p 6379
20.20.50.28:6379> get test
"123"
3.2.4 哨兵配置

在三台节点, 分别执行以下配置。

  1. 复制哨兵配置文件
cp /usr/local/redis-4.0.2/sentinel.conf /etc/redis/
  1. 修改配置文件
echo > /etc/redis/sentinel.conf
vi /etc/redis/sentinel.conf

增加以下内容:

# 绑定IP地址, 注意绑定IP时,要将外部通讯IP放置前面, 否则会出现找不到sentinel节点的情况
bind 20.20.50.26 127.0.0.1
# 绑定监听的端口
port 26379
# 是否开启保护模式, 如果绑定外部IP, 需要关闭访问保护
protected-mode no
# 后台方式运行
daemonize yes

# sentinel监控配置
sentinel monitor mymaster  20.20.50.26 6379 2
sentinel down-after-milliseconds mymaster  15000
sentinel parallel-syncs mymaster  1
sentinel failover-timeout mymaster  30000

配置说明:

sentinel monitor mymaster 20.20.50.26 6379 2: Sentinel去监视一个名为redis_master的主redis实例,IP地址为20.20.50.26,端口号为6379,将这个主实例判断为失效至少需要2个 Sentinel进程的同意。

sentinel down-after-milliseconds mymaster :指定了Sentinel认为Redis实例已经失效所需的毫秒数。当实例超过该时间没有返回PING,或者直接返回错误,那么Sentinel将这个实例标记为主观下线。

sentinel parallel-syncs mymaster 1:指定在执行故障转移时,最多有多少个从Redis实例在同步新的主实例,在从Redis实例较多的情况下这个数字越小,同步的时间越长,完成故障转移所需的时间就越长。

sentinel failover-timeout mymaster 30000:如果在该时间(ms)内未能完成failover操作,则认为该failover失败。

  1. 启动哨兵
    在三台节点分别配置完成以后, 再执行启动命令:
redis-sentinel /etc/redis/sentinel.conf

如果出现警告提示:

WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.

修改:

vi /etc/sysctl.conf
net.core.somaxconn=32768
sysctl -p
  1. 查看哨兵集群状态
[root@localhost ~]# redis-cli  -p 26379
127.0.0.1:26379> info sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=20.20.50.26:6379,slaves=2,sentinels=3

可以看到sentinel_masters数为1, sentinels总数为3,哨兵集群搭建成功。

3.2.5 哨兵功能验证
  1. 先进入哨兵集群, 查看当前状态
[root@localhost ~]# redis-cli  -p 26379
127.0.0.1:26379> info sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=20.20.50.26:6379,slaves=2,sentinels=3
  1. 停止Redis主节点服务, 再此查看状态信息
[root@localhost ~]# /etc/init.d/redis_6379 stop
Stopping ...
Waiting for Redis to shutdown ...
Redis stopped

查看哨兵集群信息(间隔数秒)

127.0.0.1:26379> info sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=20.20.50.27:6379,slaves=2,sentinels=3

可以看到, Redis主节点已经从20.20.50.26转移至20.20.50.27服务器上。

  1. 验证单个哨兵节点的有效性
    我们在哨兵配置中, sentinel monitor mymaster 20.20.50.26 6379 2 , 将哨兵投票数量设为2, 如果只存在1个哨兵节点, 是无法重新进行选主, 我们做个验证。
  • 恢复Redis主从三个节点, 正常运行
[root@localhost ~]# /etc/init.d/redis_6379 start
Starting Redis server...
  • 查看当前哨兵状态:
127.0.0.1:26379> info sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=20.20.50.27:6379,slaves=2,sentinels=3

可以看到, 当前Redis主节点为20.20.50.27。

  • 停止两个哨兵节点
    停止20.20.50.27上的哨兵服务:
redis-cli -p 26379 shutdown

停止20.20.50.28上的哨兵服务:

redis-cli -p 26379 shutdown
  • 停止20.20.50.27节点上的Redis服务
[root@localhost ~]# /etc/init.d/redis_6379 stop
Stopping ...
Waiting for Redis to shutdown ...
Redis stopped
  • 再次查看哨兵状态
127.0.0.1:26379> info sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=sdown,address=20.20.50.27:6379,slaves=2,sentinels=1

状态变为sdown, 但没有选举新的Redis主节点, 整个哨兵集群数量不够, 没有生效。

3.3 Redis集群模式部署
3.3.1 部署规划

Redis主从部署:

20.20.50.26: Redis主节点, 端口7000; Redis从节点, 端口7001。

20.20.50.27: Redis从节点, 端口7000; Redis从节点, 端口7001。

20.20.50.28: Redis从节点, 端口7000; Redis从节点, 端口7001。

3.3.2 Redis安装

参考上面3.2.2章节Redis安装, 确保Redis已成功安装。

3.3.3 Ruby安装

Redis集群创建工具需要依赖Ruby, 如果已安装, 并且版本在2.4.5以上, 可以忽略此步骤。

注意重新建立会话, 要使用ruby, 需要通过命令开启: scl enable rh-ruby24 bash

  1. 安装YUM源
yum install -y centos-release-scl-rh
  1. 安装ruby2.4以上版本
yum  -y install rh-ruby24
  1. scl开启
scl enable rh-ruby24 bash

如果重新建立会话, 要再次开启。

  1. 查看ruby版本
[root@localhost src]# ruby -v
ruby 2.4.6p354 (2019-04-01 revision 67394) [x86_64-linux]
[root@localhost src]# gem -v
2.6.14.4
  1. gen安装redis插件
[root@localhost src]# gem install redis
Fetching: redis-4.1.3.gem (100%)
Successfully installed redis-4.1.3
Parsing documentation for redis-4.1.3
Installing ri documentation for redis-4.1.3
Done installing documentation for redis after 1 seconds
1 gem installed
3.3.4 集群安装配置
  1. 分别在三台节点上创建集群目录
mkdir -p /usr/local/redis_cluster/7000/
mkdir -p /usr/local/redis_cluster/7001/
  1. 集群配置文件
    在每台节点上创建主从两个节点的配置文件:
vi /etc/redis/cluster-7000.conf

7000端口节点的配置内容:

# 绑定IP, 注意改成对应不同节点的IP地址
bind 20.20.50.26
port 7000
# 客户端连接密码
requirepass Redis1234{}
# 集群连接密码
masterauth Redis1234{}
# 是否后台运行
daemonize yes
pidfile /usr/local/redis_cluster/7000/redis.pid
appendonly yes
appendfilename "appendonly_7000.aof"
dir /usr/local/redis_cluster/7000/
dbfilename "dump_7000.rdb"
protected-mode no

cluster-enabled yes
cluster-config-file /usr/local/redis_cluster/7000/nodes.conf
# 集群超时时间
cluster-node-timeout 5000
# 表示负责一个插槽的主库下线且没有相应的从库进行故障恢复时,集群仍然可用
cluster-require-full-coverage no
maxmemory 100mb
# 缓存更新策略, 优先删除掉最近最不经常使用的key
maxmemory-policy allkeys-lru
maxclients 10000

继续增加7001的配置:

vi /etc/redis/cluster-7001.conf

配置内容:

bind 20.20.50.26
port 7001
# 客户端连接密码
requirepass Redis1234{}
# 集群连接密码
masterauth Redis1234{}
# 是否后台运行
daemonize yes
pidfile /usr/local/redis_cluster/7001/redis.pid
appendonly yes
appendfilename "appendonly_7001.aof"
dir /usr/local/redis_cluster/7001/
dbfilename "dump_7001.rdb"
protected-mode no

cluster-enabled yes
cluster-config-file /usr/local/redis_cluster/7001/nodes.conf
# 集群超时时间
cluster-node-timeout 5000
# 表示负责一个插槽的主库下线且没有相应的从库进行故障恢复时,集群仍然可用
cluster-require-full-coverage no
maxmemory 100mb
# 缓存更新策略, 优先删除掉最近最不经常使用的key
maxmemory-policy allkeys-lru
maxclients 10000
  1. 启动各集群节点
redis-server /etc/redis/cluster-7000.conf 
redis-server /etc/redis/cluster-7001.conf

查看进程:

[root@localhost ~]# ps -ef | grep cluster
root      32933      1  0 00:01 ?        00:00:05 redis-server 20.20.50.26:7000 [cluster]
root      33038      1  0 00:03 ?        00:00:04 redis-server 20.20.50.26:7001 [cluster]
3.3.5 集群创建
  1. 执行命令
cd /usr/local/redis-4.0.2/src
./redis-trib.rb  create  --replicas  1  20.20.50.26:7000 20.20.50.26:7001  20.20.50.27:7000 20.20.50.27:7001  20.20.50.28:7000  20.20.50.28:7001

如果出现不能连接创建的错误:

[ERR] Sorry, can't connect to node 20.20.50.26:7000

先确保ruby的redis插件已安装, 检查所有节点是否都已正常启动。

gem install redis

如果还是出现错误, 需要修改ruby的redis配置文件, 加上认证密码:

vi /opt/rh/rh-ruby24/root/usr/local/share/gems/gems/redis-4.1.3/lib/redis/client.rb

修改:

class Redis
  class Client

    DEFAULTS = {
      :url => lambda { ENV["REDIS_URL"] },
      :scheme => "redis",
      :host => "127.0.0.1",
      :port => 6379,
      :path => nil,
      :timeout => 5.0,
      :password => "Redis1234{}",

确认password输入正确。

  1. 再次执行集群创建命令
[root@localhost src]# ./redis-trib.rb  create  --replicas  1  20.20.50.26:7000 20.20.50.26:7001  20.20.50.27:7000 20.20.50.27:7001  20.20.50.28:7000  20.20.50.28:7001
>>> Creating cluster
>>> Performing hash slots allocation on 6 nodes...
Using 3 masters:
20.20.50.26:7000
20.20.50.27:7000
20.20.50.28:7000
Adding replica 20.20.50.27:7001 to 20.20.50.26:7000
Adding replica 20.20.50.26:7001 to 20.20.50.27:7000
Adding replica 20.20.50.28:7001 to 20.20.50.28:7000
M: 770036cb37f3fd9623e79b677e032488d307929e 20.20.50.26:7000
   slots:0-5460 (5461 slots) master
S: b88106a9c1da2ccf706f0348527c5c411ce53276 20.20.50.26:7001
   replicates f75cf9009d46f462b34c917fec35c9307a0f3778
M: f75cf9009d46f462b34c917fec35c9307a0f3778 20.20.50.27:7000
   slots:5461-10922 (5462 slots) master
S: 82ff87e5f73422a213951467b70fbc409bc68e51 20.20.50.27:7001
   replicates 770036cb37f3fd9623e79b677e032488d307929e
M: b3687887df3db9333c455044866dbaa21b786fc9 20.20.50.28:7000
   slots:10923-16383 (5461 slots) master
S: 0cfa4bdcd26c5a974ef64b606452bcf70de5d7b9 20.20.50.28:7001
   replicates b3687887df3db9333c455044866dbaa21b786fc9
Can I set the above configuration? (type 'yes' to accept): yes
>>> 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 20.20.50.26:7000)
M: 770036cb37f3fd9623e79b677e032488d307929e 20.20.50.26:7000
   slots:0-5460 (5461 slots) master
   1 additional replica(s)
M: f75cf9009d46f462b34c917fec35c9307a0f3778 20.20.50.27:7000
   slots:5461-10922 (5462 slots) master
   1 additional replica(s)
S: b88106a9c1da2ccf706f0348527c5c411ce53276 20.20.50.26:7001
   slots: (0 slots) slave
   replicates f75cf9009d46f462b34c917fec35c9307a0f3778
S: 0cfa4bdcd26c5a974ef64b606452bcf70de5d7b9 20.20.50.28:7001
   slots: (0 slots) slave
   replicates b3687887df3db9333c455044866dbaa21b786fc9
S: 82ff87e5f73422a213951467b70fbc409bc68e51 20.20.50.27:7001
   slots: (0 slots) slave
   replicates 770036cb37f3fd9623e79b677e032488d307929e
M: b3687887df3db9333c455044866dbaa21b786fc9 20.20.50.28:7000
   slots:10923-16383 (5461 slots) master
   1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

按提示选择yes继续处理, 可以在最后面看到所有slots分配成功的提示。

  1. 集群的信息查看
    连接到集群节点:
redis-cli -h 20.20.50.26  -p 7000

查看集群状态信息:

20.20.50.26:7000> cluster info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:13
cluster_my_epoch:10
cluster_stats_messages_ping_sent:6837
cluster_stats_messages_pong_sent:5196
cluster_stats_messages_fail_sent:64
cluster_stats_messages_auth-req_sent:5
cluster_stats_messages_auth-ack_sent:3
cluster_stats_messages_sent:12105
cluster_stats_messages_ping_received:5193
cluster_stats_messages_pong_received:5529
cluster_stats_messages_fail_received:30
cluster_stats_messages_auth-req_received:4
cluster_stats_messages_auth-ack_received:2
cluster_stats_messages_update_received:2
cluster_stats_messages_received:10760
3.4 应用项目连接配置

Spring Data Redis 在1.7版本开始支持Redis的集群,如果非1.7版本,需要自己实现Redis集群的支持。这里采用Spring Data Redis版本为2.1.9.RELEASE, 可以直接支持集群使用。

  1. 修改项目配置
    修改配置文件bootstrap.yml:
spring:
  redis:
#    host: 127.0.0.1
#    password:
#    port: 6379
    # jedis 连接池配置
    jedis:
      pool:
        max-wait: 6000
        min-idle: 2
        max-idle: 8
    # 集群节点配置
    cluster:
      nodes: 20.20.50.26:7000,20.20.50.26:7001,20.20.50.27:7000,20.20.50.27:7001,20.20.50.28:7000,20.20.50.28:7001
    # 集群连接超时配置
    timeout: 2000
    # 密码认证配置
    password: 654321

将原来的单节点连接配置注释, 增加集群与连接池配置。 只修改配置文件即可, 其他不用修改。

连接缓存集群节点, 查看缓存信息

[root@localhost ~]# redis-cli -c -h 20.20.50.26 -p 7000
20.20.50.26:7000> auth Redis1234{}
OK
20.20.50.26:7000> keys *
1) "account:warn:setting:stockId:1::1"

-c 开启集群模式, 能够支持重定向操作。

4. 合理

  • 这里讲解了Redis所支持的部署模式, 并实际搭建部署了哨兵模式与多主集群模式,哨兵模式实际上是包含了主从模式的搭建,基本上是覆盖了Redis的所有部署模式。
  • 每种部署模式都有其适合的场景, 因地制宜, 合理选择, 更为简单高效的使用Redis, 当然java端的集群连接组件有很多, Spring Boot 从2.0开始, Redis的连接组件从Jedis替换为Lettuce, 不同客户端有不同的特性与实现机制,具体大家可以再去搜寻相关资料, 这里就不再赘述。