Redis
1 介绍
Redis(Remote Dictionary Server)是一个开源的内存数据存储系统,它可以用作数据库、缓存和消息中间件。Redis支持多种数据结构,包括字符串、哈希表、列表、集合、有序集合等。它提供了丰富的命令集合,使得开发者可以方便地对这些数据结构进行操作。
以下是Redis的一些关键特性和优势:
-
内存存储: Redis数据完全存储在内存中,因此读写速度非常快。同时,Redis也可以将数据持久化到磁盘,以防止数据丢失。
-
丰富的数据结构: Redis支持多种数据结构,包括字符串、列表、集合、有序集合、哈希表等,每种数据结构都支持丰富的操作。
-
持久化: Redis支持将数据持久化到磁盘,可以选择使用RDB快照或者AOF(Append-Only File)日志文件的方式进行持久化。
-
高可用性: Redis支持主从复制,可以创建多个Redis副本来提供高可用性和容错性。
-
分布式: Redis Cluster是Redis的分布式解决方案,它可以将数据分布到多个节点上,提供横向扩展性。
-
事务支持: Redis支持事务,可以批量执行一系列命令,保证这些命令的原子性。
-
发布/订阅模式: Redis支持发布/订阅模式,可以用于消息传递和事件通知。
-
灵活性: Redis非常灵活,可以用于多种用途,包括缓存、计数器、消息队列等。
-
社区和生态系统: Redis拥有庞大的开发者社区和丰富的生态系统,有很多客户端库、工具和扩展可以使用。
2 Redis数据类型
2.1 String类型
字符串是Redis最简单的数据类型,可以存储文本、整数或者浮点数。字符串类型是二进制安全的,意味着它可以包含任意数据,比如图片或者序列化的对象。
使用场景
- 视频的播放量统计
- 共享session
常用命令
set key value
:设置String类型的键key
的值为value
get key
:获取String类型的键key
中的值value
- 例如:
incr key
:对键key
进行递增操作decr key
:对键key
进行递减操作- 例如:
setex key timeout value
:设置键key
在指定的时间后过期,单位是秒(s)ttl key
:获取键key
剩余时间- 例如:设置age的时间为10s,10s之后自动清空
例如:设置age的时间为20s,获取剩余时间为12s
2.2 hash类型
Hash类型是一种键值对的集合,适用于存储对象(例如用户信息、商品信息等)的属性和属性值。每个Hash类型的键可以包含多个字段和字段值,类似于关联数组。
在java中的比喻:
Map<String,Map<String,?>> map
使用场景
开发中不建议使用hash类型,如果一定要用它,使用对象转换为json类型
常用命令
-
hset key field value
: 设置Hash类型的键key
中字段field
的值为value
。 -
hget key field
: 获取Hash类型的键key
中字段field
的值。 -
例如:
-
hdel key field1 field2 ...
: 删除Hash类型的键key
中的一个或多个字段。 -
hexists key field
: 判断Hash类型的键key
中是否存在字段field
。 -
例如:
-
hkeys key
: 获取Hash类型的键key
中所有的字段名。 -
havls key
: 获取Hash类型的键key
中所有的字段值。 -
hlen key
: 获取Hash类型的键key
中字段的数量。
2.3 list类型
在Redis中,List(列表)是一种有序的字符串元素集合,它可以包含字符串、数字等类型的元素。List数据类型支持在头部(左侧)和尾部(右侧)快速添加、删除元素,因此常用来实现队列、栈等数据结构,也可以用来存储有序的元素集合。
使用场景:收藏文章列表
常用命令
lpush key value [value ...]
:在列表头部(左侧)插入一个或多个值。rpush key value [value ...]
: 在列表尾部(右侧)插入一个或多个值。lpop key
:移除并返回列表头部(左侧)的元素。rpop key
:移除并返回列表尾部(右侧)的元素。lrange key start stop
:获取列表指定范围内的所有元素。llen key
:获取列表的长度。- 例如:
2.4 set类型
Set是一个无序的、不重复的元素集合。以下是关于Redis中Set类型的一些重要特点:
-
无序性: Set中的元素是无序的,不像列表(List)类型那样有顺序。
-
不重复性: Set中不允许重复的元素,每个元素都是唯一的。
-
集合操作: Redis提供了丰富的集合操作,如求交集、并集、差集等,可以方便地对集合进行操作。
常用命令
-
sadd key member [member ...]
:将一个或多个元素添加到集合中。 -
srem key member [member ...]
:从集合中移除一个或多个元素。 -
smembers key
:返回集合中的所有元素。 -
scard key
:返回集合中的元素个数。 -
例如:
2.5 zset类型
ZSET 是 Redis 提供的一种有序集合数据类型。ZSET 中的每个成员都关联着一个分值(score),Redis 使用分值来对集合中的成员进行排序。ZSET 是有序的,这意味着你可以按照分值的范围或者按照成员来查询元素。
在 ZSET 中,每个成员都是唯一的,但是分值(score)可以重复。ZSET 中的成员按照分值从小到大进行排序,分值相同的成员按照字典序进行排序。
常用命令
-
zadd key score member [score member ...]
:向有序集合中添加一个或多个成员,或者更新已存在成员的分值。 -
zrem key member [member ...]
:从有序集合中移除一个或多个成员。 -
zscore key member
:获取有序集合中指定成员的分值。 -
zrank key member
:获取有序集合中指定成员的排名(按照分值从小到大排序)。 -
zrevrank key member
:获取有序集合中指定成员的排名(按照分值从大到小排序)。 -
zrange key min max
:按照分值范围获取成员列表,可以指定返回结果的数量和起始位置。 -
zrevrank key max min
:按照分值范围从大到小获取成员列表。 -
zcard key
:获取有序集合中的成员数量。
3 Redis 安装(Linux环境)
1.安装redis所需要的依赖
yum install -y gcc tcl
2.上传 redis 压缩包到 tmp 目录下
3.解压缩redis压缩包
tar -xvf redis-6.2.4.tar.gz
4.进入解压缩目录,执行安装操作
make && make install
5.编辑 redis.confg
bind 127.0.0.1 #本地访问
bind 0.0.0.0 #任意ip都能访问
更改任意一个即可
6.启动 redis
redis-server redis.conf
结果如下:
安装成功!
7.停止 Redis 服务
redis-cli shutdown
或者 ctrl + C
4 Redis 持久化
Redis提供了两种主要的持久化方式,分别是RDB快照(Snapshotting)和AOF(Append-Only File)日志。
4.1 RDB 持久化
RDB(Redis DataBase Backup file)快照是一种周期性将内存中的数据保存到磁盘上的持久化方式。它的工作原理是在指定的时间间隔内,将整个数据集的快照保存到一个压缩的二进制文件(.rdb)中。
-
配置: RDB快照的配置在Redis的配置文件 redis.conf 中,通过以下配置项进行设置:
save 900 1 # 在900秒内如果至少有1个key被修改,则触发快照 save 300 10 # 在300秒内如果至少有10个key被修改,则触发快照 save 60 10000 # 在60秒内如果至少有10000个key被修改,则触发快照 save "" # 表示禁用RDB
-
其他配置: RDB的其它配置也可以在 redis.conf 文件中设置:
rdbcompression yes #是否压缩 ,建议不开启,压缩也会消耗cpu,磁盘的话不值钱 dbfilename dump .rdb #RDB文件名称 dir ./ #文件保存的路径目录
-
手动触发: 可以通过
save
或bgsave
命令手动触发RDB快照。- save: 由Redis的主进程执行RDB,会阻塞所有命令
- bfsave: 开启子进程执行RDB,避免主进程受到影响
-
恢复: 使用
redis-server
启动时,如果存在RDB文件,则会自动加载并恢复数据。 -
RDB原理:
bgsave命令一开始 就会 fork 主进程得到子进程 ,子进程会共享主进程的内存数据。完成 fork 之后读取内存中的数据并写入 RDB 文件。fork采用的是 copy-on-write 技术
当主进程执行读操作的时候,访问共享内存。
当主进程执行写的操作,则会拷贝一份数据,执行写操作。 -
RDB方式中的bgsave的基本流程
fork主进程得到一个子进程,共享内存空间。子进程读取内存数据并写入新的RDB文件。然后用新的RDB文件替换旧的RDB文件。 -
RDB会在什么时候执行?
服务停止的时候执行 -
RDB缺点:
RDB执行时间间隔长,两次RDB之间写入数据会有丢失数据的风险 。
fork子进程、压缩、写入RDB都比较耗时。
4.2 AOF 持久化
AOF( Append Only File)是一种以追加的方式记录每个写操作的持久化方式。它将写命令追加到一个日志文件中,以保持对数据修改的完整记录。AOF文件是一个文本文件,可以通过查看它来了解数据修改的历史。
-
配置: AOF默认是关闭的,需要修改 redis.conf 配置文件来开启 AOF:
#是否开启AOF功能,默认是no appendonly yes # 开启AOF持久化 appendfilename "appendonly.aof" # AOF文件的名字
-
AOF的命令记录的频率也可以通过 redis.conf 文件来配:
#表示每执行一次写命令,立即记录到AOF文件 appendfsync always #写命令执行完先放入AOF缓冲区,然后表示每隔1秒将缓冲区数据写到AOF文件,是默认方案 appendfsync everysec #写命令执行完先放入AOF缓冲区,由操作系统决定何时将缓冲区内容写回磁盘 appendfsync no
-
重写: 因为是记录命令,AOF文件会比RDB文件大的多。而且AOF会记录对同一个key的多次写操作,但只有最后一次写操作才有意义。通过执行
bgrewriteaof
命令,可以让AOF文件执行重写功能,用最少的命令达到相同效果。 -
Redis也会在触发阈值时自动去重写AOF文件。阈值也可以在 redis.conf 中配置:
#AOF文件比上次文件增长超过多少百分比则触发重写 auto-aof-rewrite-percentage 100 #AOF文件体积最小多大以上才触发重写 auto-aof-rewrite-min-size 64mb
-
实验:
前提:禁用RDB,启用AOF
查看 AOF 文件:
RDB 和 AOF 对比:
RDB | AOF | |
---|---|---|
使用场景 | 容忍分钟数据的丢失,追求更快的启动速度 | 对数据安全性要求较高 |
持久化方式 | 定时对整个内存做快照 | 记录每一次执行的命令 |
数据完整性 | 不完整,两次备份之间会丢失数据 | 相对完整,取决于刷盘策略 |
文件大小 | 会有压缩,文件体积小 | 记录命令,体积大 |
宕机恢复速度 | 很快 | 慢 |
数据恢复的优先级 | 低,数据完整性不如AOF | 高,数据完整性高 |
系统资源占用 | 高,大量CPU和内存消耗 | 低,主要是磁盘IO资源 |
5 Redis 主从 (一主二从 )
Redis集群是将多个Redis节点组合在一起,以提供高可用性、横向扩展性和负载均衡。在Redis集群中,数据被分片存储到多个节点上,每个节点负责其中一部分数据。
5.1 搭建主从架构
节点 | 操作 | 作用 |
---|---|---|
master | 写操作 | 主节点 |
slave1 | 读操作 | 从节点 |
slave2 | 读操作 | 从节点 |
关系如图所示:
要搭建的主从
ip | 端口 | 角色 |
---|---|---|
192.168.64.128 | 7001 | master |
192.168.64.128 | 7002 | slave |
192.168.64.128 | 7003 | slave |
1.修改 redis.confg 文件:关闭AOF, 开启RDB
# 关闭AOF
appendonly no
# 开启RDB
save 3600 1
save 300 100
save 60 10000
2.在 tmp 目录下创建三个文件夹
mkdir 7001 7002 7003
3.将刚刚修改的 redis.conf 文件拷贝到7001、7002、7003三个文件中
cp redis-6.2.4/redis.conf 7001
cp redis-6.2.4/redis.conf 7002
cp redis-6.2.4/redis.conf 7003
4.使用 sed 命令将 redis.conf 文件中的端口和 dir 保存路径进行更改
sed -i -e 's/6379/7001/g' -e 's/dir .\//dir \/tmp\/7001\//g' 7001/redis.conf
sed -i -e 's/6379/7002/g' -e 's/dir .\//dir \/tmp\/7002\//g' 7002/redis.conf
sed -i -e 's/6379/7003/g' -e 's/dir .\//dir \/tmp\/7003\//g' 7003/redis.conf
5.修改实例 ip
sed -i '1a replica-announce-ip 192.168.64.128' 7001/redis.conf
sed -i '1a replica-announce-ip 192.168.64.128' 7002/redis.conf
sed -i '1a replica-announce-ip 192.168.64.128' 7003/redis.conf
6.分别启动三个 redis
redis-server /tmp/7001/redis.conf
redis-server /tmp/7002/redis.conf
redis-server /tmp/7003/redis.conf
7.开启主从
连接 7002
redis-cli -p 7002
执行
slaveof 192.168.64.128 7001
结果:
连接 7003
redis-cli -p 7003
执行
slaveof 192.168.64.128 7001
8.查看集群状态
连接 master 7001
redis-cli -p 7001
查看状态
info replication
结果如下:
此时主从搭建完成!
主从测试:
在 master 执行 set
在 slave 执行 get
5.2 主从数据同步原理
5.2.1 全量同步
主从第一次建立连接时,会执行全量同步,将master节点的所有数据都拷贝给slave节点,流程:
这里有一个问题,master如何得知salve是第一次来连接呢??
有几个概念,可以作为判断依据:
- Replication Id:简称replid,是数据集的标记,id一致则说明是同一数据集。每一个master都有唯一的replid,slave则会继承master节点的replid
- offset:偏移量,随着记录在repl_baklog中的数据增多而逐渐增大。slave完成同步时也会记录当前同步的offset。如果slave的offset小于master的offset,说明slave数据落后于master,需要更新。
因此slave做数据同步,必须向master声明自己的replication id 和offset,master才可以判断到底需要同步哪些数据。
因为slave原本也是一个master,有自己的replid和offset,当第一次变成slave,与master建立连接时,发送的replid和offset是自己的replid和offset。
master判断发现slave发送来的replid与自己的不一致,说明这是一个全新的slave,就知道要做全量同步了。
master会将自己的replid和offset都发送给这个slave,slave保存这些信息。以后slave的replid就与master一致了。
因此,master判断一个节点是否是第一次同步的依据,就是看replid是否一致。
完整流程描述:
- slave节点请求增量同步
- master节点判断replid,发现不一致,拒绝增量同步
- master将完整内存数据生成RDB,发送RDB到slave
- slave清空本地数据,加载master的RDB
- master将RDB期间的命令记录在repl_baklog,并持续将log中的命令发送给slave
- slave执行接收到的命令,保持与master之间的同步
5.2.2 增量同步
全量同步需要先做RDB,然后将RDB文件通过网络传输个slave,成本太高了。因此除了第一次做全量同步,其它大多数时候slave与master都是做增量同步。
什么是增量同步?就是只更新slave与master存在差异的部分数据。如图:
5.2.3 repl_backlog原理
master怎么知道slave与自己的数据差异在哪里呢?
这就要说到全量同步时的repl_baklog文件了。
这个文件是一个固定大小的数组,只不过数组是环形,也就是说角标到达数组末尾后,会再次从0开始读写,这样数组头部的数据就会被覆盖。
repl_baklog中会记录Redis处理过的命令日志及offset,包括master当前的offset,和slave已经拷贝到的offset:
slave与master的offset之间的差异,就是salve需要增量拷贝的数据了。
随着不断有数据写入,master的offset逐渐变大,slave也不断的拷贝,追赶master的offset:
直到数组被填满:
此时,如果有新的数据写入,就会覆盖数组中的旧数据。不过,旧的数据只要是绿色的,说明是已经被同步到slave的数据,即便被覆盖了也没什么影响。因为未同步的仅仅是红色部分。
但是,如果slave出现网络阻塞,导致master的offset远远超过了slave的offset:
如果master继续写入新数据,其offset就会覆盖旧的数据,直到将slave现在的offset也覆盖:
棕色框中的红色部分,就是尚未同步,但是却已经被覆盖的数据。此时如果slave恢复,需要同步,却发现自己的offset都没有了,无法完成增量同步了。只能做全量同步。
注意:repl_ baklog大小有上限,写满后会覆盖最早的数据。如果slave断开时间过久,导致尚未备份的数据被覆盖,则无法基于log做增量同步,只能再次全量同步。
5.2.4 主从同步优化
主从同步可以保证主从数据的一致性,非常重要。可以从以下几个方面来优化Redis主从就集群:
- 在master中配置repl-diskless-sync yes启用无磁盘复制,避免全量同步时的磁盘IO。
- Redis单节点上的内存占用不要太大,减少RDB导致的过多磁盘IO
- 适当提高repl_baklog的大小,发现slave宕机时尽快实现故障恢复,尽可能避免全量同步
- 限制一个master上的slave节点数量,如果实在是太多slave,则可以采用主-从-从链式结构,减少master压力
6 Redis 哨兵
Redis提供了哨兵(Sentinel)机制来实现主从集群的自动故障恢复。
6.1 哨兵原理
6.1.1 集群结构和作用
哨兵的结构如图:
哨兵的作用如下:
- 监控:Sentinel 会不断检查您的master和slave是否按预期工作
- 自动故障恢复:如果master故障,Sentinel会将一个slave提升为master。当故障实例恢复后也以新的master为主
- 通知:Sentinel充当Redis客户端的服务发现来源,当集群发生故障转移时,会将最新信息推送给Redis的客户端
6.1.2 集群监控原理
Sentinel基于心跳机制监测服务状态,每隔1秒向集群的每个实例发送ping命令:
•主观下线:如果某sentinel节点发现某实例未在规定时间响应,则认为该实例主观下线。
•客观下线:若超过指定数量(quorum)的sentinel都认为该实例主观下线,则该实例客观下线。quorum值最好超过Sentinel实例数量的一半。
6.1.3 集群故障恢复原理
一旦发现master故障,sentinel需要在salve中选择一个作为新的master,选择依据是这样的:
- 首先会判断slave节点与master节点断开时间长短,如果超过指定值(down-after-milliseconds * 10)则会排除该slave节点
- 然后判断slave节点的slave-priority值,越小优先级越高,如果是0则永不参与选举
- 如果slave-prority一样,则判断slave节点的offset值,越大说明数据越新,优先级越高
- 最后是判断slave节点的运行id大小,越小优先级越高。
当选出一个新的master后,该如何实现切换呢?
流程如下:
- sentinel给备选的slave1节点发送slaveof no one命令,让该节点成为master
- sentinel给所有其它slave发送slaveof 192.168.150.101 7002 命令,让这些slave成为新master的从节点,开始从新的master上同步数据。
- 最后,sentinel将故障节点标记为slave,当故障节点恢复后会自动成为新的master的slave节点
6.1.4 小结
Sentinel的三个作用是什么?
- 监控
- 故障转移
- 通知
Sentinel如何判断一个redis实例是否健康?
- 每隔1秒发送一次ping命令,如果超过一定时间没有相向则认为是主观下线
- 如果大多数sentinel都认为实例主观下线,则判定服务下线
故障转移步骤有哪些?
- 首先选定一个slave作为新的master,执行slaveof no one
- 然后让所有节点都执行slaveof 新master
- 修改故障节点配置,添加slaveof 新master
6.2 搭建哨兵集群
6.2.1 集群结构
这里我们搭建一个三节点形成的Sentinel集群,来监管之前的Redis主从集群。如图:
三个sentinel实例信息如下:
节点 | IP | PORT |
---|---|---|
s1 | 192.168.150.101 | 27001 |
s2 | 192.168.150.101 | 27002 |
s3 | 192.168.150.101 | 27003 |
6.2.2 准备实例和配置
要在同一台虚拟机开启3个实例,必须准备三份不同的配置文件和目录,配置文件所在目录也就是工作目录。
我们创建三个文件夹,名字分别叫s1、s2、s3:
# 进入/tmp目录
cd /tmp
# 创建目录
mkdir s1 s2 s3
如图:
然后我们在s1目录创建一个sentinel.conf文件,添加下面的内容:
port 27001
sentinel announce-ip 192.168.150.101
sentinel monitor mymaster 192.168.150.101 7001 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 60000
dir "/tmp/s1"
解读:
port 27001
:是当前sentinel实例的端口sentinel monitor mymaster 192.168.150.101 7001 2
:指定主节点信息mymaster
:主节点名称,自定义,任意写192.168.150.101 7001
:主节点的ip和端口2
:选举master时的quorum值
然后将s1/sentinel.conf文件拷贝到s2、s3两个目录中(在/tmp目录执行下列命令):
# 方式一:逐个拷贝
cp s1/sentinel.conf s2
cp s1/sentinel.conf s3
# 方式二:管道组合命令,一键拷贝
echo s2 s3 | xargs -t -n 1 cp s1/sentinel.conf
修改s2、s3两个文件夹内的配置文件,将端口分别修改为27002、27003:
sed -i -e 's/27001/27002/g' -e 's/s1/s2/g' s2/sentinel.conf
sed -i -e 's/27001/27003/g' -e 's/s1/s3/g' s3/sentinel.conf
6.2.3 启动
为了方便查看日志,我们打开3个ssh窗口,分别启动3个redis实例,启动命令:
# 第1个
redis-sentinel s1/sentinel.conf
# 第2个
redis-sentinel s2/sentinel.conf
# 第3个
redis-sentinel s3/sentinel.conf
启动后:
6.2.4 测试
尝试让master节点7001宕机,查看sentinel日志:
查看7003的日志:
查看7002的日志:
7 Redis 分片集群
7.1 搭建分片集群
主从和哨兵可以解决高可用、高并发读的问题。但是依然有两个问题没有解决:
-
海量数据存储问题
-
高并发写的问题
使用分片集群可以解决上述问题,如图:
分片集群特征:
-
集群中有多个master,每个master保存不同数据
-
每个master都可以有多个slave节点
-
master之间通过ping监测彼此健康状态
-
客户端请求可以访问集群任意节点,最终都会被转发到正确节点
7.1.1 集群结构
分片集群需要的节点数量较多,这里我们搭建一个最小的分片集群,包含3个master节点,每个master包含一个slave节点,结构如下:
这里我们会在同一台虚拟机中开启6个redis实例,模拟分片集群,信息如下:
IP | PORT | 角色 |
---|---|---|
192.168.64.128 | 8001 | master |
192.168.64.128 | 8002 | master |
192.168.64.128 | 8003 | master |
192.168.64.128 | 9001 | slave |
192.168.64.128 | 9002 | slave |
192.168.64.128 | 9003 | slave |
7.1.2 准备实例和配置
创建出8001、8002、 8003、 9001 、9002、 9003这几个目录:
# 进入/tmp目录
cd /tmp
# 创建目录
mkdir 8001 8002 8003 9001 9002 9003
在/tmp下准备一个新的redis.conf文件,内容如下:
port 6379
# 开启集群功能
cluster-enabled yes
# 集群的配置文件名称,不需要我们创建,由redis自己维护
cluster-config-file /tmp/6379/nodes.conf
# 节点心跳失败的超时时间
cluster-node-timeout 5000
# 持久化文件存放目录
dir /tmp/6379
# 绑定地址
bind 0.0.0.0
# 让redis后台运行
daemonize yes
# 注册的实例ip
replica-announce-ip 192.168.64.128
# 保护模式
protected-mode no
# 数据库数量
databases 1
# 日志
logfile /tmp/6379/run.log
将这个文件拷贝到每个目录下:
# 进入/tmp目录
cd /tmp
# 执行拷贝
echo 8001 8002 8003 9001 9002 9003 | xargs -t -n 1 cp redis.conf
修改每个目录下的redis.conf,将其中的6379修改为与所在目录一致:
# 进入/tmp目录
cd /tmp
# 修改配置文件
printf '%s\n' 8001 8002 8003 9001 9002 9003 | xargs -I{} -t sed -i 's/6379/{}/g' {}/redis.conf
7.1.3 启动
因为已经配置了后台启动模式,所以可以直接启动服务:
# 进入/tmp目录
cd /tmp
# 一键启动所有服务
printf '%s\n' 8001 8002 8003 9001 9002 9003 | xargs -I{} -t redis-server {}/redis.conf
通过ps查看状态:
ps -ef | grep redis
发现服务都已经正常启动:
如果要关闭所有进程,可以执行命令:
ps -ef | grep redis | awk '{print $2}' | xargs kill
或者(推荐这种方式):
printf '%s\n' 8001 8002 8003 9001 9002 9003 | xargs -I{} -t redis-cli -p {} shutdown
7.1.4 创建集群
虽然服务启动了,但是目前每个服务之间都是独立的,没有任何关联。
我们需要执行命令来创建集群,在Redis5.0之前创建集群比较麻烦,5.0之后集群管理命令都集成到了redis-cli中。
1)Redis5.0之前
Redis5.0之前集群命令都是用redis安装包下的src/redis-trib.rb来实现的。因为redis-trib.rb是有ruby语言编写的所以需要安装ruby环境。
# 安装依赖
yum -y install zlib ruby rubygems
gem install redis
然后通过命令来管理集群:
# 进入redis的src目录
cd /tmp/redis-6.2.4/src
# 创建集群
./redis-trib.rb create --replicas 1 192.168.64.128:8001 192.168.64.128:8002 192.168.64.128:8003 192.168.64.128:9001 192.168.64.128:9002 192.168.64.128:9003
2)Redis5.0以后
我们使用的是Redis6.2.4版本,集群管理以及集成到了redis-cli中,格式如下:
redis-cli --cluster create --cluster-replicas 1 192.168.64.128:8001 192.168.64.128:8002 192.168.64.128:8003 192.168.64.128:9001 192.168.64.128:9002 192.168.64.128:9003
命令说明:
redis-cli --cluster
或者./redis-trib.rb
:代表集群操作命令create
:代表是创建集群--replicas 1
或者--cluster-replicas 1
:指定集群中每个master的副本个数为1,此时节点总数 ÷ (replicas + 1)
得到的就是master的数量。因此节点列表中的前n个就是master,其它节点都是slave节点,随机分配到不同master
运行后的样子:
这里输入yes,则集群开始创建:
通过命令可以查看集群状态:
redis-cli -p 7001 cluster nodes
7.1.5 测试
尝试连接8001节点,存储一个数据:
# 连接
redis-cli -p 8001
# 存储数据
set nums 123
结果悲剧了:
集群操作时,需要给redis-cli
加上-c
参数才可以:
redis-cli -c -p 8001
这次可以了:
7.2 散列插槽
7.2.1 插槽原理
Redis会把每一个master节点映射到0~16383共16384个插槽(hash slot)上,查看集群信息时就能看到:
数据key不是与节点绑定,而是与插槽绑定。redis会根据key的有效部分计算插槽值,分两种情况:
- key中包含"{}",且“{}”中至少包含1个字符,“{}”中的部分是有效部分
- key中不包含“{}”,整个key都是有效部分
例如:key是num,那么就根据num计算,如果是{itcast}num,则根据itcast计算。计算方式是利用CRC16算法得到一个hash值,然后对16384取余,得到的结果就是slot值。
如图,在8001这个节点执行set c 1
时,对c做hash运算,对16384取余,得到的结果是7365,因此要存储到103节点。
到了8002后,执行get num
时,对num做hash运算,对16384取余,得到的结果是2765,因此需要切换到8001节点
7.2.2 小结
Redis如何判断某个key应该在哪个实例?
- 将16384个插槽分配到不同的实例
- 根据key的有效部分计算哈希值,对16384取余
- 余数作为插槽,寻找插槽所在实例即可
如何将同一类数据固定的保存在同一个Redis实例?
- 这一类数据使用相同的有效部分,例如key都以{typeId}为前缀