文章目录

  • Redis
  • Redis应用场景
  • 下载及安装
  • Redis常用指令
  • Redis持久化
  • Redis主从复制
  • Redis的Sentinel分布式系统(主从切换)
  • sentnel(Redis的高可用方案)
  • Sentinel作用
  • Sentinel工作方式
  • 主观下线和客观下线
  • Sentinel配置
  • 通过Twemproxy配置Redis集群
  • Twemproxy
  • Twemproxy下载
  • 安装
  • 配置
  • 测试
  • 官方Redis集群
  • Redis 集群介绍
  • Redis 集群的端口
  • Redis 集群和数据分片
  • Redis 集群主从模式
  • Redis 集群一致性保证
  • 总结
  • 配置
  • 创建6个redis实例
  • 创建集群
  • 测试
  • 节点的热添加



实验环境:rhel7.6

Redis

redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。
Redis 是一个高性能的key-value数据库。 redis的出现,很大程度补偿了memcached这类key/value存储的不足,在部 分场合可以对关系数据库起到很好的补充作用。它提供了Java,C/C++,C#,PHP,JavaScript,Perl,Object-C,Python,Ruby,Erlang等客户端,使用很方便.\

Redis应用场景

  • 热点数据的缓存
  • 限时业务的运用
  • 数据库
  • 消息中间件

下载及安装

下载源码包,这里下载的版本为5.0.8
下载地址:
redis官网:redis.io

下载完成后,对压缩包进行解压:

redis将从从库设置为主库_redis将从从库设置为主库

解压完成后直接make:

redis将从从库设置为主库_Redis_02


make完成后直接使用make install:

redis将从从库设置为主库_Redis_03

进入utils目录,执行脚本install_server.sh:

redis将从从库设置为主库_Redis_04


确定端口、配置文件、日志文件、数据目录、命令位置

redis将从从库设置为主库_Redis_05

Redis常用指令

Redis 命令用于在 redis 服务上执行操作。
执行/etc/init.d/redis_6379 start来启动redis服务

启动 redis 服务器,打开终端并输入命令 redis-cli,该命令会连接本地的 redis 服务
所有的命令可在官方文档中查找用法。

指令

含义

config get *

查看配置

select 1

选择数据库

flushdb

清空当前数据库

flushall

清空所有数据库

move key 1

移动key

rename 【oldkey】【newkey】

改名

expire key 10

设置过期时间

persist key

设置持久化,移除key的生存时间

exists key

判断是否存在

查看配置:所有的配置以key-value方式展现

redis将从从库设置为主库_redis将从从库设置为主库_06


redis共有16个数据库, 默认进入的是数据库0:

redis将从从库设置为主库_Redis_07


在一个数据库中存入的信息只能在该数据库中查询,在其他数据库不能查询:

redis将从从库设置为主库_数据_08


清空当前数据库:

redis将从从库设置为主库_redis将从从库设置为主库_09


为数据设置10秒过期时间,TTL为查询过期时间:

redis将从从库设置为主库_Redis_10

Redis持久化

默认使用RDB快照存储。
RDB格式(适合主从复制):
三种:

  • SAVE:

    使用set存入的name值是在内存中,执行SAVE命令后,该数据就会保存在redis的数据目录中[/var/lib/redis/6379/]:生成rdb文件。 RDB快照存储(默认)
  • BGSAVE:当数据量特别庞大时,执行SAVE指令会阻塞命令的输入,此时可以使用bgsave会进行后台执行SAVE
  • 由服务自动执行
    使用CONFIG GET SAVE指令可看到服务自动执行持久化情况服务自动执行持久化情况:

    或者在配置文件中(/etc/redis/6379.conf)中看到服务自动执行持久化情况服务自动执行持久化情况:
    在配置文件中可定义多条自动执行永久化的规则,默认规则为:
    触发条件为:一条Key数据被改变时,900秒会进行BGSAVE,十条Key数据被改变时,300秒会进行BGSAVE;一万条Key数据被改变时,60秒会进行BGSAVE。
    注意:不宜设置太过于频繁,BGSAVE动作耗内存,容易造成性能瓶颈。

AOF(适合数据据恢复):

默认不开启,可在配置文件中开启:

redis将从从库设置为主库_数据_11


三种方式:

redis将从从库设置为主库_redis_12

appendfsync always ##写一条记录一条
appendfsync everysec##每秒钟记录一次
appendfsync no ##自己不定义,跟随操作系统(30s一次)

修改完成后重启redis,可以看到aof文件已经生成了:

redis将从从库设置为主库_redis_13


在redis中作操作:

INCR nu(计数)

redis将从从库设置为主库_数据_14

查看刚才生成的aof文件,可以看到,将所有操作记录:

redis将从从库设置为主库_Redis_15

有点类似于mysql中的binlog

但是在此文件中有许多冗余数据,比如刚才的技术操作执行了50次,在aof文件中记录了到50,而rdb中则记录的最终的数值50。所以主从复制使用的是rdb文件,而aof文件则适合数据恢复。

Redis主从复制

我们在本机在开一个端口6380为从redis,制定主redis主机为本机的6379:

redis将从从库设置为主库_redis将从从库设置为主库_16

6380端口已经打开:

redis将从从库设置为主库_redis将从从库设置为主库_17


在6379的主redis中写入数据,写入后在6380的从redis中进行查询,成功查询到:

redis将从从库设置为主库_redis_18


当redis为slave状态时,本地数据会丢失,redis为readonly:

redis将从从库设置为主库_数据_19


实验环境 redis主机:

server1[172.25.1.1]<主>

server2[172.25.1.2]

server3[172.25.1.3]在server2、server3上的redis配置文件中,添加主redis信息,监听本机所有接口:

注意:在server1<主>上也要监听所有接口,默认监听本机回环接口127.0.0.1

redis将从从库设置为主库_数据_20

此时主从复制就配置完成。

测试:

server1的rediss数据:

[root@server1 ~]# hostname
server1
[root@server1 ~]# redis-cli 
127.0.0.1:6379> get name
"xng"
127.0.0.1:6379>

在server2,server3上进行查询:

[root@server2 redis]# hostname
server2
[root@server2 redis]# redis-cli 
127.0.0.1:6379> get name
"xng"


[root@server3 ~]# hostname
server3
[root@server3 ~]# redis-cli 
127.0.0.1:6379> get name
"xng"

主从复制原理:
slave向master发送连接请求(认证)
认证通过后,slave发送同步指令给master,触发master执行bgsave动作,产生rdb文件。同时开辟缓冲区,记录bgsave动作之后的写操作。gbsave完成后,发送给slave。
slave收到rdb文件后在本机首先执行flushall操作,清空所有数据,导入rdb文件(全量)。
master上perlicationfeedslave()缓冲区的写操作再发送给slave,最终达到数据一致。
至此实现主从复制。

Redis的Sentinel分布式系统(主从切换)

之前已经实现了主从复制,但是当master挂掉之后,还无法进行故障切换。
问题的引出:
一般的主从切换;
当master挂掉之后,从节点转化为master,接受新的用户请求。另外一台slave开始复制新的master上的数据。但是如果master和slave之间有了网络隔离,master没有挂,但是两台slave认为master挂了,会有一个slave节点身份提升为master,当网络隔离取消后,原master发现集群已经有master,身份降级为slave。但是!!!在成为slave的时候会进行flushall操作!

要实现redis的主从切换,每个节点需要配置sentinel。

sentnel(Redis的高可用方案)

Redis SentinelSentinel(哨兵)是用于监控redis集群中Master状态的工具,其已经被集成在redis2.4+的版本中。

Sentinel作用

  • Master状态检测。
  • 如果Master异常,则会进行Master-Slave切换,将其中一个Slave作为Master,将之前的Master作为Slave。
  • Master-Slave切换后,master_redis.conf、slave_redis.conf和sentinel.conf的内容都会发生改变,即master_redis.conf中会多一行slaveof的配置,sentinel.conf的监控目标会随之调换。

Sentinel工作方式

  • 每个Sentinel以每秒钟一次的频率向它所知的Master,Slave以及其他 Sentinel 实例发送一个 PING 命令
  • 如果一个实例(instance)距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 选项所指定的值, 则这个实例会被 Sentinel 标记为主观下线。
  • 如果一个Master被标记为主观下线,则正在监视这个Master的所有 Sentinel 要以每秒一次的频率确认Master的确进入了主观下线状态。
  • 当有足够数量的 Sentinel(大于等于配置文件指定的值)在指定的时间范围内确认Master的确进入了主观下线状态, 则Master会被标记为客观下线
  • 在一般情况下, 每个 Sentinel 会以每 10 秒一次的频率向它已知的所有Master,Slave发送 INFO 命令。
  • 当Master被 Sentinel 标记为客观下线时,Sentinel 向下线的 Master 的所有 Slave 发送 INFO 命令的频率会从 10 秒一次改为每秒一次
  • 若没有足够数量的 Sentinel 同意 Master 已经下线, Master 的客观下线状态就会被移除。
      若 Master 重新向 Sentinel 的 PING 命令返回有效回复, Master 的主观下线状态就会被移除。

主观下线和客观下线

  • 主观下线:Subjectively Down,简称 SDOWN,指的是当前 Sentinel 实例对某个redis服务器做出的下线判断。
  • 客观下线:Objectively Down, 简称 ODOWN,指的是多个 Sentinel 实例在对Master Server做出 SDOWN 判断,并且通过 SENTINEL is-master-down-by-addr 命令互相交流之后,得出的Master Server下线判断,然后开启failover.
      SDOWN适合于Master和Slave,只要一个 Sentinel 发现Master进入了ODOWN, 这个 Sentinel 就可能会被其他 Sentinel 推选出, 并对下线的主服务器执行自动故障迁移操作。
      ODOWN只适用于Master,对于Slave的 Redis 实例,Sentinel 在将它们判断为下线前不需要进行协商, 所以Slave的 Sentinel 永远不会达到ODOWN。

Sentinel配置

首先在redis源码包中将redis自带的配置文件sentinel拷贝到redis的配置目录(所有节点都需要做):

redis将从从库设置为主库_Redis_21

编辑sentinel的配置文件:

关闭保护模式:

redis将从从库设置为主库_redis将从从库设置为主库_22

指定master的地址及端口:

redis将从从库设置为主库_数据_23

其中,作后边的2的含义为:最少需要两个节点判断master存活才认为master为存活状态down-after-milliseconds 选项所指定的值默认为30秒:

redis将从从库设置为主库_redis_24


sentinel parallel-syncs mymaster 值默认为1

redis将从从库设置为主库_Redis_25

新的master只允许每次一个slave同步数据

这里有好多人问:将此值设置大不是会同步更快吗?

虽然将此值设置大会一次同步多台slave,会更快完成切换。但是在同步数据的过程中,slave是不可读的,那么据群众能被用户访问的活跃节点数就越少。将此值设置小的优点就是集群可用度高,缺点是切换速度慢。切换默认超时时间默认是3分钟:

redis将从从库设置为主库_redis将从从库设置为主库_26


到此,配置完成。

使用 redis-sentinel /etc/redis/sentinel.conf (redis-sentinel + 配置文件)启动sentinel(每台节点都做):

redis将从从库设置为主库_redis_27

此时关掉server1(master)上的redis,查看sentinel输出内容的变化:

redis将从从库设置为主库_Redis_28


master成功从server1切换到server3。此时开启server1上的redis服务,server1自动加入集群,身份为slave:

redis将从从库设置为主库_redis将从从库设置为主库_29

通过Twemproxy配置Redis集群

配置完Redis的主从复制、主从切换可以清晰的感受到,这仅仅只是增加了Redis读的性能,写的性能依旧是没有增加(只有一个点)。
设想:
能不能多点对redis进行写操作?
能不能让客户端通过调度器访问后端的多台Redis服务器?

Twemproxy

Twemproxy是一种代理分片机制,由Twitter开源,主要用于减少后端缓存服务器的连接数量。Twemproxy作为代理,可接受来自多个程序的访问,按照路由规则,转发给后台的各个Redis或memcached服务器,再原路返回。该方案很好的解决了单个Redis或memcached实例承载能力的问题。Twemproxy本身也是单点,需要用Keepalived做高可用方案,可以使用多台服务器来水平扩张redis或memcached服务,可以有效的避免单点故障问题。

Twemproxy下载

Twemproxy源码托管在GIthub上,直接可以下载源码。

https://github.com/twitter/twemproxy

redis将从从库设置为主库_数据_30

实验环境:
twemproxy:server4[172.25.1.4]
master:
server1[172.25.1.1]
server2[172.25.1.2]
server3[172.25.1.3]
将刚才做实验时身份为slave的redis改为master:

127.0.0.1:6379> SLAVEOF no one
OK

安装

redis将从从库设置为主库_redis将从从库设置为主库_31

解压完成后,进入解压目录,没有找到configure

按照github上指定的命令:

redis将从从库设置为主库_redis将从从库设置为主库_32

下载相关工具:

yum install automake libtool autoconf -y

在解压目录中:
执行:

[root@server4 twemproxy-master]# autoreconf -fvi
autoreconf: Entering directory `.'
autoreconf: configure.ac: not using Gettext
autoreconf: running: aclocal --force -I m4
autoreconf: configure.ac: tracing
autoreconf: configure.ac: adding subdirectory contrib/yaml-0.1.4 to autoreconf
autoreconf: Entering directory `contrib/yaml-0.1.4'
autoreconf: configure.ac: not using Autoconf
autoreconf: Leaving directory `contrib/yaml-0.1.4'
autoreconf: configure.ac: creating directory config
autoreconf: running: libtoolize --copy --force
libtoolize: putting auxiliary files in AC_CONFIG_AUX_DIR, `config'.
libtoolize: copying file `config/ltmain.sh'
libtoolize: putting macros in AC_CONFIG_MACRO_DIR, `m4'.
libtoolize: copying file `m4/libtool.m4'
libtoolize: copying file `m4/ltoptions.m4'
libtoolize: copying file `m4/ltsugar.m4'
libtoolize: copying file `m4/ltversion.m4'
libtoolize: copying file `m4/lt~obsolete.m4'
libtoolize: `AC_PROG_RANLIB' is rendered obsolete by `LT_INIT'
autoreconf: running: /usr/bin/autoconf --force
autoreconf: running: /usr/bin/autoheader --force
autoreconf: running: automake --add-missing --copy --force-missing
configure.ac:36: installing 'config/config.guess'
configure.ac:36: installing 'config/config.sub'
configure.ac:16: installing 'config/install-sh'
configure.ac:16: installing 'config/missing'
src/Makefile.am: installing 'config/depcomp'
autoreconf: Leaving directory `.'

此时configure出现:

redis将从从库设置为主库_redis_33


编译:./configure

redis将从从库设置为主库_Redis_34

make:

redis将从从库设置为主库_Redis_35

make install:

redis将从从库设置为主库_数据_36

配置

创建配置文件: vim /etc/twemproxy.yml

lpha:
  listen: 172.25.1.4:22121
  hash: fnv1a_64
  distribution: ketama
  auto_eject_hosts: true
  redis: true
  server_retry_timeout: 20000
  server_failure_limit: 1
  servers:
   - 172.25.1.1:6379:1
   - 172.25.1.2:6379:1
   - 172.25.1.3:6379:1

配置完成后启动服务:

nutcracker -d -c /etc/twemproxy.yml ##-d打入后台 -c制定配置文件

测试

注:若twemproxy端没有redis-cli命令可从其他主机拷贝。

redis-cli -p 22121 -h 172.25.1.4

可以取到之前的信息:

[root@server4 twemproxy-master]# redis-cli -p 22121 -h 172.25.1.4
172.25.1.4:22121> get name
"xng"

通过twemproxy往后端redis写入数据:

172.25.1.4:22121> set key1 111
OK

在后端redis中进行查询:

server1:

redis将从从库设置为主库_redis将从从库设置为主库_37

server2:

redis将从从库设置为主库_redis将从从库设置为主库_38

server3:

redis将从从库设置为主库_redis将从从库设置为主库_39


可以看到,数据key1被存放在server1上的redis。当server1上的redis挂掉:

[root@server1 ~]# /etc/init.d/redis_6379 stop
Stopping ...
Redis stopped

代理端不能取到在server1上的数据,但是还能继续写入数据:

172.25.1.4:22121> get key1
(error) ERR Connection refused
172.25.1.4:22121> set key6 666
OK

新的数据被写入到server2上的redis:

127.0.0.1:6379> get key6
"666"
127.0.0.1:6379> 
[root@server2 ~]# hostname
server2

挂掉的节点被踢出集群。

将server1的redis启动,服务恢复:

[root@server1 ~]# /etc/init.d/redis_6379 start
Starting Redis server...

查询刚才存放在server1的redis中的数据:

172.25.1.4:22121> get key1
(nil)
172.25.1.4:22121> get key1
"111"
172.25.1.4:22121>

可以查到。

  • 可以看到,最大的问题就在于一个节点挂掉之后,那么此节点上的数据也就没有了,所以一般对每个master做高可用,配置主从复制及主从切换。但是还是有很大的数据丢失风险,且还需要解决调度器twemproxy单点问题。

官方Redis集群

Redis 集群介绍

Redis Cluster 提供一种Redis安装方式:数据自动在多个Redis节点间分片。

Redis Cluster 提供一定程度的高可用,在实际的环境中当某些节点失败或者不能通讯的情况下能够继续提供服务。大量节点失败的情况下集群也会停止服务(例如大多数主节点不可用)。

Redis集群提供的能力:

  • 自动切分数据集到多个节点上。
  • 当部分节点故障或不可达的情况下继续提供服务。

Redis 集群的端口

每个Redis集群节点需要打开两个TCP连接。端口6379提供给客户端连接,外加上一个端口16379,记起来也比较容易,在6379的基础上加10000。

端口16379提供给集群总线使用,总线用来集群节点间通信,使用的是二进制协议。集群总线的作用:失败检测、配置升级、故障转移授权等。客户端只能连接6379端口,不能连接端口16379。防火墙需要确保打开这两个端口,否则集群节点之间不能通信。

命令端口和总线端口之间总是相差10000 。

每个节点的端口原则:

  • 客户端通讯端口需要开放给所有与集群交互的客户端,和集群内的其它节点(主要是用来做keys迁移)。
  • 集群总线端口(命令端口+10000)需要被所有其它集群节点能访问到。

集群总线使用二进制协议(不同于跟客户端通信协议)来进行节点之间数据交换,这个协议更适合节点间使用小的带宽和处理时间来交换数据。

Redis 集群和数据分片

Redis集群不是使用一致性哈希,而是使用哈希槽。整个redis集群有16384个哈希槽,决定一个key应该分配到那个槽的算法是:计算该key的CRC16结果再模16834。

集群中的每个节点负责一部分哈希槽,比如集群中有3个节点,则:

  • 节点A存储的哈希槽范围是:0 – 5500
  • 节点B存储的哈希槽范围是:5501 – 11000
  • 节点C存储的哈希槽范围是:11001 – 16384

这样的分布方式方便节点的添加和删除。比如,需要新增一个节点D,只需要把A、B、C中的部分哈希槽数据移到D节点。同样,如果希望在集群中删除A节点,只需要把A节点的哈希槽的数据移到B和C节点,当A节点的数据全部被移走后,A节点就可以完全从集群中删除。

因为把哈希槽从一个节点移到另一个节点是不需要停机的,所以,增加或删除节点,或更改节点上的哈希槽,也是不需要停机的。

集群支持通过一个命令(或事务, 或lua脚本)同时操作多个key。通过“哈希标签”的概念,用户可以让多个key分配到同一个哈希槽。哈希标签在集群详细文档中有描述,这里做个简单介绍:如果key含有大括号”{}”,则只有大括号中的字符串会参与哈希,比如”this{foo}”和”another{foo}”这2个key会分配到同一个哈希槽,所以可以在一个命令中同时操作他们。

Redis 集群主从模式

为了保证在部分节点故障或网络不通时集群依然能正常工作,集群使用了主从模型,每个哈希槽有一(主节点)到N个副本(N-1个从节点)。

在我们刚才的集群例子中,有A,B,C三个节点,如果B节点故障集群就不能正常工作了,因为B节点中的哈希槽数据5501-11000没法操作。

但是,如果我们给每一个节点都增加一个从节点,就变成了:A,B,C三个节点是主节点,A1, B1, C1 分别是他们的从节点,当B节点宕机时,我们的集群也能正常运作。

B1节点是B节点的副本,如果B节点故障,集群会提升B1为主节点,从而让集群继续正常工作。但是,如果B和B1同时故障,集群就不能继续工作了。

Redis 集群一致性保证

Redis集群不能保证强一致性。一些已经向客户端确认写成功的操作,会在某些不确定的情况下丢失。

产生写操作丢失的第一个原因,是因为主从节点之间使用了异步的方式来同步数据。

一个写操作是这样一个流程:

  • 客户端向主节点B发起写的操作
  • 主节点B回应客户端写操作成功
  • 主节点B向它的从节点B1,B2,B3同步该写操作

从上面的流程可以看出来,主节点B并没有等从节点B1,B2,B3写完之后再回复客户端这次操作的结果。所以,如果主节点B在通知客户端写操作成功之后,但同步给从节点之前,主节点B故障了,其中一个没有收到该写操作的从节点会晋升成主节点,该写操作就这样永远丢失了。

就像传统的数据库,在不涉及到分布式的情况下,它每秒写回磁盘。为了提高一致性,可以在写盘完成之后再回复客户端,但这样就要损失性能。这种方式就等于Redis集群使用同步复制的方式。

基本上,在性能和一致性之间,需要一个权衡。

如果真的需要,Redis集群支持同步复制的方式,通过WAIT 指令来实现,这可以让丢失写操作的可能性降到很低。但就算使用了同步复制的方式,Redis集群依然不是强一致性的,在某些复杂的情况下,比如从节点在与主节点失去连接之后被选为主节点,不一致性还是会发生。

这种不一致性发生的情况是这样的,当客户端与少数的节点(至少含有一个主节点)网络联通,但他们与其他大多数节点网络不通。比如6个节点,A,B,C是主节点,A1,B1,C1分别是他们的从节点,一个客户端称之为Z1。

当网络出问题时,他们被分成2组网络,组内网络联通,但2组之间的网络不通,假设A,C,A1,B1,C1彼此之间是联通的,另一边,B和Z1的网络是联通的。Z1可以继续往B发起写操作,B也接受Z1的写操作。当网络恢复时,如果这个时间间隔足够短,集群仍然能继续正常工作。如果时间比较长,以致B1在大多数的这边被选为主节点,那刚才Z1发给B的写操作都将丢失。

注意,Z1给B发送写操作是有一个限制的,如果时间长度达到了大多数节点那边可以选出一个新的主节点时,少数这边的所有主节点都不接受写操作。

这个时间的配置,称之为节点超时(node timeout),对集群来说非常重要,当达到了这个节点超时的时间之后,主节点被认为已经宕机,可以用它的一个从节点来代替。同样,在节点超时时,如果主节点依然不能联系到其他主节点,它将进入错误状态,不再接受写操作。

总结

16384个hash槽不可或缺,当hash槽不完整时,集群不可用。
无中心化,6个节点3主3从,当数据是在本机,直接返回,当数据不在本机,进行重写。

配置

创建6个redis实例

在/usr/local下新建目录test-cluster
进入test-cluster新建7000 7001 7002 7003 7004 7005五个目录
在每个目录下编写redis配置文件redis.conf

[root@server1 local]# pwd
/usr/local
[root@server1 local]# mkdir cluster-tset
[root@server1 local]# cd cluster-tset/
[root@server1 cluster-tset]# mkdir 7000 7001 7002 7003 7004 7005
[root@server1 cluster-tset]# ls
7000  7001  7002  7003  7004  7005
[root@server1 cluster-tset]# cd 7000
[root@server1 7000]# vim redis.conf

编写完配置文件后开启服务:

root@server1 7000]# redis-server redis.conf 
3432:C 29 Aug 2020 07:10:05.718 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
3432:C 29 Aug 2020 07:10:05.718 # Redis version=5.0.8, bits=64, commit=00000000, modified=0, pid=3432, just started
3432:C 29 Aug 2020 07:10:05.718 # Configuration loaded

配置文件:

port 7000
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
daemonize yes

注意:此配置文件为目录7000下的配置文件,7001的配置文件中port应为7001,以此类推,相同操作,打开服务。

端口成功打开:

redis将从从库设置为主库_redis_40

创建集群

直接可以通过redis-cli创建集群:

[root@server1 7001]# redis-cli --cluster create 127.0.0.1:7000 127.0.0.1:7001 \
> 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 \
> --cluster-replicas 1
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 127.0.0.1:7004 to 127.0.0.1:7000
Adding replica 127.0.0.1:7005 to 127.0.0.1:7001
Adding replica 127.0.0.1:7003 to 127.0.0.1:7002
>>> Trying to optimize slaves allocation for anti-affinity
[WARNING] Some slaves are in the same host as their master
M: 27b428bc9cdb396da31a11126d86585dd155f0a2 127.0.0.1:7000
   slots:[0-5460] (5461 slots) master
M: 97c8d22ad9a8c312a07c1a6c61ad678d3f4abc50 127.0.0.1:7001
   slots:[5461-10922] (5462 slots) master
M: 147ecda2bfb075158a347277010d0b32297b80ea 127.0.0.1:7002
   slots:[10923-16383] (5461 slots) master
S: 210c5e3d09345f479131fc09e0a0058f6d382467 127.0.0.1:7003
   replicates 27b428bc9cdb396da31a11126d86585dd155f0a2
S: 7a862d7fcf8c160f59029ae536fd2d70a6461455 127.0.0.1:7004
   replicates 97c8d22ad9a8c312a07c1a6c61ad678d3f4abc50
S: 006e1403670f7dc30bd994063f41a1364d7a072e 127.0.0.1:7005
   replicates 147ecda2bfb075158a347277010d0b32297b80ea
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 127.0.0.1:7000)
M: 27b428bc9cdb396da31a11126d86585dd155f0a2 127.0.0.1:7000
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
S: 210c5e3d09345f479131fc09e0a0058f6d382467 127.0.0.1:7003
   slots: (0 slots) slave
   replicates 27b428bc9cdb396da31a11126d86585dd155f0a2
M: 97c8d22ad9a8c312a07c1a6c61ad678d3f4abc50 127.0.0.1:7001
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
S: 006e1403670f7dc30bd994063f41a1364d7a072e 127.0.0.1:7005
   slots: (0 slots) slave
   replicates 147ecda2bfb075158a347277010d0b32297b80ea
S: 7a862d7fcf8c160f59029ae536fd2d70a6461455 127.0.0.1:7004
   slots: (0 slots) slave
   replicates 97c8d22ad9a8c312a07c1a6c61ad678d3f4abc50
M: 147ecda2bfb075158a347277010d0b32297b80ea 127.0.0.1:7002
   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.

集群配置成功,(7000为主 7003为从,7001为主 7004为从,7002为主7005为从)!

测试

[root@server1 ~]# redis-cli -c -p 7000
127.0.0.1:7000> set k1 111
-> Redirected to slot [12706] located at 127.0.0.1:7002
OK
127.0.0.1:7002> set k2 222
-> Redirected to slot [449] located at 127.0.0.1:7000
OK
127.0.0.1:7000> get k1
-> Redirected to slot [12706] located at 127.0.0.1:7002
"111"
127.0.0.1:7002> get k2
-> Redirected to slot [449] located at 127.0.0.1:7000
"222"

写入的节点随机,在读取数据时,数据不在本地则进行重写。
可以看到,k1的值是储存在7002上,在查询时,自动重写到7002。

127.0.0.1:7002> SHUTDOWN
not connected> 
[root@server1 ~]# redis-cli -c -p 7000
127.0.0.1:7000> get k1
-> Redirected to slot [12706] located at 127.0.0.1:7005
"111"
127.0.0.1:7005>

将7002的redis关掉后,再次查询保存在7002的数据依然可以查询到,自动重写到了7005(7002的从节点)

127.0.0.1:7005> SHUTDOWN
not connected> 
[root@server1 ~]# redis-cli -c -p 7000
127.0.0.1:7000> get k1
(error) CLUSTERDOWN The cluster is down

将7002的从节点7005关掉之后,再次查询7002上的数据,因为hash槽已经缺少一部分了,集群不可用。

[root@server1 local]# cd cluster-tset/7002
[root@server1 7002]# redis-server redis.conf 
3787:C 29 Aug 2020 07:55:53.791 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
3787:C 29 Aug 2020 07:55:53.791 # Redis version=5.0.8, bits=64, commit=00000000, modified=0, pid=3787, just started
3787:C 29 Aug 2020 07:55:53.791 # Configuration loaded
[root@server1 7002]# cd /usr/local/cluster-tset/7005
[root@server1 7005]# redis-server redis.conf 
3794:C 29 Aug 2020 07:57:18.061 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
3794:C 29 Aug 2020 07:57:18.061 # Redis version=5.0.8, bits=64, commit=00000000, modified=0, pid=3794, just started
3794:C 29 Aug 2020 07:57:18.061 # Configuration loaded
[root@server1 7005]# redis-cli -c -p 7000
127.0.0.1:7000> get k1
-> Redirected to slot [12706] located at 127.0.0.1:7005
"111"

将关闭的节点启动,集群恢复正常!

节点的热添加

再新创建两个redis实例,端口为7006 7007

[root@server1 7007]# redis-server redis.conf 
3825:C 29 Aug 2020 08:14:20.903 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
3825:C 29 Aug 2020 08:14:20.903 # Redis version=5.0.8, bits=64, commit=00000000, modified=0, pid=3825, just started
3825:C 29 Aug 2020 08:14:20.903 # Configuration loaded
[root@server1 7007]# cd ../7006
[root@server1 7006]# redis-server redis.conf 
3830:C 29 Aug 2020 08:14:29.373 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
3830:C 29 Aug 2020 08:14:29.373 # Redis version=5.0.8, bits=64, commit=00000000, modified=0, pid=3830, just started
3830:C 29 Aug 2020 08:14:29.373 # Configuration loaded

将两个实例添加进集群:

redis-cli --cluster add-node 127.0.0.7:7006 127.0.0.1:7000
[root@server1 7006]# redis-cli --cluster add-node 127.0.0.7:7007 127.0.0.1:7000 --cluster-slave --cluster-master-id 38ecdbedc41959519385b6768e0844df117f45cc  (7006d的id)

此时7006上还没有hash槽。
可以使用

[root@server1 7006]# redis-cli --cluster reshard 127.0.0.1:7000 --cluster-from xxxxxxxxxxxx(7000的id) --cluster-to xxxxxxxxxxxx (7006的id)--cluster-slots 1000(分配的hash槽数) --cluster-yes

进行添加。