本文使用的系统是CenterOS7
安装VMware虚拟机的过程在这里不多赘述。
详情可以查看:xxxxx(待撰写)
本文直接从安装redis开始记录。
目录
目录
一.前期准备
1.准备好VMware虚拟机
2.准备好redis安装包
可以通过下面的链接进行访问下载,本文中使用版本为redis-3.0.7.tar.gz
二.开始简单安装Redis
1.上传redis安装包
本文通过FinalShell连接虚拟机,将下载的redis安装包上传在/usr/mine位置中。

2.解压安装包
使用命令:
--使用cd命令进入安装包存放位置
cd /usr/mine
--将安装包解压到/usr/local位置
tar -zxvf redis-3.0.7.tar.gz -C /usr/local
解压后可以看到redis目录,如图

3.安装Redis的依赖环境gcc
使用命令:yum install gcc-c++
此处可能会有命令失败的情况,如图

此时可以根据下列步骤操作,修改YUM仓库镜像源为阿里云
找到下面目录下的CentOS-Base.repo文件
/etc/yum.repos.d/CentOS-Base.repo
文件如图
将CentOS-Base.repo文件内容替换为以下内容:
[base]
name=CentOS-$releasever - Base - mirrors.aliyun.com
baseurl=http://mirrors.aliyun.com/centos/$releasever/os/$basearch/
gpgcheck=1
gpgkey=http://mirrors.aliyun.com/centos/RPM-GPG-KEY-CentOS-7[updates]
name=CentOS-$releasever - Updates - mirrors.aliyun.com
baseurl=http://mirrors.aliyun.com/centos/$releasever/updates/$basearch/
gpgcheck=1
gpgkey=http://mirrors.aliyun.com/centos/RPM-GPG-KEY-CentOS-7[extras]
name=CentOS-$releasever - Extras - mirrors.aliyun.com
baseurl=http://mirrors.aliyun.com/centos/$releasever/extras/$basearch/
gpgcheck=1
gpgkey=http://mirrors.aliyun.com/centos/RPM-GPG-KEY-CentOS-7[centosplus]
name=CentOS-$releasever - Plus - mirrors.aliyun.com
baseurl=http://mirrors.aliyun.com/centos/$releasever/centosplus/$basearch/
gpgcheck=1
enabled=0
gpgkey=http://mirrors.aliyun.com/centos/RPM-GPG-KEY-CentOS-7
也可直接执行下面的命令:
sudo cat <<EOF > /etc/yum.repos.d/CentOS-Base.repo
[base]
name=CentOS-\$releasever - Base - mirrors.aliyun.com
baseurl=http://mirrors.aliyun.com/centos/\$releasever/os/\$basearch/
gpgcheck=1
gpgkey=http://mirrors.aliyun.com/centos/RPM-GPG-KEY-CentOS-7
[updates]
name=CentOS-\$releasever - Updates - mirrors.aliyun.com
baseurl=http://mirrors.aliyun.com/centos/\$releasever/updates/\$basearch/
gpgcheck=1
gpgkey=http://mirrors.aliyun.com/centos/RPM-GPG-KEY-CentOS-7
[extras]
name=CentOS-\$releasever - Extras - mirrors.aliyun.com
baseurl=http://mirrors.aliyun.com/centos/\$releasever/extras/\$basearch/
gpgcheck=1
gpgkey=http://mirrors.aliyun.com/centos/RPM-GPG-KEY-CentOS-7
[centosplus]
name=CentOS-\$releasever - Plus - mirrors.aliyun.com
baseurl=http://mirrors.aliyun.com/centos/\$releasever/centosplus/\$basearch/
gpgcheck=1
enabled=0
gpgkey=http://mirrors.aliyun.com/centos/RPM-GPG-KEY-CentOS-7
EOF
保存文件并退出。
使用下面命令清理并重建缓存
sudo yum clean all
sudo yum makecache
sudo yum update
在执行过程中可能会有需要输入y进行下一步的情况,一直输入y继续即可。
执行完上述操作后,重新执行yum install gcc-c++ 命令,即可安装成功

4.进行编译
执行命令 cd /usr/local/redis-3.0.7 进入redis目录下
执行命令 make 进行编译
如下图所示:


5.进行安装
进入redis的src目录下 命令:cd /usr/local/redis-3.0.7/src
进行安装,命令: make install
如下图,即可

如果不安装在src目录下,可以额外操作下面的命令:
如果此处想将redis安装在其他目录下,可以使用命令:
make PREFIX=指定的目录绝对路径 install
拷贝解压缩后的配置到安装目录, 命令:
cp /usr/local/redis/redis-3.0.7/redis.conf 指定的目录绝对路径/bin
6.启动Redis
/usr/local/redis-4.0.0/src/redis-server:Redis服务启动脚本
/usr/local/redis-4.0.0/src/redis-cli:Redis客户端脚本
/usr/local/redis-4.0.0/redis.conf:Redis配置文件
在src目录下执行命令: ./redis-server 即可启动

启动成功,redis安装成功!
7.配置文件
(1)修改redis端口及后台启动redis
如果想修改redis的默认端口6379,可以通过两种方式:
1.通过启动命令指定 ./redis-server -port 7777 即可将端口修改为7777
2.通过修改/usr/local/redis-3.0.7/redis.conf文件实现。

通过修改Redis配置文件可以进行如下配置:
1)设置Redis服务后台运行
将配置文件中的==daemonize==配置项改为yes,默认值为no。
注意:Windows版的Redis不支持后台运行。
2)设置Redis服务密码
将配置文件中的 ==# requirepass foobared== 配置项取消注释,默认为注释状态。foobared为密码,可以根据情况自己指定。
3)设置允许客户端远程连接Redis服务
Redis服务默认只能客户端本地连接,不允许客户端远程连接。将配置文件中的 ==bind 127.0.0.1== 配置项注释掉。
修改redis.conf配置文件的 69行 bind 0.0.0.0
解释说明:
Redis配置文件中 # 表示注释
Redis配置文件中的配置项前面不能有空格,需要顶格写
daemonize:用来指定redis是否要用守护线程的方式启动,设置成yes时,代表开启守护进程模式。在该模式下,redis会在后台运行
requirepass:设置Redis的连接密码
bind:如果指定了bind,则说明只允许来自指定网卡的Redis请求。如果没有指定,就说明可以接受来自任意一个网卡的Redis请求。
注意:修改配置文件后需要重启Redis服务配置才能生效,并且启动Redis服务时需要显示的指定配置文件:
# 进入Redis安装目录
cd /usr/local/redis-3.0.7
# 启动Redis服务,指定使用的配置文件
./src/redis-server ./redis.conf
8.公布端口
公布 6379端口号到防火墙
命令: firewall-cmd --zone=public --add-port=6379/tcp --permanent
公布完端口后,需要重启防火墙
命令: firewall-cmd --reload
查看已公布的端口:
命令: firewall-cmd --zone=public --list-ports
如此即可进行远程访问。
三.redis高阶
1.redis事务
redis 是支持事务机制的,通过如下命令可以开启事务。
#开启事务
multi
#添加命令
sadd user:1001:follow 1002
sadd user:1002:follow 1001
sadd user:1001:fans 1002
sadd user:1002:fans 1002
#执行事务
exec
# 取消事务
discard
但是redis的事务机制较为鸡肋。
Redis对于命令执行错误处理,有两种解决方式:
- 语法错误(编译)
- 执行错误(运行)
(1)语法错误
#开启事务
multi
#命令
set name zhangsan
set age
seterror sex male
#执行事务
exec
#获取正确指令数据
get name

如上图所示,开启事务后,先执行正确命令,再执行语法错误的命令,提交后,正确命令也被回滚。达到了事务需求。
(2)执行错误
#开启事务
multi
#命令
set name zhangsan
set age
seterror sex male
#执行事务
exec
#获取正确指令数据
get name

如图所示 ,第二条命令执行错误,但提交事务后,第一条和第三条命令仍然被正确执行了,此时事务没有明显效果。
(3)SpringBoot实现事务操作
//1)修改RedisConfig配置类,开启事务控制
redisTemplate.setEnableTransactionSupport(true);
//2)自定义方法,测试事务效果
@Test
@Transactional(rollbackFor = Exception.class)
public void multiTest(){
//开启事务
redisTemplate.multi();
try{
redisTemplate.opsForValue().set("lesson","java");
redisTemplate.opsForSet().add("lesson","eureka","feign","gateway");
redisTemplate.opsForValue().set("lesson","redis");
System.out.println(redisTemplate.opsForValue().get("lesson"));
}catch (Exception e){
//回滚
System.out.println("出现异常");
redisTemplate.discard();
}finally {
redisTemplate.exec();
}
}
2.持久化机制
Redis将数据保存在内存中。一旦服务器宕机重启,内存中的数据就会丢失。当出现这种情况后,为了能够让Redis进行数据恢复,因此Redis提供了持久化机制,将内存中的数据保存到磁盘中,避免数据意外丢失。
Redis提供了两种持久化机制:RDB、AOF。 根据不同的场景,可以选择只使用其中一种或一起使用。
(1)RDB快照
①概述
RDB(Redis DataBase)是Redis默认存储方式。其基于快照思想,当符合一定条件(手动或自动触发)时,Redis会将这一刻的内存数据进行快照并保存在磁盘上,产生一个经过压缩的二进制文件,文件后缀名.rdb。
因为RDB文件是保存在磁盘上的,因此即使Redis进程退出,甚至服务器宕机重启。只要RDB文件存在,就可以利用它来还原Redis数据。

②RDB触发条件
1.符合配置文件中的快照规则
在redis.conf文件中配置了一些默认触发机制
save "" # 不使用RDB存储 不能主从
save 3600 1 #表示1小时内至少1个键被更改则进行快照。
save 300 100 #表示5分钟(300秒)内至少100个键被更改则进行快照。
save 60 10000 #表示1分钟内至少10000个键被更改则进行快照。
但使用该种方式,当redis宕机时,重新恢复,会丢失最后一次快照之后的所有数据。
2.手动执行save或bgsave命令
在redis客户端执行save或bgsave命令,手动触发RDB快照
#进入客户端
/usr/local/redis3.0.7/src/redis-cli#执行save命令(同步执行)
save#执行bgsave命令(异步子线程执行)
bgsave
两个命令的区别:
- save:同步处理,阻塞Redis服务进程,服务器不会处理任何命令,直到RDB文件保存完毕。
- bgsave:会fork一个和主线程一致的子线程负责操作RDB文件,不会阻塞Redis服务进程,操作RDB文件的同时仍然可以处理命令。
- Redis默认使用的是 bgsave 来保存快照数据。
1)Redis服务进程判断,当前是否有子线程在执行save或bgsave。
2)如果有,则直接返回,不做任何处理。
3)如果没有,则以阻塞式创建子线程,在创建子线程期间,Redis不处理任何命令。
4)创建完子线程后,取消阻塞,Redis服务继续响应其他命令。
5)同时基于子线程操作RDB文件,将此刻数据保存到磁盘。
③优缺点
优点:
- 基于二进制文件完成数据备份,占用空间少,便于文件传输。
- 能够自定义规则,根据Redis繁忙状态进行数据备份。
缺点:
- 无法保证数据完整性,会丢失最后一次快照后的所有数据。
- bgsave执行每次执行都会阻塞Redis服务进程创建子线程,频繁执行影响系统吞吐率。
④配置文件关于rdb部分详解
#通过配置文件配置自动写入rdb文件的条件 save 间隔(秒) 频率 save 3600 1 #表示1小时内至少1个键被更改则进行快照。 save "" # 不使用RDB存储 不能主从 # 是否在 bgsave 失败时停止写操作 stop-writes-on-bgsave-error yes # 是否在生成 RDB 文件时使用 LZF 压缩(节省磁盘空间,但会增加 CPU 开销) rdbcompression yes # 是否在 RDB 文件末尾添加 CRC64 校验(提高 RDB 文件的抗损坏能力,但会带来一定的性能损失。) rdbchecksum yes # 写出rdb文件的名称 默认为dump.rdb dbfilename dump.rdb # 是否在 RDB 持久化操作成功完成后删除临时文件 rdb-del-sync-files no # rbd文件存储位置 dir /usr/local/redis-6.2.9/rdbsave
(2)AOF
①概述
AOF(append only file)是Redis提供了另外一种持久化机制。与RDB记录数据不同,当开启AOF持久化后,Redis会将客户端发送的所有更改数据的命令,记录到磁盘中的AOF文件。 这样的话,当Redis重启后,通过读取AOF文件,按顺序获取到记录的数据修改命令,即可完成数据恢复。

②基础使用
AOF方式需要手动开启,修改redis.conf配置文件
# 是否开启AOF,默认为no appendonly yes # 此配置项指定 AOF 文件的名称。 appendfilename appendonly.aof # 此配置项控制 AOF 文件的同步策略。 always/everysec/no # no:不调用 fsync,让操作系统决定何时将数据写入磁盘,性能最高,但最不安全。 # always:每次写操作后立即调用 fsync,最安全但性能最低。 # everysec:每秒调用一次 fsync,性能和安全性之间的平衡。 appendfsync everysec # 此配置项控制在 AOF 重写期间是否禁用 fsync # yes:在 AOF 重写期间禁用 fsync,可以减少 I/O 压力,但会降低数据安全性。 # no:在 AOF 重写期间继续调用 fsync,保证数据安全性。 no-appendfsync-on-rewrite no # 此配置项控制 AOF 文件自动重写的触发条件,基于文件大小增长的百分比。当 AOF 文件大小增长超过指定的百分比时,触发 AOF 重写。 auto-aof-rewrite-percentage 100 # 此配置项控制 AOF 文件自动重写的最小文件大小,只有当 AOF 文件大小超过指定的最小值时,才会触发 AOF 重写 auto-aof-rewrite-min-size 64mb # 此配置项控制 Redis 在启动时如何处理截断的 AOF 文件。 # yes:加载尽可能多的数据并启动 Redis,同时记录日志。 # no:如果 AOF 文件被截断,则 Redis 将拒绝启动,需要使用 redis-check-aof 工具修复 AOF 文件。 aof-load-truncated yes # 此配置项控制是否在 AOF 文件中使用 RDB 前缀。 # yes:在 AOF 文件中使用 RDB 前缀,加快 AOF 重写和恢复速度。 # no:不使用 RDB 前缀。 aof-use-rdb-preamble yes
修改redis.conf,开启了AOF之后,重启redis。

执行redis命令后,查看dir指定的目录,可以看到生成了aof文件。

打开该文件查看,可以看到我们刚刚执行的写命令被记录在aof文件中,读命令不会被记录。
③执行原理
AOF功能实现的整个执行过程可以分为三个部分:命令追加、文件写入、文件同步。

1)客户端向Redis发送写命令。
2)Redis将接收到的写命令保存到缓冲文件aof_buf的末尾。 这个过程是命令追加。
3)redis将缓冲区文件内容写入到AOF文件,这个过程是文件写入。
4)redis根据策略将AOF文件保存到磁盘,这个过程是文件同步。
5)何时将AOF文件同步到磁盘的策略依据就是redis.conf文件中appendfsync属性值:always、everysec、no。
- always:每次执行写入命令都会将aof_buf缓冲区文件全部内容写入到AOF文件中,并将AOF文件同步到磁盘。该方式效率最低,安全性最高。
- everysec:每次执行写入命令都会将aof_buf缓冲区文件全部内容写入到AOF文件中。 并且每隔一秒会由子线程将AOF文件同步到磁盘。该方式兼备了效率与安全,即使出现宕机重启,也只会丢失不超过两秒的数据。
- no:每次执行写入命令都会将aof_buf缓冲区文件全部内容写入到AOF文件中,但并不对AOF文件进行同步磁盘。 同步操作交由操作系统完成(每30秒一次),该方式最快,但最不安全。
④AOF重写优化
概述:AOF会将对Redis操作的所有写命令都记录下来,随着服务器的运行,AOF文件内保存的内容会越来越多。这样就会造成两个比较严重的问题:占用大量存储空间、数据还原花费的时间多。为了解决AOF文件巨大的问题,Redis提供了AOF文件重写功能。 当AOF文件体积超过阈值时,则会触发AOF文件重写,Redis会开启子线程创建一个新的AOF文件替代现有AOF文件。 新的AOF文件不会包含任何浪费空间的冗余命令,只存在恢复当前Redis状态的最小命令集合。
触发配置:
配置文件中修改配置,自动重写AOF
#当前aof文件大小超过上一次aof文件大小的百分之多少时进行重写。如果之前没有重写过,以
启动时aof文件大小为准
auto-aof-rewrite-percentage 100
#限制允许重写最小aof文件大小,也就是文件大小小于64mb的时候,不需要进行优化
auto-aof-rewrite-min-size 64mb
手动执行bgrewriteaof命令重写aof
通过redis-cli执行命令bgrewriteaof 之后的aof文件内容如下

可以看到文件内容被重写,文件大小也发生了变化。
(3)RDB与AOF对比
- RDB默认开启,AOF需手动开启。
- RDB性能优于AOF。
- AOF安全性优于RDB。
- AOF优先级高于RDB(混合模式)。
- RDB存储某个时刻的数据快照,AOF存储写命令。
- RDB在配置触发状态会丢失最后一次快照以后更改的所有数据,AOF默认使用everysec,每秒保存一次,最多丢失两秒以内的数据。
(4)生产环境下持久化实践
- 如当前只追求高性能,不关注数据安全性,则关闭RDB和AOF,如redis宕机重启,直接从数据源恢复数据。
- 如需较高性能且关注数据安全性,则开启RDB,并定制触发规则。当开启RDB后发现,Redis数据量过多,服务线程被频繁阻塞,造成系统性能严重下降,则开启AOF。
- 如更关注数据安全性,则开启AOF。
3.高可用-主从复制
通过持久化机制的学习, 可以发现,不管是RDB还是AOF,都并不能百分百的避免数据丢失。关键是现在只有一台服务器,持久化数据都是保存在这台服务器的磁盘上,假设这台服务器的磁盘损坏,数据仍然会全部丢失。 那这个问题该怎么解决呢?
那我们想一下,现在所有持久化数据只是保存在一台服务器上,能不能让它们同时保存在多台服务器上,这样即使一台服务器出现问题,仍然可以从其他服务器同步数据。
这样就需要当一台服务器中数据更新后,可以自动的将更新的数据同步到其他服务器上, 这就是所谓的复制。

(1)复制搭建&使用
安装环境及redis
#安装gcc
yum install -y gcc-c++ autoconf automake
#centos7 默认的 gcc 默认是4.8.5,版本小于 5.3 无法编译,需要先安装gcc新版才能编译
gcc -v
#升级新版gcc,配置永久生效
yum -y install centos-release-scl
yum -y install devtoolset-9-gcc devtoolset-9-gcc-c++ devtoolset-9-binutilsscl enable devtoolset-9 bash
echo "source /opt/rh/devtoolset-9/enable" >>/etc/profile
上面的步骤可能会报错Cannot find a valid baseurl for repo: centos-sclo-rh/x86_64。
可以通过如下步骤解决:
//进入目录
cd /etc/yum.repos.d
//找到文件CentOS-SCLo-scl.repo和CentOS-SCLo-scl-rh.repo,进行重命名使其失效
mv CentOS-SCLo-scl.repo CentOS-SCLo-scl.repo.bak
mv CentOS-SCLo-scl-rh.repo CentOS-SCLo-scl-rh.repo.bak
//编辑vim CentOS-SCLo-scl-rh.repo文件,直接将下面内容粘贴进去
[centos-sclo-rh]
name=CentOS-7 - SCLo rh
baseurl=https://mirrors.aliyun.com/centos/7/sclo/x86_64/rh/
gpgcheck=1
enabled=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-SIG-SCLo
//保存即可
#到Redis的源码包上传并且编译redis
cd redis-6.2.4
make#安装到指定目录
mkdir -p /usr/local/redismake PREFIX=/usr/local/redis install
#
vm.overcommit_memory可以设置为 0、1 或 2,每种模式有不同的行
0(默认值):
- 描述:内核会尝试估算应用程序的内存需求,并允许一定程度的过度承诺(overcommit)。内核会根据系统当前的内存使用情况和历史数据来决定是否允许内存分配。
- 行为:如果内核认为有足够的内存来满足请求,它会允许内存分配;否则,可能会拒绝分配请求。
- 适用场景:适用于大多数通用场景,但对于内存需求非常严格的场景可能不够可靠。
1:
- 描述:内核总是允许内存分配,即使没有足够的物理内存来满足请求。这种模式下,内核会过度承诺内存,依赖于交换分区(swap)来处理内存不足的情况。
- 行为:内核会无条件地允许内存分配请求,但可能会导致系统在内存不足时使用交换分区,从而影响性能。
- 适用场景:适用于需要最大化内存利用率的场景,但可能会导致系统不稳定和性能下降。
2:
- 描述:内核会严格检查是否有足够的物理内存和交换分区来满足内存分配请求。这种模式下,内核不会过度承诺内存。
- 行为:如果内核确定没有足够的内存来满足请求,它会拒绝内存分配请求。
- 适用场景:适用于需要高度可靠的内存管理的场景,确保系统在内存不足时不会崩溃。
sysctl vm.overcommit_memory=1
# 为了使设置永久生效,可以将配置添加到
/etc/sysctl.conf文件中echo "vm.overcommit_memory=1" >> /etc/sysctl.conf
sysctl -p
配置主节点
将redis.conf配置文件中下列配置进行修改:
# 允许任何连接
bind 0.0.0.0
# 当设置了密码后 该选项可以关闭
protected-mode no
# 端口
port 6379
# 后台运行配置
daemonize yes
# redis密码
requirepass "123456"
# 输入日志的路径和日志文件名称
logfile "/usr/local/redis/logs/redis_6379.log"
# rdb文件的名称
dbfilename "redis_6379.rdb"
# rdb文件的生成目录
dir "/usr/local/redis/data"
# 开启aof
appendonly yes
# aof文件的名称
appendfilename "appendonly_6379.aof"
# 主从模式下,主节点的密码
masterauth "123456"
配置从节点
创建一个新的虚拟机,执行上述操作,安装好redis后修改redis.conf文件
bind 0.0.0.0
protected-mode no
port 6380
daemonize yes
requirepass "123456"
logfile "/usr/local/redis/logs/redis_6380.log"
dbfilename "redis_6380.rdb"
dir "/usr/local/redis/data"
appendonly yes
appendfilename "appendonly_6380.aof"
# 主节点的密码
masterauth "123456"
# 主节点的ip和端口
replicaof 192.168.200.151 6379
可以看出,主节点和从节点的配置上,最主要的差异就是replicaof,配置了该配置的节点会被当做从节点注册到配置的主节点上
简单验证
启动三台redis服务器,进入redis-cli执行命令INFO REPLICATION,可以查看到redis的主从连接情况,如下图:

图中可以看出,当前服务器redis角色为master,有两台从服务器,分别为192.168.187.130:6379和192.168.187.131:6379
进入到192.168.187.130:6379,通过redis-cli执行命令INFO REPLICATION,可以看到

此时,主从搭建已经完成了,下面可以进行简单测试。
在主节点上写入命令

在从节点上成功读到

注意:只能主写从读
(2)生产环境下主从复制实践
①读写分离
在生产环境下,读请求会远远多于写请求,大概10:1的比率。 当单机无法应对大量读请求时,可以通过主从复制机制,实现读写分离。主节点只负责写请求,从节点只负责读请求。

②持久化优化
现在如果master和所有的slave都开启持久化的话,性能相对来说比较低。该如何优化提升性能呢?
我们可以在从节点上开启持久化、在主节点关闭持久化。 但是这样的话,数据不会丢失吗?
在主从复制的结构下,无非要么主节点宕机,要么从节点宕机。
- 当从节点宕机重启后,主节点会自动的将数据同步到从节点上。所以不会出现数据丢失。
- 当主节点宕机后,可以将从节点提升为主节点(slaveof no one),继续对外提供服务。 并且当原先的主节点重启后,使用slaveof命令将其设置为新主节点的从节点,即可完成数据同步。
#中断端口为6379的redis主节点服务进程
#将从节点提升为新的主节点
slaveof no one
#在从节点添加数据
sadd lessons java redis rocketmq
#启动主节点
#将6379节点作为从节点连接到新的主节点192.168.187.130 6379
slaveof 192.168.187.130 6379
#6379节点获取断开连接期间数据
smembers lessons

如图,130机器变为主节点。
③主从复制总结

具体步骤:
1、Slave服务启动,主动连接Master,并发送SYNC命令,请求初始化同步;
2、Master收到SYNC后,执行BGSAVE命令生成RDB文件,并缓存该时间段内的写命令;
3、Master完成RDB文件后,将其发送给所有Slave服务器;
4、Slave服务器接收到RDB文件后,删除内存中旧的缓存数据,并装载RDB文件;
5、Master在发送完RDB后,即刻向所有Slave服务器发送缓存中的写命令;
主从复制的作用:
- 读写分离:主写从读,提高服务器的读写负载能力
- 负载均衡:基于主从结构,配合读写分离,由slave分担master负载,并根据需求的变化,改变slave的数量,通过多个从节点分担数据读取负载,大大提高Redis服务器并发量与数据吞吐量
-
故障恢复:当master出现问题时,由slave提供服务,实现快速的故障恢复
-
数据冗余:实现数据热备份,是持久化之外的一种数据冗余方式
-
高可用基石:基于主从复制,构建哨兵模式与集群,实现Redis的高可用方案
4.哨兵模式
(1)概述

如上图:
-
如果客户端发送的读请求,可以由从库继续提供服务
-
如果客户端发送的写请求,需要主库提供服务,但是主库挂了
无论是写服务中断,还是从库无法进行数据同步,都是不能接受的。所以,如果主库挂了,我们就需要运行一个新主库,比如说把一个从库切换为主库,把它当成主库。
这就涉及到三个问题:
-
主库真的挂了吗?
-
该选择哪个从库作为主库?
-
怎么把新主库的相关信息通知给从库和客户端呢?
这就要提到哨兵机制了。在 Redis 主从集群中,哨兵机制是实现主从库自动切换的关键机
制,它有效地解决了主从复制模式下故障转移的这三个问题。
哨兵(sentinel) 是一个分布式系统,用于对主从结构中的每台服务器进行监控,当出现故障时通过投票机制选择新的master并将所有slave连接到新的master。

注意:
哨兵也是一台redis服务器,只是不提供数据服务
通常哨兵配置数量为单数
如果配置启用单节点哨兵,如果有哨兵实例在运行时发生了故障,主从库无法正常切换啦,所以我们需要搭建 哨兵集群
(2)集群节点哨兵模式

Redis提供了哨兵的命令,是一个独立的进程
原理:哨兵通过发送命令给多个节点,等待Redis服务器响应,从而监控运行的多个Redis实例的运行情况
当哨兵监测到master宕机,会自动将slave切换成master,通过通知其他的从服务器,修改配置文件切换主机
①Sentinel三大工作任务
- 监控(Monitoring):Sentinel 会不断地检查你的主服务器和从服务器是否运作正常
- 通知(Notification):当被监控的某个 Redis 服务器出现问题时, Sentinel 可以通过 API 向管理员或者其他应用程序发送通知。
- 自动故障迁移(Automatic failover):当一个主服务器不能正常工作时, Sentinel 会开始一次自动故障迁移操作, 它会将失效主服务器的其中一个从服务器升级为新的主服务器, 并让失效主服务器的其他从服务器改为复制新的主服务器,当客户端试图连接失效的主服务器时, 集群也会向客户端返回新主服务器的地址, 使得集群可以使用新主服务器代替失效服务器
②客观下线和主观下线
主观下线(Subjectively Down, 简称 SDOWN)
哨兵进程会使用 PING 命令检测它自己和主、从库的网络连接情况,用来判断实例的状态。如果哨兵发现主库或从库对 PING 命令的响应超时了,那么,哨兵就会先把它标记为“主观下线”
一个服务器没有在 down-after-milliseconds 选项所指定的时间内, 对向它发送 PING 命令的 Sentinel 返回一个有效回复(valid reply), 那么 Sentinel 就会将这个服务器标记为主观下线
如果检测的是从库,那么,哨兵简单地把它标记为“主观下线”就行了,因为从库的下线影响一般不太大,集群的对外服务不会间断。
如果检测的是主库,那么,哨兵还不能简单地把它标记为“主观下线”,开启主从
切换。因为很有可能存在这么一个情况:那就是哨兵**误判**了,其实主库并没有故障。可是,一旦启动了主从切换,后续的选主和通知操作都会带来额外的计算和通信开销。(我们要知道啥叫误判。很简单,就是主库实际并没有下线,但是哨兵误以为它下线了。误判一般会发生在集群网络压力较大、网络拥塞,或者是主库本身压力较大的情况下。)
客观下线(Objectively Down, 简称 ODOWN)
- 指的是多个 Sentinel 实例在对同一个服务器做出 SDOWN 判断, 并且通过 SENTINEL is-master-down-by-addr 命令互相交流之后, 得出的服务器下线判断。
- 一个 Sentinel 可以通过向另一个 Sentinel 发送 SENTINEL is-master-down-by-addr 命令来询问对方是否认为给定的服务器已下线(客观下线条件只适用于主服务器)。
仲裁 qurum
Sentinel 在给定的时间范围内, 从其他 Sentinel 那里接收到了【足够数量】的主服务器下线报告, 那么 Sentinel 就会将主服务器的状态从主观下线改变为客观下线。
- 这个【足够数量】就是配置文件里面的值,一般是Sentinel个数的一半加1,比如3个Sentinel则就设置为2。
- down-after-milliseconds 是一个哨兵在超过规定时间依旧没有得到响应后,会自己认为主机不可用。
- 当拥有认为主观下线的哨兵达到sentinel monitor所配置的数量时,就会发起一次投票,进行failover(故障转移)。
(3)一主二从三哨兵搭建
关键步骤:
基于搭建成功的一主二从Redis集群
配置3个哨兵,每个哨兵的配置都是一样的
启动顺序 先启动主再启动从,最后启动3个哨兵
①配置文件准备
打开redis的安装目录,可以找到文件sentinel.conf,这就是sentinel的配置文件。
复制该文件,新建一个文件后,对下列配置项进行修改
# 设置sentinel端口
port 26379
# 不限制ip
bind 0.0.0.0
# 配置日志文件位置(根据实际目录配置)
logfile "/usr/local/redis-6.2.9/logs/sentinel_26379.log"
# Redis数据库文件和持久化文件的存放目录(根据实际目录配置)
dir /usr/local/redis-6.2.9/logs
# 让sentinel服务后台运行
daemonize yes
# 配置监听的主服务器,mymaster代表服务器的名称,自定义,192.168.187.129 代表监控的主服务器,6379代表端口(根据实际配置)
#2代表只有两个或两个以上的哨兵认为主服务器不可用的时候,才会进行failover操作。
# 计算规则:哨兵个数/2 +1
sentinel monitor mymaster 192.168.187.129 6379 2
# sentinel auth-pass定义服务的密码,mymaster是服务名称,123456是Redis服务器密码(根据实际配置)
sentinel auth-pass mymaster 123456
#超过5秒master还没有连接上,则认为master已经停止
sentinel down-after-milliseconds mymaster 5000
#如果该时间内没完成failover操作,则认为本次failover失败
sentinel failover-timeout mymaster 30000
②哨兵集群搭建
根据上面的配置,可以依照基础redis的搭建方式搭建新的redis服务器启动sentinel,也可以在一主二从的服务器上启动sentinel。
此处为了简便,在从服务器上启动了三个sentinel服务。步骤如下:
1.依据上面的sentinel.conf配置文件,复制出同样的两份,一共三份配置文件,依次自定义命名文件,不要重复,此处我设置为sentinel-1.conf、sentinel-2.conf、sentinel-3.conf,修改配置文件中的端口,如果是同一台服务器上启动,保证端口不同,修改日志文件名称,保证日志文件名称不同。
2.进入到redis目录下,启动sentinel
cd /usr/local/redis-6.2.9
启动sentinel服务(注意:一定要加 --sentinel)
src/redis-server ../conf/sentinel/sentinel1.conf --sentinel
src/redis-server ../conf/sentinel/sentinel2.conf --sentinel
src/redis-server ../conf/sentinel/sentinel3.conf --sentinel
如图所示,此时已经启动了sentinel服务。

查看日志可以看到哨兵集群构建成功,并且都已成功监控redis主节点。

(4)哨兵模式测试
1.进入redis主节点中,关闭该主节点服务。

2.此时查看哨兵集群日志。
sentinel1(端口为26379)日志如下

sentinel2(端口为26380)日志如下

sentinel3(端口为26381)日志如下

名词解释
基于pub/sub的客户端事件通知
- 主库下线事件:
- +sdown:实例进入主观下线状态
- -sdown:实例退出主观下线状态
- +odown:实例进入客观下线状态
- -odown:实例退出客观下线状态
- 从库重新配置事件
- +slave-reconf-sent:哨兵发送SLAVEOF命令重新配置从库
- +slave-reconf-inpprog:从库配置了新主库,但尚未进行同步
- +slave-reconf-done:从库配置了新主库,且和新主库完成同步
- 新主库切换:- +swith-master:主库地址发送变化
此时查看192.168.187.130 新的redis主节点信息,被成功提升为主节点,且有一个在线从节点,至此,测试完成。

(5)集群节点哨兵模式工作原理

哨兵集群中的多个实例共同判断,可以降低对主库下线的误判率
哨兵集群组成: 基于 pub/sub 机制
- 哨兵间发现:
- 主库频道“__sentinel__:hello”,不同哨兵通过它相互发现,实现互相通信
- 哨兵发现从库
- 向主库发送 INFO 命令
基于 pub/sub 机制的客户端事件通知
- 事件:主库下线事件
- +sdown : 实例进入“主观下线”状态
- -sdown : 实例退出“主观下线”状态
- +odown : 实例进入“客观下线”状态
- -odown : 实例退出“客观下线”状态
- 事件:从库重新配置事件
- +slave-reconf-sent : 哨兵发送 SLAVEOF 命令重新配置从库
- +slave-reconf-inprog : 从库配置了新主库,但尚未进行同步
- +slave-reconf-done : 从库配置了新主库,且完成同步
- 事件:新主库切换
- +switch-master : 主库地址发生变化
由哪个哨兵执行主从切换?
- 一个哨兵获得了仲裁所需的赞成票数后,就可以标记主库为“客观下线”
- 所需的赞成票数 <= quorum 配置项
例如,现在有 5 个哨兵,quorum 配置的是 3,那么,一个哨兵需要 3 张赞成票,就可以标记主库为“客观下线”了。这 3 张赞成票包括哨兵自己的一张赞成票和另外两个哨兵的赞成票。
- Leader 选举
- 两个条件:
- 拿到半数以上的赞成票
- 拿到的票数>= quorum
- 如果未选出,则集群会等待一段时间(哨兵故障转移超时时间的 2 倍),再重新选举
经验:要保证所有哨兵实例的配置是一致的,尤其是主观下线的判断值 down-after-milliseconds
(6)总结
目前解决了什么问题:
- 主从集群间可以实现自动切换,可用性更高
- 数据更大限度的防止丢失
- 解决哨兵的集群高可用问题,减少误判率
目前还存在什么问题:
- 主节点的写能力和存储能力受限
5.高可扩-Redis Cluster分片集群
(1)问题概述
提出问题:要用 Redis 保存 5000 万个键值对,每个键值对大约是 512B,为了能快速部署并对外提供服务,我们采用云主机来运行 Redis 实例,那么,该如何选择云主机的内存容量呢?
思路分析:
- 所有的key占用内存预估是:5000 万 *512B = 25GB,所以redis的服务器申请 32G以上可以解决海量数据存储问题
- 为防止单点故障,必须还需要主从+哨兵实现故障自动转移和恢复数据
- 过程会发现一旦主节点宕机,会出现数据恢复时间会很长(秒级以上)
得出结论:如果只是单纯按照内存来申请redis服务器,这个方案是行不通的
那么如果想解决这个问题,就必须需要 Redis Cluster 分片集群,在Redis 3.0 之后开始支持。
(2)分片集群原理

Redis原理:
数据切片和实例的对应分布关系
Redis Cluster 方案:无中心化
- 采用哈希槽(Hash Slot)来处理数据和实例之间的映射关系
- 一个切片集群共有 16384 个哈希槽,只给Master分配
具体的映射过程
- 根据键值对的 key,按照CRC16 算法计算一个 16 bit 的值;
- 再用这个 16bit 值对 16384 取模,得到 0~16383 范围内的模数,每个模数代表一个相应编号的哈希槽
哈希槽映射到具体的 Redis 实例上
注意:需要把 16384 个槽都分配完,否则 Redis 集群无法正常工作
- 用 cluster create 命令创建集群,Redis 会自动把这些槽平均分布在集群实例上
- 也可以使用 cluster meet 命令手动建立实例间的连接,形成集群,再使用 cluster addslots 命令,指定每个实例上的哈希槽个数
客户端如何定位数据
- Redis 实例会把自己的哈希槽信息发给和它相连接的其它实例,来完成哈希槽分配信息的扩散
- 客户端和集群实例建立连接后,实例就会把哈希槽的分配信息发给客户端
- 客户端会把哈希槽信息缓存在本地。当请求键值对时,会先计算键所对应的哈希槽
- 但集群中,实例和哈希槽的对应关系并不是一成不变的
- 实例新增或删除
- 负载均衡
- 实例之间可以通过相互传递消息,获得最新的哈希槽分配信息,但客户端是无法主动感知这些变化
重定向机制
- 如果实例上没有该键值对映射的哈希槽,就会返回 MOVED 命令
- 客户端会更新本地缓存
- 在迁移部分完成情况下,返回ASK
- 表明 Slot 数据还在迁移中
- ASK 命令把客户端所请求数据的最新实例地址返回给客户端
- 并不会更新客户端缓存的哈希槽分配信息
(3)Redis Cluster分片集群搭建
参考配置
bind 0.0.0.0
protected-mode no
port 7001
daemonize yes
requirepass "123456"
logfile "/usr/local/redis/logs/redis_7001.log"
dbfilename "redis_7001.rdb"
dir "/usr/local/redis/data"
appendonly yes
appendfilename "appendonly_7001.aof"
masterauth "123456"
#是否开启集群
cluster-enabled yes
# 生成的node文件,记录集群节点信息,默认为nodes.conf,防止冲突,改为nodes-7001.conf
cluster-config-file nodes-7001.conf
#节点连接超时时间
cluster-node-timeout 20000
#集群节点的ip,当前节点的ip, 如果是阿里云是可以写内网ip
cluster-announce-ip 192.168.200.151
#集群节点映射端口
cluster-announce-port 7001
#集群节点总线端口,节点之间互相通信,常规端口+1万
cluster-announce-bus-port 17001
如果是使用一个服务器,则需注意端口不能冲突,如果是使用多个服务器部署,注意需开通防火墙端口。
①具体步骤
1.创建redis.conf 配置文件,参考上面配置。
2.启动6个Redis实例
3.加入Redis集群(任意一个Redis实例即可),命令:
redis-cli -a 123456 --cluster create 192.168.187.129:7000 192.168.187.129:7001 192.168.187.130:7000 192.168.187.130:7001 192.168.187.131:7000 192.168.187.131:7001 --cluster-replicas 1
- –cluster 构建集群全部节点信息
- –cluster-replicas 1 主从节点的比例,1表示1主1从的方式

集群创建成功,可以看到16384个哈希槽被分配给了3个主节点。
查看集群状态信息
redis-cli -a 123456 --cluster check 192.168.187.129:7001
可以看到3个主节点的哈希槽数量,key数量和从节点数量
连接集群,查看集群信息,注意必须在参数后添加 -c 标识集群连接
redis-cli -a 123456 -p 7001 -c
连接后使用cluster info命令查看

- 测试集群读写命令set/get
- key哈希运算计算槽位置
- 槽在当前节点的话直接插入/读取,否则自动转向到对应的节点
- 操作都是主节点操作,从节点只是备份
(4)集群动态扩缩容
1.参照上文,新启动两个redis实例

扩容-添加主节点
redis-cli -a 123456 --cluster add-node 192.168.187.129:7002 192.168.187.129:7001。### 将192.168.187.129:7002 节点添加到 192.168.187.129:7001 所在的集群中

通过命令可以查看到该主节点被分配到的哈希槽为0。
重新分配哈希槽:
此处命令给192.168.187.129:7001重新分配哈希槽,--cluster-from 是指从哪些节点,此处填入主节点ID,-cluster-to 是指分配到哪个节点,此处填入需要分配哈希槽节点的id,--cluster-slots 是指需要分配的哈希槽数量,此处写了120,这120会尽可能平均的从其他主节点中被分配给新节点。
redis-cli -a 123456 --cluster reshard 192.168.187.129:7001 --cluster-from 0cfa9a6d5a0aa9cdc06573e692e6dcbc694c097d,0f54be31d6612450cea7f0ead5a9ceb74684e847,fe62f37c7ca89577c37e5be8cb4964f26643b8ed --cluster-to baf324c679b8eef1b30a56a555477a3ecdb3e2d3 --cluster-slots 120

分配之后再通过redis-cli -a 123456 --cluster check 192.168.187.129:7001命令进行查看

可以看到,新的主节点的哈希槽是由原来的主节点哈希槽分配得到的。
扩容-添加从节点
redis-cli -a 123456 --cluster add-node 192.168.200.151:7008 192.168.200.151:7007 --cluster-slave --cluster-master-id a2a40b5b5dc2eeea246ff7a98560230b1d886106
命令说明:
- 将192.168.200.151:7008节点添加到192.168.200.151:7007对应的集群中,并且加入的节点为从节点
- 对应的主节点 id是c64c1ffab2d8400d54415c7bfd397f85184a2eb6
参数说明:
add-node: 后面的分别跟着新加入的slave和slave对应的master
cluster-slave:表示加入的是slave节点
–cluster-master-id:表示slave对应的master的node ID
缩容-删除从节点
bin/redis-cli -a 123456 --cluster del-node 192.168.200.151:7008 9f28a607e2540a8b518eef5dc37117624f69999b
参数说明:
- del-node:删除节点,后面跟着slave节点的 ip:port 和node ID
缩容-删除主节点
主节点缩容,首先需要将哈希槽分配给其他主节点
bin/redis-cli -a 123456 --cluster reshard 192.168.200.151:7007 --cluster-from a2a40b5b5dc2eeea246ff7a98560230b1d886106 --cluster-to 6a3e3aa58608ce00ef42d5b279587a3d3df21bde --cluster-slots 39 --cluster-yes
将192.168.211.141:7007节点所在集群中c64c1ffab2d8400d54415c7bfd397f85184a2eb6节点的33个哈希槽迁移给 596cb9e8da99ea12f4405649f37ea11a27379129 节点,不回显需要迁移的slot,直接迁移。
同样再次迁移其他哈希槽到其他节点,将剩余的哈希槽迁移到对应的其他主节点。
删除节点命令如下:
bin/redis-cli -a 123456 --cluster del-node 192.168.200.151:7007 c64c1ffab2d8400d54415c7bfd397f85184a2eb6
(5)总结
分片解决了什么问题:
- 海量数据存储
- 高可用
- 高可扩
高可用架构总结
- 主从模式:读写分离,负载均衡,一个Master可以有多个Slaves
- 哨兵sentinel:监控,自动转移,哨兵发现主服务器挂了后,就会从slave中重新选举一个主服务器
- 分片集群: 为了解决单机Redis容量有限的问题,将数据按一定的规则分配到多台机器,内存/QPS不受限于单机,提高并发量。
2671

被折叠的 条评论
为什么被折叠?



