redis高可用-持久化-主从复制-哨兵-cluster集群概述与部署,内容依旧多看完直接通透!

一,Redis 高可用

  • 在web服务器中,高可用是至服务器可以正常访问的时间,衡量的标准是在时间内提供正常的服务(99.9%、99.99%、99.999%等等)
  • 但是在 Redis 语境中,高可用除了保证提供正常服务(如主从分离,快速容灾技术),还需要考录数据容量的扩展,数据安全不会丢失等
  • 在Redis 中,实现高可用的技术主要包括持久化,主从复制,哨兵和集群

1.持久化

主要作用是数据备份,即把数据保存在一个位置或者磁盘中,保证数据不会因为进程退出而丢失

2.主从复制

  • 主要复制是高可用 Redis 的基础,主从复制主要实现了数据的多机备份,以及对于读操作的负载均衡和简单的故障恢复

  • 缺陷:故障恢复无法自动化,写操作无法负载均衡,单机的原因限制了存储能了

3.哨兵

  • 需要在主从复制的基础上实现自动化的故障恢复
  • 缺陷:写操作无法实现负载均衡,单机原因限制了存储能力

4.集群(cluster)

  • 通过集群,Redis 解决了写操作无法负载均衡,以及存储能力受到单机限制的问题
  • 实现了较为完善的高可用方案

二,Redis 持久化方式

1.持久化的功能

  • Redis 是内存数据库,数据都是存储在内存中,为了避免服务器断电等原因导致 Redis 进程异常退出后数据的永久丢失,需要定期将 Redis 中的数据以某种形式 (数据或命令) 从内存保存到硬盘
  • 当下次 Redis 重启时,利用持久化文件实现数据恢复。除此之外,为了进行灾难备份,可以将持久化文件拷贝到一个远程位置(NFS)

2.持久化的方式

  • RDB 持久化

原理是将 Redis 在内存中的数据库记录定时保存到磁盘上(类似于快照(完备))

  • AOF持久化(append only file)

目前主流的持久化方式

原理是将 Redis 的操作日志以追加的方式写入文件,类似于 MySQL 的 binlog(基于日志持久化方式(类似于增备))

三, RDB 持久化

  • 又称快照持久化,指在指定的时间间隔内将内存中当前进程中的数据生成快照保存到硬盘,用二进制压缩存储,保存的文件后缀是rdb

  • 当 Redis 重新启动时,可以读取快照文件恢复数据

1.触发条件

  • 手动触发(生成RDB文件:save命令、bgsave命令)

save命令和bgsave命令都可以生成RDB文件

① save命令会阻塞 Redis 服务器进程,直到 RDB 文件创建完毕为止,在 Redis 服务器阻塞期间,服务器不能处理任何命令请求

② bgsave 命令——>派生子进程——>子进程来创建 RDB 文件并阻塞服务器——>父进程(主进程)则继续处理请求

bgsave命令执行过程中,只有fork子进程时会阻塞服务器,而对于save命令,整个过程都会阻塞服务器,因此save已基本被废弃,线上环境要杜绝save的使用

  • 自动触发

在自动触发RDB持久化时,Redis也选择bgsave而不是save来进行持久化

根据触发器—— 阈值来完成自动行的持久化

① 在自动触发 RDB 持久化时,Redis 会选择 bgsave 来进行持久化
② save m n →自动触发通常是在配置文件中此命令触发 bgsave
m:多少 s 内; n:发生多少次

vim /etc/redis/6379.conf
#下面三个 save 条件满足任意一个,都会引起 bgsave 的调用

219 save 900 1 	 					#当时间到900秒时,如果redis数据发生了至少1次变化,则执行bgsave
220 save 300 10  					#当时间到300秒时, 如果redis数据发生了至少10次变化, 则执行bgsave
221 save 60 10000  					#当时间到60秒时,如果redis数据发生了至少10000次变化, 则执行bgsave

242 rdbcompression yes		 		#是否开启RDB文件压缩
254 dbfilename dump.rdb		 		#指定RDB文件名
264 dir /var/lib/redis/6379			#指定RDB文件和AOF文件所在目录
  • 其他自动触发机制

除了 savemn 以外,还有一些其他情况会触发bgsave

在主从复制场景下,如果从节点执行全量复制操作,则主节点会执行bgsave命令,并将rdb文件发送给从节点

执行shutdown命令时,自动执行rdb持久化

2. 执行流程

  • 1.Redis 父进程首先判断:当前是否在执行 save,或 bgsave/bgrewriteaof 的子进程,如果在执行则 bgsave 命令直接返回 bgsave/bgrewriteaof
  • 2.父进程执行 fork 操作创建子进程,这个过程中父进程是阻塞的,Redis 不能执行来自客户端的任何命令
  • 3.父进程 fork后,bgsave 命令返回 ”Background saving started" 信息并不再阻塞父进程,并可以响应其他命令
  • 4.子进程创建 RDB文件,根据父进程内存快照生成临时快照文件,完成后对原有文件进行原子替换
  • 5.子进程发送信号给父进程表示完成,父进程更新统计信息

image-20220820161613765

3. 启动时加载

  • RDB 文件的载入工作是在服务器启动时自动执行的,并没有专门的命令
  • 优先级:AOF大于RDB,因此当 AOF 开启时,默认先载入 AOF 文件,仅当 AOF 关闭,才会载入 RDB 文件
  • Redis 载入 RDB 文件时(即启动过程中),会对RDB 文件进行校验,如果文件损坏,则日志中会打印错误,Redis启动失败

4.RDB 的优,缺点

  • Redis 的数据是存在内存中的,Redis持久化就是把内存中的数据写到磁盘中去,防止服务宕机了内存数据丢失

  • Redis 提供两种持久化机制 RDB(默认) 和 AOF 机制:当两种方式同时开启时,数据恢复Redis会优先选择AOF恢复

  • 是Redis DataBase缩写快照

  • RDB是Redis默认的持久化方式。按照一定的时间将内存的数据以快照的形式保存到硬盘中,对应产生的数据文件为dump.rdb。通过配置文件中的save参数来定义快照的周期

1.优点
  • 只有一个文件 dump.rdb,方便持久化
  • 文件紧凑,体积小,网络传输快
  • 容灾性好,一个文件可以保存到安全的磁盘
  • 相对于数据集大时,比 AOF 的启动效率更高
  • 性能最大化,fork 子进程来完成写操作,让主进程继续处理命令,所以是 IO 最大化。使用单独子进程来进行持久化,主进程不- 会进行任何 IO 操作,保证了 redis 的高性能
  • 持久化的速度快(因为保存的是数据结果),在写入到*.rdb持久化文件,会进
    行压缩,来减小自身的体积
  • 集群中,redis的主从复制,从–》主服务器进行同步,默认先视同RDB文件进行
    恢复操作,所以同步性能较高
2.缺点
  • 数据完成性不如AOF

  • RDB类似于快照(完备),速度慢

  • 在进行备份时,会阻塞进程

  • 做不到实时持久化

  • 兼容性差(如老版本的Redis不兼容新版本的RDB文件)

  • 数据安全性低。RDB 是 间隔一段时间进行持久化,如果持久化之间 redis 发生故障,会发生数据丢失。所以这种方式更适合数据要求不严谨的时候

四、AOF 持久化

RDB持久化是将进程数据写入文件,而AOF持久化,则是将Redis执行的每次写、删除命令记录到单独的日志文件中,查询操作不会记录

当Redis重启时再次执行AOF文件中的命令来恢复数据

1.开启 AOF

  • Redis服务器默认开启RDB,关闭AOF的, 要开启AOF,需要在/etc/ redis/6379.conf配置文件中配置
vim /etc/redis/6379.conf
700 appendonly yes								#修改成yes,开启AOF
704 appendfilename "appendonly.aof"		    	#指定A0F文件名称
796 aof-load-truncated yes		           	 	#是否忽略最后一条可能存在问题的指令

/etc/ init.d/redis_ 6379 restart		   	 	#重启redis

2. 执行流程

由于需要记录 Redis 的每条写命令,因此 A0F 不需要触发,AOF 的执行流程如下

① 命令追加(append)
将Redis的写命令追加到缓冲区aof_buf; (为了尽量不因为持久化而影响redis性能)

② 文件写入(write)文件同步(sync)
根据不同的同步策略将 aof_buf 中的内容同步到硬盘,所以 Redis 系统同时提供了 fsync、fdatasync 等同步函数,可以强制操作系统立刻将缓冲区中的数据写入到硬盘里,从而确保数据的安全性

③文件从写(rewrite)

定期重写AOF文件,达到压缩的目的

2.1详细叙述,命令追加,文件写入 文件同步,文件重写
2.1.1命令追加(append):
  • Redis先将写命令追加到缓冲区,而不是直接写入文件,主要是为了避免每次有写命令都直接写入硬盘,导致硬盘IO成为Redis负载的瓶颈
  • 命令追加的格式是Redis命令请求的协议格式,它是一种纯文本格式,具有兼容性好、可读性强、容易处理、操作简单避免二次开销等优点。在A0F文件中,除了用于指定数据库的select命令 (如select0为选中0号数据库) 是由Redis添加的,其他都是客户端发送来的写命令
2.1.2文件写入(write)文件同步(sync):
  • Redis 提供了多种AOF缓存区的同步文件策略,策略涉及到操作系统的write函数和fsync函数,说明如下:
  • 为了提高文件写入效率,在现代操作系统中,当用户调用write函数将数据写入文件时,操作系统通常会将数据暂存到一个内存缓冲区里,当缓冲区被填满或超过了指定时限后,才真正将缓冲区的数据写入到硬盘里。这样的操作虽然提高了效率,但也带来了安全问题:如果计算机停机,内存缓冲区中的数据会丢失;因此系统同时提供了fsync、fdatasync等同步函数,可以强制操作系统立刻将缓冲区中的数据写入到硬盘里,从而确保数据的安全性
AOF缓存区的同步文件策略存在三种同步触发 方式,它们分别是:
vim /etc/redis/6379.conf
appendfsync always:    #一直触发AOF
#命令写入aof_ buf后立即调用系统fsync操作同步到AOF文件,fsync完成后线程返回。这种情况下,每次有写命令都要同步到AOF文件,硬盘IO成为性能瓶颈,Redis只能支持大约几百TPS写入,严重降低了Redis的性能;即便是使用固态硬盘(SSD),每秒大约也只能处理几万个命令,而且会大大降低SSD的寿命

appendfsync no:    #不触发AOF
#命令写入aof_ buf后调用系统write操作,不对AOF文件做fsync同步;同步由操作系统负责,通常同步周期为30秒。这种情况下,文件同步的时间不可控,且缓冲区中堆积的数据会很多,数据安全性无法保证

appendfsync everysec:   #按秒触发AOF
#命令写入aof_ buf后调用系统write操作,write完成后线程返回; fsync同步文件操作由专门的线程每秒调用一次。everysec是前述两种策略的折中,是性能和数据安全性的平衡,因此是Redis的默认配置,也是我们推荐的配置。
2.1.3文件重写 (rewrite)
  • 随着时间流逝,Redis服务器执行的写命令越来越多,AOF文件也会越来越大:过大的AOF文件不仅会影响服务器的正常运行,也会导致数据恢复需要的时间过长
  • 文件重写是指定期重写AOF文件,减小AOF文件的体积。需要注意的是,AOF重写是把Redis进程内的数据转化为写命令,同步到新的AOF文件;不会对旧的AOF文件进行任何读取、写入操作
  • 关于文件重写需要注意的另一点是:对于AOF持久化来说,文件重写虽然是强烈推荐的,但并不是必须的;即使没有文件重写,数据也可以被持久化并在Redis启动的时候导入:因此在一些实现中,会关闭自动的文件重写,然后通过定时任务在每天的某一时刻定时执行
文件重写能压缩AOF文件的原因
  • 过期的数据不再写入文件
  • 无效的命令不再写入文件:如有些数据被重复设值(set mykey test1, set mykey test2)、有些数据被删除了(sadd myset vtest, del myset) 等
  • 多条命令可以合并为一个:如sadd myset test1, sadd myset test2, sadd myset test3可以合并为sadd myset test1 test2 test3

通过上述内容可以看出,由于重写后AOF执行的命令减少了,文件重写既可以减少文件占用的空间,也可以加快恢复速度。过期的数据不再写入文件

3. 文件重写的触发分类

文件重写的触发,分为手动触发和自动触发

  • ① 手动触发
    直接调用 bgrewriteaof 命令
    通过 fork 子进程进行具体的工作,且只有在 fork 时阻塞

  • ② 自动触发
    通过设置 auto-aof-rewrite-min-size 选项和 auto-aof-rewrite-percentage 选项来自动执行 BGREWRITEA0F,且两个选项同时满足时,才会自动触发 AOF 重写,即 bgrewriteaof 操作

vim /etc/ redis/ 6379. conf

#AOF同步的策略
729 # appendfsync always
730 appendfsync everysec
731 # appendfsync no
771	auto-aof-rewrite-percentage 100		 #当前AOF文件大小(即aof_current_size)是上次日志重写时AOF文件大小(aof_base_size)两倍时,发生BGREWRITEAOF操作
772 auto-aof-rewrite -min-size 64mb		 #当前A0F文件执行BGREWRITEAOF命令的最小值,避免刚开始启动Reids时由于文件尺寸较小导致频繁的BGREWRITEA0F
3.1文件重写的流程
  • **1.**Redis父进程首先判断当前是否存在正在执行bgsave/bgrewriteaof的子进程,如果存在则bgrewriteaof命令直接返回,如果存在bgsave命令则等bgsave执行完成后再执行
  • **2.**父进程执行fork操作创建子进程,这个过程中父进程是阻塞的
  • **3.**父进程fork后,bgrewriteaof 命令返回"Background append only file rewrite started" 信息并不再阻塞父进程,并可以响应其他命令。Redis的所有写命令依然写入AOF缓冲区,并根据appendfsync策略同步到硬盘,保证原有A0F机制的正确
  • **4.**由于fork操作使用写时复制技术,子进程只能共享fork操作时的内存数据。由于父进程依然在响应命令,因此Redis使用AOF重写缓冲区(aof_ rewrite_buf) 保存这部分数据,防止新AOF文件生成期间丢失这部分数据。也就是说,bgrewriteaof执行 期间,Redis的写 命令同时追加到aof_ buf和aof_ rewirte_ buf两个缓冲区
  • **5.**子进程根据内存快照,按照命令合并规则写入到新的AOF文件
  • **6.**子进程写完新的AOF文件后,向父进程发信号,父进程更新统计信息,具体可以通过info persistence查看
  • **7.**父进程把AOF重写缓冲区的数据写入到新的AOF文件,这样就保证了新AOF文件所保存的数据库状态和服务器当前状态一致
  • **8.**使用新的AOF文件替换老文件,完成AOF重写

重写流程注意点

  • 重写由父进程fork子进程进行
  • 重写期间Redis执行的写命令,需要追加到新的AOF文件中,为此Redis引入了aof_ rewrite_buf缓存

image-20220820172309087

3.2启动时加载
  • 当 AOF 开启时,Redis 启动时会优先载入 AOF 文件来恢复数据;只有当 AOF 关闭时,才会载入 RDB 文件恢复数据
  • 当 AOF 开启,但 AOF 文件不存在时,即使 RDB 文件存在也不会加载
  • Redis 载入 AOF 文件时,会对 AOF 文件进行校验,如果文件损坏,则日志中会打印错误,Redis 启动失败。但如果是 AOF 文件结尾不完整 (机器突然宕机等容易导致文件尾部不完整),且 aof-load-truncated 参数开启,则日志中会输出警告,Redis 忽略掉 AOF 文件的尾部,启动成功
  • aof-load-t runcated 参数默认是开启的

4.AOF 的优,缺点

  • Append Only File持久化,则是将Redis执行的 每次写命令记录到单独的日志文件中,当重启Redis会重新将持久化的日志中文件恢复数据
1.优点
  • aof的数据完整性比RDB更高

  • 重写功能,会对无效进行删除,目的是为了节省AOF文件占用磁盘空间

  • 数据安全,aof 持久化可以配置 appendfsync 属性,有 always,每进行一次 命令操作就记录到 aof 文件中一次

  • 通过 append 模式写文件,即使中途服务器宕机,可以通过 redis-check-aof 工具解决数据一致性问题

  • AOF 机制的 rewrite 模式。AOF 文件没被 rewrite 之前(文件过大时会对命令 进行合并重写),可以删除其中的某些命令(比如误操作的 flushall)

2.缺点
  • AOF 文件比 RDB 文件大,且恢复速度慢

  • RDB备份的内容较小
    RDB备份的是结果
    RDB备份的是语句

  • 数据集大的时候,比 rdb 启动效率低

  • AOF消耗的性能更大,占用磁盘越来越大(可以理解为mysql增量备份)

以上总结

1、RDB和AOE的基本理解
①RDB:周期性的把内存中的数据保存在磁盘中
②AOF:从redis的操作口志记录中执行的过程同步到磁盘中

2、RDB和AOF持久化过程
RDB:内存中—》写入磁盘中保存方式
②结果数据—》写入磁盘中保存的数据对象
③内存–》写入磁盘后,会进行压缩,来减小*.rdb的磁盘占用空间量

AOF: ①内存—》append追加到缓冲l区—》调用cPU资源来写入到磁盘中
②操作口志记录中的执行语句—》追加到缓冲—》调用CPU来写入磁盘
③内存—》缓冲—》磁盘,写入后,会周期性的进行重写,跳过一些"无效操作”米保存

3、RDB和AOF触发方式
RDB分为:①手动触发
②自动触发save m n(假设save 60 900 ,则表示60s内有900条语句执行,则触发RDB持久化)
③特殊触发:当手动关闭redis时,会进行RDB方式持久化

AOF分为:①手动触发
②自动触发
1)always每条语句同步执行持久化
2)no不进行持久化
3)every second每秒进行一次AoF持久化(建议使用的,均衡型场景)

4、RDB和AOF优先级
前提:①因为redis默认是将数据保存在内存中的,所以若redis重启,关闭时内存中的数据会丢失
②在redis每次启动时,都会读取持久化的文件来恢复数据到内存中,以保证redis数据的完整性

  • RDB和AOF优先级,AOF大于RDB

五、Redis 性能管理

1. 查看 Redis 内存使用

[root@localhost ~]# redis-cli -h 192.168.113.127 -p 6379
192.168.113.127:6379> info memory
# Memory
used_memory:853336
used_memory_human:833.34K
used_memory_rss:12836864
used_memory_rss_human:12.24M
used_memory_peak:853336
used_memory_peak_human:833.34K
used_memory_peak_perc:100.01%
used_memory_overhead:841110
used_memory_startup:791416
used_memory_dataset:12226
used_memory_dataset_perc:19.74%
......

2. 内存碎片率

  • 操作系统分配的内存值 used_memory_rss 除以 Redis 使用的内存值 used_memory 计算得出内存碎片是由操作系统低效的分配/回收物理内存导致的(不连续的物理内存分配)
  • 跟踪内存碎片率对理解 Redis 实例的资源性能是非常重要的

① 内存碎片率稍大于1是合理的,这个值表示内存碎片率比较低

② 内存碎片率超过1.5,说明Redis消耗了实际需要物理内存的150号,其中50号是内存碎片率。需要在redis-cli工具上输入shutdownsave命令,并重启Redis服务器

③ 内存碎片率低于1的,说明Redis内存分配超出了物理内存,操作系统正在进行内存交换。需要增加可用物理内存或减少Redis内存占用

3. 内存使用率

  • redis实例的内存使用率超过可用最大内存,操作系统将开始进行内存与swap空间交换

  • 避免内存交换发生的方法如下:

① 针对缓存数据大小选择安装Redis实例(云平台里面使用RDS服务,ECS云主机选择内存、缓存型配置) 尽可能的使用Hash数据结构存储

② 设置key的过期时间

4. 内回收 key

  • 保证合理分配 redis 有限的内存资源
  • 当达到设置的最大阀值时,需选择一种 key 的回收策略,默认情况下回收策略是禁止删除
  • 配置文件中修改 maxmemory- policy 属性值
vim /etc/redis/6379.conf

598 maxmemory-policy noenviction
volatile-lru	 								#使用LRU算法从已设置过期时间的数据集合中淘汰数据
volatile-ttl	  								#从已设置过期时间的数据集合中挑选即将过期的数据淘汰
volatile-random	 								#从已设置过期时间的数据集合中随机挑选数据淘汰
allkeys-lru 	 								#使用LRU算法从所有数据集合中淘汰数据
allkeys-random  								#从数据集合中任意选择数据淘汰

六.主从复制

1.主从复制原理

  • 主从复制,是指将一台 Redis 服务器的数据,复制到其他的 Redis 服务器。前者称为主节点(Master),后者称为从节点(Slave);数据的复制是单向的,只能由主节点到从节点
  • 默认情况下,每台 Redis 服务器都是主节点;且一个主节点可以有多个从节点 (或没有从节点),但一个从节点只能有一个主节点

详细版:

  • 通过持久化功能,redis保证了即使在服务器重启的情况下也不会丢失(或少量丢失)数据,因为持久化会把内存中的数据保存到硬盘上,重启会从硬盘上加载数据,但是由于数据是存储在一台服务器上的,如果这台服务器出现硬盘故障等问题,也会导致数据丢失
  • 为了避免单点故障,通常的做法是将数据库复制多个副本以部署在不同的服务器上,这样即使有一台服务器出现故障,其他服务器依然可以继续提供服务,为此,redis提供了复制(replication)功能,可以实现当一台数据库中的数据更新后,自动将更新的数据同步到其他数据库上
  • 在复制的概念中,数据库分为两类,一类是主数据库(master),另一类是从数据(slave)。主数据可以进行读写操作,当写操做导致数据变化时自动将数据同步给数据库,而从数据库一般是只读的,并接收主数据同步过来的数据。一个主数据库可以拥有多个从数据库,而一个从数据库只能拥有一个主数据库

2.主从复制作用

  • 1.数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式

  • 2.故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复;实际上是一种服务的冗余

  • 3.负载均衡:在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务 (即写 Redis 数据时应用连接主节点,读 Redis 数据时应用连接从节点),分担服务器负载;尤其是在写少读多的场景下,通过多个从节点分担读负载,可以大大提高Redis服务器的并发量

  • 4.高可用基石:除了上述作用以外,主从复制还是哨兵和集群能够实施的基础,因此说主从复制是Redis高可用的基础

3.主从复制流程

  • 1.若启动一个Slave机器进程,则它会向Master机器发送一个“sync command" 命令,请求同步连接
  • 2.无论是第一次连接还是重新连接,Master机器 都会启动一个后台进程,将数据快照保存到数据文件中(执行rdb操作) ,同时 Master 还会记录修改数据的所有命令并缓存在数据文件中
  • 3.后台进程完成缓存操作之后,Master 机器就会向 Slave 机器发送数据文件,Slave 端机器将数据文件保存到硬盘上,然后将其加载到内存中,接着 Master 机器就会将修改数据的所有操作一并发送给 Slave 端机器。若 Slave 出现故障导致宕机,则恢复正常后会自动重新连接
  • 4.Master机器收到 Slave 端机器的连接后,将其完整的数据文件发送给 Slave 端机器,如果 Mater 同时收到多个 Slave 发来的同步请求,则 Master 会在后台启动一个进程以保存数据文件,然后将其发送给所有的 Slave 端机器,确保所有的 Slave 端机器都正

简单版:

1.从向主发送sync同步请求

2.主redis 会fork一个子进程,然后产生RDB 文件(完备)的过程,此时客户端还在持续的写入数据

3.RDB文件持久化完成之后,主redis会将RDB 文件和缓存起立的命令推送给服务器

4.复制,推送完之后,主redis会持续的同步操作命令利用 AOF(增备)持久化功能

5.在下一台从redis接入主从复制集群之前,会持续利用 AOF的方式同步数据给从redis

image-20220822152136003

4.搭建Redis主从复制

  • 环境
1.安装Redis服务

三台服务器同样配置

节点名   IP地址
master	192.168.113.128
slave1	192.168.113.129
slave2  192.168.113.130
###################老实人版本###################
#关闭防火墙与增强机制
systemctl stop firewalld
setenforce0
#安装依赖包
yum install -y gcc gcc-c++ make  
#安装Redis
cd /opt
tar xf redis-5.0.7.tar.gz
cd redis-5.0.7/
make   #编译
make PREFIX=/usr/local/redis install   #指定安装路径
cd utils/
[root@localhost utils]# ./install_server.sh 
.......          #一直回车.
Please select the redis executable path [/usr/local/bin/redis-server] /usr/local/redis/bin/redis-server
#需要手动修改为 /usr/local/redis/bin/redis-server    注意要一次性正确输入

#创建软连接
ln -s /usr/local/redis/bin/* /usr/local/bin/
ln -s /etc/init.d/redis_6379 /usr/local/bin/redis  #将启动服务软连接到全局,可以直接使用redis命令启动程序

image-20220818200804102

  • 脚本一键部署执行如下:
##要拖入安装包
#!/bin/bash

systemctl stop firewalld
systemctl disable firewalld
setenforce 0

yum -y install gcc gcc-c++ make

cd /opt
if [ ! -f " redis-5.0.7.tar.gz" ]; then
wget http://download.redis.io/releases/redis-5.0.7.tar.gz
fi

tar zxvf redis-5.0.7.tar.gz -C /opt/
cd redis-5.0.7/
make
make PREFIX=/usr/local/redis install

yum -y install tcl expect
cd /opt/redis-5.0.7/utils/
/usr/bin/expect <<EOF
spawn ./install_server.sh
expect "instance" {send "\r"} 
expect "config" {send "\r"}
expect "log" {send "\r"}
expect "data" {send "\r"}
expect "executable" {send "/usr/local/redis/bin/redis-server\r"}
expect "abort" {send "\r"}
expect eof
EOF

ln -s /usr/local/redis/bin/* /usr/local/bin/

sed -i '/bind 127.0.0.1/c bind 0.0.0.0' /etc/redis/6379.conf
sed -i 's/appendonly no/appendonly yes/' /etc/redis/6379.conf

/etc/init.d/redis_6379 restart
/etc/init.d/redis_6379 status

netstat -natp | grep "redis"

pgrep "redis" &> /dev/null
if [ $? -eq 0 ];then
        echo -e "\033[46;37m Redis 服务运行正常 \033[0m"
else
        echo -e "\033[46;37m Redis 服务运行异常,请检查 \033[0m"
fi
sleep 2
echo ' '
echo -e "\033[46;37m Redis 未设置密码,执行 redis-cli 命令登录 \033[0m"
2.修改Redis配置文件
  • master节点
[root@master redis]# vim /etc/redis/6379.conf 

bind 0.0.0.0                        
#70行,修改监听地址为 0.0.0.0

daemonize yes                       
#137行,开启守护进程

logfile /var/1og/redis_6379.1og    
#172行,指定日志文件目录

dir /var/lib/redis/6379             
#264行,指定工作目录

appendonly yes                      
#700行,开启 AOF 持久化功能

[root@master redis]# /etc/init.d/redis_6379 restart
#重启服务使配置生效
  • Slave1 Slave2节点
[root@slavr1 opt]# vim /etc/redis/6379.conf 

bind 0.0.0.0                        
#70行,修改监听地址为 0.0.0.0

daemonize yes                       
#137行,开启守护进程

logfile /var/log/redis_6379.log   
#172行,指定日志文件目录

dir /var/lib/redis/6379             
#264行,指定工作目录

replicaof 192.168.113.128 6379       
#288行添加,指定要同步的 Master 节点 IP 和端口

appendonly yes                      
#700行,开启 AOF 持久化功能

[root@slavr1 opt]# /etc/init.d/redis_6379 restart
#重启服务使配置生效

3.验证主从效果

  • 主节点查看日志
[root@master redis]# tail -f /var/log/redis_6379.log 

image-20220822163501347

  • 在主节点验证
[root@master redis]# redis-cli info replication
# Replication
role:master
connected_slaves:2
slave0:ip=192.168.113.129,port=6379,state=online,offset=280,lag=0
slave1:ip=192.168.113.130,port=6379,state=online,offset=280,lag=0
master_replid:551a8dd4260f41e52dd561a7d1290029d4908216 #master启动时生成的40位16进制的随机字符串,用来标master节点
master_replid2:0000000000000000000000000000000000000000  ##切换主从的时候master节点标识会有更改
master_repl_offset:280
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:280
  • 在master上创建数据
[root@master redis]# redis-cli
127.0.0.1:6379> set q jm
127.0.0.1:6379> get q
"jm"

image-20220822164048966

  • 在两个从服务器查看信息,成功主从复制

image-20220822164208771

image-20220822164149027

七,哨兵模式

概述:

主从切换技术的方法是:当服务器宕机后,需要手动一台从机切换为主机,这需要人工干预,不仅费时费力而且还会造成一段时间内服务不可用。为了解决主从复制的缺点,就有了哨兵机制

哨兵的核心功能:在主从复制的基础上,哨兵引入了主节点的自动故障转移

1.哨兵模式的原理

哨兵(sentinel):是一个分布式系统,用于对主从结构中的每台服务器进行监控,当出现故障时通过投票机制选择新的Master并将所有slave连接到新的Master

所以整个运行哨兵的集群的数量不得少于3个节点

2.哨兵模式的作用

监控:哨兵会不断地检查主节点和从节点是否运作正常

  • 自动故障转移:当主节点不能正常工作时,哨兵会开始自动故障转移操作,它会将失效主节点的其中一个从节点升级为新的主节点,并让其它从节点改为复制新的主节点
  • 通知(提醒):哨兵可以将故障转移的结果发送给客户端

哨兵结构由两部分组成,哨兵节点和数据节点

  • 哨兵节点:哨兵系统由一个或多个哨兵节点组成,哨兵节点是特殊的redis节点,不存储数据
  • 数据节点:主节点和从节点都是数据节点

3.哨兵模式主要功能

① 集群监控:负责监控Redismaster和slave进程是否正常工作

② 消息通知:如果某个Redis实例有故障,那么哨兵负责发送消息作为报敬通知给管理员

③ 故障转移:如果masternode挂掉了,会自动转移到slave node上

④ 配置中心:如果故障转移发生了,通知client客户端新的master地址

使用一个或者多个哨兵(Sentinel)实例组成的系统,对redis节点进行监控 在主节点出现故障的情况下, 能将从节点中的一个升级为主节点,进行故障转义,保证系统的可用性

4.哨兵的故障转移机制

  • 由哨兵节点定期监控发现主节点是否出现了故障
    每个哨兵节点每隔1秒会向主节点、从节点及其它哨兵节点发送一次ping命令做—次心跳检测。如果主节点在一定时间范围内不回复或者是回复一个错误消息,那么这个哨兵就会认为这个主节点主观下线了(单方面的)。当超过半数哨兵节点认为该主节点主观下线了,这样就客观下线了

  • 当主节点出现故障,此时哨兵节点会通过Raft算法(选举算法)实现选举机制共同选举出一个哨兵节点为leader,来负责处理主节点的故障转移和通知。所以整个运行哨兵的集群的数量不得少于3个节点

  • 由leader哨兵节点执行故障转移,过程如下:

1.将某一个从节点升级为新的主节点,让其它从节点指向新的主节点:

2.若原主节点恢复也变成从节点,并指向新的主节点:

3.通知客户端主节点已经更换

需要特别注意的是,客观下线是主节点才有的概念;如果从节点和哨兵节点发生故障,被哨兵主观下线后,不会再有后续的客观下线和故障转移操作

image-20220822184246050

主观下线详细版

哨兵(Sentinel)节点会每秒一次的频率向建立了命令连接的实例发送PING命令,如果在down-after-milliseconds毫秒内没有做出有效响应包括(PONG/LOADING/MASTERDOWN)以外的响应,哨兵就会将该实例在本结构体中的状态标记为SRI_S_DOWN主观下线

  • 简说

单个哨兵节点认为主节点(master)挂了,master为down,就会执行故障切换,称为主观下线

客观下线详细版

当一个哨兵节点发现主节点处于主观下线状态是,会向其他的哨兵节点发出询问,该节点是不是已经主观下线了。如果超过配置参数quorum个节点认为是主观下线时,该哨兵节点就会将自己维护的结构体中该主节点标记为SRIO DOWN客观下线询问命令SENTINEL is-master-down-by-addr

  • 简说

一台哨兵向master发送ping命令,若master没回复,所有哨兵节点都认为主节点(master)挂了,然后进行故障切换,称为客观下线

主节点master选举详细版

  1. 过滤掉不健康的(已下线的),没有回复哨兵ping 响应的从节点
  2. 选择配置文件中从节点优先级配置最高的。 ( replica-priority, 默认值为100)
  3. 选择复制偏移量最大,也就是复制最完整的从节点

在认为主节点客观下线的情况下,哨兵节点节点间会发起一次选举,命令为:SENTINEL is-master-down-by-addr
只是runid这次会将自己的runid带进去,希望接受者将自己设置为主节点。如果超过半数以上的节点返回将该节点标记为leacer的情况下,会有该leader对故障进行迁移

故障转移详细版**

####在从节点中挑选出新的主节点
		通讯正常
		优先级排序
		优先级相同时选择offset最大的

###将该节点设置成新的主节点SLAVEOF no one,并确保在后续的INGO命令时 该节点返回状态为master 
###将其他的从节点设置成从新的主节点复制,SLAVEOF命令
###将旧的主节点变成新的主节点的从节点

PS:优缺点
#优点:
		高可用,哨兵模式是基于主从模式的,所有主从模式的优点,哨兵模式都具有有;主从可以自动切换,系统更健壮,可用性更高

#缺点:
		redis比较难支持在线扩容,在群集容量达到上限时在线扩容会变得很复杂

5.哨兵们监控整个系统节点的过程

① 首先主节点的信息是配置在哨兵(Sentinel)的配置文件中

② 哨兵节点会和配置的主节点建立起两条连接命令连接和订阅连接
PS:Redis发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消 息,订阅者 (sub) 接收消息

③ 哨兵会通过命令连接每10s发送一次INFO命令,通过INFO命令,主节点会返回自己的run_id和自己的从节点信息

④ 哨兵会对这些从节点也建立两条连接命令连接和订阅连接

⑤ 哨兵通过命令连接向从节点发送INFO命令,获取到他的一些信息:
run id(redis服务器id)
role(职能)
从服务器的复制偏移量offset
其他

⑥ 通过命令连接向服务器的sentinel:hello频道发送一条消息,内容包括自己的ip端口、run id、配置(后续投票的时候会用到)等

⑦ 通过订阅连接对服务器的sentinel:hello频道做了监听,所以所有的向该频道发送的哨兵的消息都能被接受到

⑧ 解析监听到的消息,进行分析提取,就可以知道还有那些别的哨兵服务节点也在监听这些主从节点了,更新结构体将这些
哨兵节点记录下来

⑨ 向观察到的其他的哨兵节点建立命令连接----没有订阅连接

6.哨兵模式优缺点

优点:
1、哨兵集群,基于主从复制模式,所有的主从配置优点,它都有
2、主从可以切换,故障可以转移,高可用性的系统
3、哨兵模式就是主从模式的升级,手动到自动,更加健壮

缺点:
1、Redis不好在线扩容的,集群容量一旦到达上限,在线扩容就十分麻烦
2、哨兵模式的配置繁琐

7.哨兵模式配置

  • 哨兵的启动依赖于主从模式,所以须把主从模式安装好的情况下再去做哨兵模式,三台机器都要配置
  • 环境
节点名   IP地址
master	192.168.113.128
slave1	192.168.113.129
slave2  192.168.113.130
[root@master ~]# cd /opt/redis-5.0.7
[root@master redis-5.0.7]# ls
[root@master redis-5.0.7]# vim sentinel.conf 

#17行,关闭保护模式
protected-mode no		

#21行,Redis哨 兵默认的监听端口
port 26379			

#26行 开启守护进程
daemonize yes		

#36行,指定日志存放路径
logfile "/var/log/sentinel.log"		

#65行,指定数据库存放路径
dir "/var/lib/redis/6379"		

#84行,指定哨兵节点监控主master节点
#2表示,至少需要 2 个哨兵节点同意,才能判定主节点故障并进行故障转移
sentinel monitor mymaster 192.168.113.128 6379 2 	

#113行,判定服务器down掉的时间周期,默认30000毫秒 (30秒 )
sentinel down-after-milliseconds mymaster 3000 		

#146行,故障节点的最大超时时间为180000 (180秒)
sentinel failover-timeout mymaster 180000	

启动哨兵模式

  • 先启动主节点在启动从节点
[root@master ~]# cd /opt/redis-5.0.7
[root@master redis-5.0.7]# redis-sentinel sentinel.conf 
  • 查看哨兵信息
[root@master redis-5.0.7]# redis-cli -p 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=192.168.113.128:6379,slaves=2,sentinels=3

image-20220822193404395

  • 模拟故障
#查看 redis-server 的进程号,杀死它看会不会故障切换
[root@master redis-5.0.7]# ps -ef | grep redis
root      11420      1  0 16:28 ?        00:00:12 /usr/local/redis/bin/redis-server 0.0.0.0:6379
root      13230      1  0 19:32 ?        00:00:00 redis-sentinel *:26379 [sentinel]
root      13270  13084  0 19:36 pts/1    00:00:00 grep --color=auto redis

[root@master redis-5.0.7]# kill -9 11420
[root@master redis-5.0.7]# ps -ef | grep redis   ##再次查看成功杀掉
root      13230      1  0 19:32 ?        00:00:01 redis-sentinel *:26379 [sentinel]
root      13343  13299  0 19:39 pts/2    00:00:00 tail -f /var/log/redis_6379.log
root      13368  13084  0 19:40 pts/1    00:00:00 grep --color=auto redis
  • 再次查看哨兵信息
[root@master redis-5.0.7]# redis-cli -p 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=192.168.113.130:6379,slaves=2,sentinels=3

image-20220822194354199

  • 查看master哨兵日志也可以看到跳转时的动态

image-20220822194324368

哨兵模式总结

1.哨兵是对主从复制集群进行监控,

​ 监控的对象:是所有redis数据节点

2.哨兵与哨兵之间进行互相监控

​ 监控的对象:哨兵彼此

3.监控的目的:

哨兵与哨兵之间的监控目的为:检查彼此的存活状态

哨兵监控所有的redis 数据库的目的:实现故障切换

4.故障切换原理

​ ①当master挂掉,哨兵会及时发现,发现后进行投票机制,选择出一个新的master服务器 (服务器得是奇数)

​ ②完成从到主的切换

​ ③完成其他的从服务器指向新的master的配置

八,Redis Cluster集群模式

1.cluster概述

  • redis的哨兵模式基本已经可以实现高可用、读写分离,但是在这种模式每台redis服务器都存储相同的数据,很浪费内存资源,所以在redis3.0上加入了Cluster群集模式,实现了redis的分布式存储,也就是说每台redis节点存储着不同的内容根据官方推荐,集群部署至少要3台以上的master节点,最好使用3主3从六个节点的模式

  • Cluster群集由多个redis服务器组成的分布式网络服务群集,群集之中有多个master主节点,每一个主节点都可读可写,节点之间会相互通信,两两相连,redis群集无中心节点

  • 在redis-Cluster群集中,可以给每个一个主节点添加从节点,主节点和从节点直接尊循主从模型的特性,当用户需要处理更多读请求的时候,添加从节点可以扩展系统的读性能

  • redis-cluster的故障转移: redis群集的主机节点内置了类似redis sentinel的节点故障检测和自动故障转移功能,当群集中的某个主节点下线时,群集中的其他在线主节点会注意到这一点,并且对已经下线的主节点进行故障转移

  • 集群进行故障转移的方法和redis sentinel进行故障转移的方法基本一样,不同的是,在集群里面,故障转移是由集群中其他在线的主节点负责进行的,所以群集不必另外使用redis sentinel

2.集群的作用

2.1数据分区

数据分区(或称数据分片)是集群最核心的功能
集群将数据分散到多个节点,一方面突破了Redis单机内存大小的限制,存储容量大大增加:另一方面每个主节点都可以对外提供读服务和写服务,大大提高了集群的响应能力

Redis单机内存大小受限问题,在介绍持久化和主从复制时都有提及:例如,如果单机内存太大,bgsave 和bgrewriteaof的fork操作可能导致主进程阻塞,主从环境下主机切换时可能导致从节点长时间无法提供服务,全量复制阶段主节点的复制缓冲区可能溢出

2.2高可用

集群支持主从复制和主节点的自动故障转移(与哨兵类似) :当任一节点发生故障时,集群仍然可以对外提供服务

2.3数据分片
  • Redis 集群引入了哈希槽的概念,有 16384 个哈希槽(编号 0~16383)
  • 集群的每个节点负责一部分哈希槽,每个 Key 通过 CRC16 校验后对 16384 取余来决定放置哪个哈希槽,通过这个值,去找到对应的插槽所对应的节点,然后直接自动跳转到这个对应的节点上进行存取操作
  • 以 3 个节点组成的集群为例:
    节点 A 包含 0~5469 号的哈希槽
    节点 B 包含 5461~10922 号的哈希槽
    节点 C 包含 10923~16383 号的哈希槽
2.4Redis集群的主从复制模型

集群中具有A、B、C三个节点,如果节点B失败了,整个集群就会因缺少5461-10922这个范围的槽而不可以用。
为每个节点添加一个从节点A1、B1、C1整个集群便有三个Master节点和三个slave节点组成,在节点B失败后,集群选举B1位为的主节点继续服务。当B和B1都失败后,集群将不可用

image-20220822200410696

2.5cluster模式优点
  • 读和写可以负载均衡
  • 自动故障转移
  • 突破了单机存储限制

3.搭建cluster集群

环境介绍:

  • redis的集群一般需要6个节点,3主3从。方便起见,这里所有节点在同一台服务器上模拟:
  • 以端口号进行区分:3个主节点端口号:6001/6002/6003, 对应的从节点端口号:6004/ 6005/ 6006
[root@master redis-5.0.7]# cd /etc/redis/
[root@master redis]# mkdir -p redis-cluster/redis600{1..6}
[root@master redis]# ls
6379.conf  6379.conf.bak  redis-cluster

#一键复制 6001~6006 
[root@master redis]# for i in {1..6}
> do
> cp /opt/redis-5.0.7/redis.conf /etc/redis/redis-cluster/redis600$i
> cp /opt/redis-5.0.7/src/redis-cli /opt/redis-5.0.7/src/redis-server /etc/redis/redis-cluster/redis600$i
> done
[root@master redis]# cd redis-cluster/
[root@master redis-cluster]# ls
redis6001  redis6002  redis6003  redis6004  redis6005  redis6006

  • 修改配置文件
[root@master redis-cluster]# cd /etc/redis/redis-cluster/redis6001
[root@master redis6001]# ls
redis-cli  redis.conf  redis-server
[root@master redis6001]# vim redis.conf 

bind 127.0.0.1
#69行,注释掉bind项或不修改,默认监听所有网卡

protected-mode no
#88行,修改,关闭保护模式

port 6001
#92行,修改,redis监听端口,

daemonize yes
#136行,开启守护进程,以独立进程启动

cluster-enabled yes
#832行,取消注释,开启群集功能

cluster-config-file nodes-6001.conf
#840行,取消注释,群集名称文件设置

cluster-node-timeout 15000
#846行,取消注释群集超时时间设置

appendonly yes
#700行,修改,开启AOF持久化

##其他5个配置文件除端口号和集群配置文件名称外改动相同
cp redis.conf ../redis6002/
cp redis.conf ../redis6003/
cp redis.conf ../redis6004/
cp redis.conf ../redis6005/
cp redis.conf ../redis6006/

[root@master redis-cluster]# vim redis6002/redis.conf 
[root@master redis-cluster]# vim redis6003/redis.conf 
[root@master redis-cluster]# vim redis6004/redis.conf 
[root@master redis-cluster]# vim redis6005/redis.conf 
[root@master redis-cluster]# vim redis6006/redis.conf 
  • 根据对应配置文件启动redis

  • 若不是快照从新做要杀死,哨兵进程,和关闭redis,才可以启动起来

  • 要杀死的和关掉的进程如图

image-20220822204134555

image-20220822204109294

[root@master redis-cluster]# for d in {1..6}
> do
> cd /etc/redis/redis-cluster/redis600$d
> redis-server redis.conf
> done

启动成功:

image-20220822204339043

  • 加入集群
[root@master redis6006]# redis-cli --cluster create 127.0.0.1:6001 127.0.0.1:6002 127.0.0.1:6003 127.0.0.1:6004 127.0.0.1:6005 127.0.0.1:6006 --cluster-replicas 1

#六个实例分为三组,每组一主一从,前面的做主节点,后面的做从节点
#下面交互的时候需要输入 yes 才可以创建
#-replicas 1 表示每个主节点有一个从节点

image-20220822204637851

  • 测试集群
[root@master redis6006]# redis-cli -p 6001 -c    #加-c参数,节点之,间就可以互相跳转
127.0.0.1:6001> cluster slots    #查看节点的哈希槽编号范围
1) 1) (integer) 10923
   2) (integer) 16383      #哈希槽编号范围
   3) 1) "127.0.0.1"
      2) (integer) 6003   #主节点IP和端口号
      3) "5d64d77ee9511730ad0cbb838fe4db526443736d"
   4) 1) "127.0.0.1"
      2) (integer) 6004   #从节点IP和端口号
      3) "1f53ec0789305fea561b867825ee2de0c4ba84b3"
2) 1) (integer) 5461
   2) (integer) 10922
   3) 1) "127.0.0.1"
      2) (integer) 6002
      3) "a0cf98212aebce9ec3e3c2df9ad1e62496d20968"
   4) 1) "127.0.0.1"
      2) (integer) 6006
      3) "9fa2597c97f33bc1edd61802b33631f79553d8c9"
3) 1) (integer) 0
   2) (integer) 5460
   3) 1) "127.0.0.1"
      2) (integer) 6001
      3) "9469bd5db53420ad0a8d40b618441545439c4e3d"
   4) 1) "127.0.0.1"
      2) (integer) 6005
      3) "d8b5607616f97c4f0ac6f3f06e5205b8a4b7997a"

image-20220822204857513

  • 在6001创建数据,并查看他的槽位
127.0.0.1:6001> set qjm ky20
-> Redirected to slot [14034] located at 127.0.0.1:6003 #分片到6003进行存储

127.0.0.1:6001> exit
[root@master redis6006]# redis-cli -p 6003 -c
127.0.0.1:6003> get qjm
"ky20"

127.0.0.1:6003> cluster keyslot qjm  查看qjm键的槽编号
(integer) 14034    ##槽位14034 属于6002节点

) “127.0.0.1”
2) (integer) 6003 #主节点IP和端口号
3) “5d64d77ee9511730ad0cbb838fe4db526443736d”
4) 1) “127.0.0.1”
2) (integer) 6004 #从节点IP和端口号
3) “1f53ec0789305fea561b867825ee2de0c4ba84b3”
2) 1) (integer) 5461
2) (integer) 10922
3) 1) “127.0.0.1”
2) (integer) 6002
3) “a0cf98212aebce9ec3e3c2df9ad1e62496d20968”
4) 1) “127.0.0.1”
2) (integer) 6006
3) “9fa2597c97f33bc1edd61802b33631f79553d8c9”
3) 1) (integer) 0
2) (integer) 5460
3) 1) “127.0.0.1”
2) (integer) 6001
3) “9469bd5db53420ad0a8d40b618441545439c4e3d”
4) 1) “127.0.0.1”
2) (integer) 6005
3) “d8b5607616f97c4f0ac6f3f06e5205b8a4b7997a”


[外链图片转存中...(img-XVIO38s7-1663309831614)]

- **在6001创建数据,并查看他的槽位**

```bash
127.0.0.1:6001> set qjm ky20
-> Redirected to slot [14034] located at 127.0.0.1:6003 #分片到6003进行存储

127.0.0.1:6001> exit
[root@master redis6006]# redis-cli -p 6003 -c
127.0.0.1:6003> get qjm
"ky20"

127.0.0.1:6003> cluster keyslot qjm  查看qjm键的槽编号
(integer) 14034    ##槽位14034 属于6002节点
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值