扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
一、redis群集相关概念
Redis是从3.0版本开始支持cluter的,采用的是hash槽方式,可以将多个Redis实例整合在一起,形成一个群集,也就是将数据分散存储到群集中的多个节点上。
让客户满意是我们工作的目标,不断超越客户的期望值来自于我们对这个行业的热爱。我们立志把好的技术通过有效、简单的方式提供给客户,将通过不懈努力成为客户在信息化领域值得信任、有价值的长期合作伙伴,公司提供的服务项目有:域名与空间、网站空间、营销软件、网站建设、屏南网站维护、网站推广。
Redis的cluster是一个无中心的结构,在群集中,每个master的身份是平等的,每个节点都保存数据和整个群集的状态,并且知道其他节点所负责的槽,也会定时发送心跳信息,能够及时感知群集中异常的节点,并且采取投票的方式来决定该节点是否为不可用,若票数为群集中节点的半数以上,则认为该节点不可用,也正是因为此特点,所以要部署Redis群集,节点数量最少要三个及以上。
群集角色有master和slave,master之间分配slots(槽),槽点编号是0-16383(共16384个)。
默认情况下,每个群集节点有两个TCP端口在监听,一个是6379(用于监听客户端的访问连接),另一个是16379(用于群集之间的节点通信)。注意,防火墙需要放行这两个端口的流量。
Redis的所有数据都是保存在内存中,然后不定期的通过异步方式保存到磁盘上(这称为“半持久化模式”);也可以把每一次数据变化都写入到一个append only file(aof)里面(这称为“全持久化模式”)。
Redis提供的这两种方式进行持久化,一种是RDB持久化(原理是将Redis在内存中的数据库定时记录dump到磁盘上的RDB持久化),另一种是AOF(append only file)持久化(原理是将Redis的操作日志以追加的方式写入文件)
RDB的优点与缺点
RDB半持久化的优点:
- 只包含一个文件,有利于文件备份;
- 灾难恢复比aof持久化要快;
- 性能最大化。对于Redis的服务进程而言,在开始持久化时,它唯一需要做的只是fork出子进程,之后再由子进程完成这些持久化的工作,这样就可以极大的避免服务进程执行IO操作了。
- 相比较AOF机制,如果数据集过大,RDB的启动效率会更高。
- RDB半持久化的缺点:
- 由于RDB是通过fork子进程来协助完成数据持久化工作的,因此,如果当数据集比较大时,可能会导致整个服务停止几百毫秒,甚至是1秒钟
AOF的优点与缺点
AOF全持久化的优点:
- 可以保证数据的高可用性;
- 写入过程中及时出现宕机现象,也不会破坏日志文件中已经存在的内容,如果在写入过程中宕机,重启Redis后可以通过redis-check-aof工具来解决;
- 如果日志过大,Redis可以自动启用rewrite机制,生成新的文件存储aof日志;
- 该机制可以带来更高的数据安全性,及数据持久性。Redis中提供了三种同步策略,即每秒同步、每修改同步和不同步。
- AOF全持久化的缺点:
- 对于相同数量的数据集而言,AOF文件通常要大于RDB文件。RDB在恢复大数据集时的速度比AOF的恢复速度要快;
- 根据同步策略的不同,AOF在运行效率上往往会慢于RDM,总之,每秒同步策略的效率是比较高的,同步禁用策略的效率和RDB一样高效。
如果RDB和AOF同时存在,则优先选择AOF方式
二、部署Redis群集
1、环境如下:
总共六台centos服务器,实现三台master分别对应一台slave
为了避免因为物理服务器的宕机而造成整个群集崩溃,也可以在一台服务器上配置多个Redis实例,实现交叉主从复制,所谓交叉就是master在node01,但对应的slave在node02,node02上master对应的slave在node03,而node03对应的slave在node01
上述只是多个服务器部署Redis群集。
但我这里主要是在一台服务器上部署多个节点,所以在node6上会有多个实例
配置前可先下载所需软件包,也可自行下载准备,链接:https://pan.baidu.com/s/1mJGBD7b0QyR_II4mSpdD8Q
提取码:72hi
2、配置Redis实例
这里以node01的配置进行示例,其他节点的配置和node1基本一样
[root@node1 /]# mkdir redis # 个人习惯而已
[root@node1 /]# cd redis/
[root@node1 redis]# rz # 上传所需软件包
[root@node1 redis]# ls # node 节点只需要redis4.0这个包,其余两个包是安装ruby环境所需的
redis-3.3.0.gem redis-4.0.14.tar.gz ruby-2.3.1.tar.gz
[root@node1 redis]# tar zxf redis-4.0.14.tar.gz # 解包
[root@node1 redis]# mv redis-4.0.14 /usr/local/redis # 移动并改名
[root@node1 redis]# cd /usr/local/redis/ # 进入目录
[root@node1 redis]# make && make install # 编译并安装
[root@node1 redis]# ./utils/install_server.sh # 对redis进行初始化
# 初始化的所有选项保持默认,一路回车确认即可,是在确认监听端口、配置文件、日志文件、pid存放Is this ok? Then press ENTER to go on or Ctrl-C to abort.
Copied /tmp/6379.conf => /etc/init.d/redis_6379
Installing service...
Successfully added to chkconfig!
Successfully added to runlevels 345!
Starting Redis server...
Installation successful!
路径等信息 # 当出现这些信息说明初始化成功
[root@node1 redis]# echo "512" > /proc/sys/net/core/somaxconn # 接下做一些优化
[root@node1 redis]# echo "vm.overcommit_memory = 1" >> /etc/sysctl.conf
[root@node1 redis]# sysctl -p
vm.overcommit_memory = 1
[root@node1 redis]# echo "never" > /sys/kernel/mm/transparent_hugepage/enabled
[root@node1 redis]# vim /etc/redis/6379.conf # 编辑配置文件
bind 0.0.0.0 #找到没有被注释的这一行,修改为0.0.0.0
daemonize yes #若有注释符号,需要删除注释符号,以便生效
cluster-enabled yes # 如有注释,需要去掉注释符号
cluster-node-timeout 5000 # 修改
appendonly yes # 改为 yes
[root@node1 redis]# /etc/init.d/redis_6379 restart # 重启服务使配置生效
[root@node1 redis]# netstat -anput | grep 6379 # 确定已经监听6379和16379两个端口
tcp 0 0 0.0.0.0:6379 0.0.0.0:* LISTEN 44263/redis-server
tcp 0 0 0.0.0.0:16379 0.0.0.0:* LISTEN 44263/redis-server
在其他节点服务器上将上述配置依次进行即可,node6除外
3、配置node06主机的多Redis实例
node06这个节点上,我将配置其运行多个Redis数据库实例,所以与前面五个节点的配置并不是完全一样,小心配置
[root@node6 /]# mkdir redis
[root@node6 /]# cd redis/
[root@node6 redis]# rz
[root@node6 redis]# tar zxf redis-4.0.14.tar.gz
[root@node6 redis]# mv redis-4.0.14 /usr/local/redis
[root@node6 redis]# cd /usr/local/redis/
[root@node6 redis]# make && make install # 编译并安装,安装完毕后无需初始化
[root@node6 redis]# redis-server # 执行此命令启动会出现3个警告,这三个警告就是我们需要优化的三个选项
[root@node6 redis]# echo "512" > /proc/sys/net/core/somaxconn
[root@node6 redis]# echo "vm.overcommit_memory = 1" >> /etc/sysctl.conf
[root@node6 redis]# sysctl -p
vm.overcommit_memory = 1
[root@node6 redis]# echo "never" > /sys/kernel/mm/transparent_hugepage/enabled
[root@node6 redis]# vim redis.conf # 编辑配置文件
bind 0.0.0.0
port 7000 # redis的默认端口是6379,这里我修改为7000,为了方便识别
daemonize yes #开启后台守护进程,以便后台运行
cluster-enabled yes #开启群集
cluster-node-timeout 5000 #群集节点间的超时时间,单位是毫秒
appendonly yes #是否开启同步到磁盘
appendfilename "appendonly-7000.aof" #aof日志的名字,因为本台主机上拥有多个实例,所以各个端口是不一样的,所以使用端口来命名日志名称
[root@node6 redis]# mkdir -p /usr/local/redis-cluster/{7000..7004}
#以上是打算运行几个Redis实例,就创建几个目录即可,这里我以实例的端口号给目录命名(暂时打算运行4个Redis实例)
#以下是将修改后的配置文件复制到指定的目录下一份
[root@node6 redis]# cp redis.conf /usr/local/redis-cluster/7000/
[root@node6 redis]# cp redis.conf /usr/local/redis-cluster/7001/
[root@node6 redis]# cp redis.conf /usr/local/redis-cluster/7002/
[root@node6 redis]# cp redis.conf /usr/local/redis-cluster/7003/
[root@node6 redis]# cp redis.conf /usr/local/redis-cluster/7004/
#然后下面将复制过去的各个配置文件中改为与Redis实例对应的端口号
[root@node6 redis]# cd /usr/local/redis-cluster/
[root@node6 redis-cluster]# ls
7000 7001 7002 7003 7004
[root@node6 redis-cluster]# sed -i s/7000/7001/g 7001/redis.conf
[root@node6 redis-cluster]# sed -i s/7000/7002/g 7002/redis.conf
[root@node6 redis-cluster]# sed -i s/7000/7003/g 7003/redis.conf
[root@node6 redis-cluster]# sed -i s/7000/7004/g 7004/redis.conf
[root@node6 redis-cluster]# cd 7000/ # 进入到7000实例目录中
[root@node6 7000]# redis-server redis.conf # 启动该实例
8142:C 13 Feb 10:44:17.501 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
8142:C 13 Feb 10:44:17.501 # Redis version=4.0.14, bits=64, commit=00000000, modified=0, pid=8142, just started
8142:C 13 Feb 10:44:17.501 # Configuration loaded
# 来就是依次进入到各个实例目录中,启动实例,这里我就不演示了
4、主机node01安装配置ruby的运行环境,便于管理Redis群集
[root@node1 /]# yum -y install rpm-build openssl openssl-devel # 安装所需依赖包
[root@node1 /]# cd /redis/
[root@node1 redis]# ls
redis-3.3.0.gem redis-4.0.14.tar.gz ruby-2.3.1.tar.gz
[root@node1 redis]# tar zxf ruby-2.3.1.tar.gz # 解包
[root@node1 redis]# cd ruby-2.3.1/
[root@node1 ruby-2.3.1]# ./configure --prefix=/usr/local/ruby && make && make install # 此环境编译时间较长
[root@node1 ruby-2.3.1]# ln -s /usr/local/ruby/bin/* /usr/local/bin/ # 为命令做软连接
[root@node1 ruby-2.3.1]# ln -s /usr/local/redis/src/redis-trib.rb /usr/local/bin/
[root@node1 ruby-2.3.1]# ln -s /usr/local/ruby/bin/* /usr/bin/
[root@node1 ruby-2.3.1]# cd ..
[root@node1 redis]# gem install redis-3.3.0.gem # 回到有gem文件的目录,进行安装
Successfully installed redis-3.3.0
Parsing documentation for redis-3.3.0
Installing ri documentation for redis-3.3.0
Done installing documentation for redis after 0 seconds
1 gem installed
# 范围如上信息则表示安装成功
5、配置群集中的各个节点
[root@node1 /]# redis-cli -p 6379 # 登录到ben'di本地实例
127.0.0.1:6379> CLUSTER MEET 192.168.171.134 6379 # 将各个节点添加到群集中
OK
127.0.0.1:6379> CLUSTER MEET 192.168.171.135 6379
OK
127.0.0.1:6379> CLUSTER MEET 192.168.171.136 6379
OK
127.0.0.1:6379> CLUSTER MEET 192.168.171.137 6379
OK
127.0.0.1:6379> CLUSTER MEET 192.168.171.138 7000 # 这块是因为node6修改过端口号
OK
127.0.0.1:6379> set test aaa # 由于并没有分配hash槽,所以并不能添加数据
(error) CLUSTERDOWN Hash slot not served
127.0.0.1:6379> CLUSTER INFO # 查看群集的状态
cluster_state:fail # 会发现这里是fail失败的
cluster_slots_assigned:0
127.0.0.1:6379> exit
# 下来我们分配槽点,要小心配置
#虽然可以将命令中的“add”换为“del”,但是我没有成功
#一定要将0至16383完全分配出去,最好是等份分配
#只需给作为master的节点分配即可,我这里node01至node03为master
[root@node1 /]# redis-cli -h 192.168.171.133 -p 6379 cluster addslots {0..5461}
OK
[root@node1 /]# redis-cli -h 192.168.171.134 -p 6379 cluster addslots {5462..10922}
OK
[root@node1 /]# redis-cli -h 192.168.171.135 -p 6379 cluster addslots {10923..16383}
OK
[root@node1 /]# redis-cli -p 6379 -c # 进入群集,需要添加-c选项
127.0.0.1:6379> CLUSTER NODES # 查看群集节点信息
#接下来是将各个slave从节点与master进行绑定
#node04作为node01的从节点,node05作为node02的从节点,node06的6379实例作为node03的从节点
#需要配置哪个从节点,就需要登录到哪个实例
127.0.0.1:6379> CLUSTER NODES #可以先执行此命令,查看相应节点的ID,以便接下来指定
[root@node1 /]# redis-cli -h 192.168.171.136 -p 6379 # 登录到node4
192.168.171.136:6379> CLUSTER REPLICATE 4397bb3e5e43fdf1700551d0a2587f502e6c02a8
OK
#以上添加的是node1的节点id
192.168.171.136:6379> exit # 退出该节点
[root@node1 /]# redis-cli -h 192.168.171.137 -p 6379
192.168.171.137:6379> CLUSTER REPLICATE 1eca51f415ba5194a95d5400176daa5713d64990
OK
#以上添加的是node2的节点id
192.168.171.137:6379> exit
[root@node1 /]# redis-cli -h 192.168.171.138 -p 7000
192.168.171.138:7000> CLUSTER REPLICATE ee71a2fd995f35992ce69328096ccd50fc68f89e
OK
#以上添加的是node3的节点id
至此,群集即可正常读写数据了,如下:
[root@node1 /]# redis-cli -h 192.168.171.133 -p 6379 -c
192.168.171.133:6379> set test aaa
-> Redirected to slot [6918] located at 192.168.171.134:6379
OK
192.168.171.134:6379> get test
"aaa"
192.168.171.134:6379>
6、使用ruby安装的命令管理Redis群集
[root@node1 /]# redis-trib.rb check 127.0.0.1:6379
7、将node06的7001实例添加节点到Redis群集中
添加节点
[root@node1 /]# redis-trib.rb add-node 192.168.171.138:7001 192.168.171.133:6379
#在添加节点时,不添加其他配置,默认加入群集后,角色是master
添加节点后需要分配相应的槽点
由于一个群集若要正常运行,必须将所有的槽点分配出去,所以当有新的节点加入后,需要重新给新加入的节点分配槽点,如下:
[root@node01 /]# redis-trib.rb check 127.0.0.1:6379 #执行此命令进行确认新加入的节点时master
[root@node01 /]# redis-trib.rb reshard 192.168.171.133:6379 #指定群集地址及端口
How many slots do you want to move (from 1 to 16384)? 4096
#若是四个master,那么平均值为4096,所以这里输入4096
What is the receiving node ID?
eca1db0392f69207c4fc3ad4ff290d5a94ea5f99
#指定接收的节点,也就是新加入的node06主机上7001的那个实例的ID
Source node #1:all #指定从哪个节点的槽点分配,这里输入“all”选择所有节点
Do you want to proceed with the proposed reshard plan (yes/no)? yes #输入“yes”进行确认
至此,新的节点就添加完成了,并且分配了相应的槽点,但是还没有从节点,所以接下来为新加入的master分配一个从节点
8、为新加入的master分配从节点
分配从节点的方式有两种,一种是不指定为哪个master的从节点,自动绑定到没有从节点的master上,一种是直接指定绑定到哪个master上,这里将这两种方式都写下来
方法一:
[root@node1 /]# redis-trib.rb add-node --slave 192.168.171.138:7002 192.168.171.138:7001
#将node06上的7002实例以slave的身份加入到群集
#注意,返回的信息不可有红色字样,那就说明有错误
[root@node1 /]# redis-trib.rb check 192.168.171.133:6379
方法二:
[root@node1 /]# redis-trib.rb add-node --slave --master-id eca1db0392f69207c4fc3ad4ff290d5a94ea5f99 192.168.171.138:7003 192.168.171.138:7001
#上述id为7001master的id
[root@node1 /]# redis-trib.rb check 192.168.171.133: 6379 # 查看群集状态,会发现7001有两个从节点
9、删除主节点操作
删除主节点的操作其实就是把添加主节点的操作反了过了,需要先将要删除的主节点上的槽点分配给其他master,然后才可以执行删除操作,并且删除主节点后,该master对应的slave也将会随着slots槽进行转移到新的master上。
这里以移除node06上的7001实例为例
[root@node1 /]# redis-trib.rb reshard 192.168.171.133:6379
How many slots do you want to move (from 1 to 16384)? 4096 # 指定删除多少槽点
What is the receiving node ID? 1eca51f415ba5194a95d5400176daa5713d64990
#上述添加的id为删除主节点后,剩余的槽点分配给谁,这里我添加的是node2的id
Please enter all the source node IDs.
Type 'all' to use all the nodes as source nodes for the hash slots.
Type 'done' once you entered all the source nodes IDs.
Source node #1:eca1db0392f69207c4fc3ad4ff290d5a94ea5f99
#上述指定的是要删除的那个节点,这里是node6上的7001
Source node #2:done # 表示结束
Do you want to proceed with the proposed reshard plan (yes/no)? yes
#移除槽点后,接下来将7001实例从群集中移除,如下:
[root@node1 /]# redis-trib.rb del-node 192.168.171.133:6379 eca1db0392f69207c4fc3ad4ff290d5a94ea5f99
>>> Removing node eca1db0392f69207c4fc3ad4ff290d5a94ea5f99 from cluster 192.168.171.133:6379 # 指定的id为7001
>>> Sending CLUSTER FORGET messages to the cluster...
>>> SHUTDOWN the node.
至此,7001实例就被彻底移除群集了,并且原本与之对应的slave也随着槽点转移到node02也一起成为了node02的slave。现在查看群集信息,node02的master应该是对应了三个slave
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流