Redis持久化,集群,哨兵,分片存储

文章详细介绍了Redis的持久化机制,包括RDB和AOF两种方式,以及它们的启用配置、原理和优缺点。接着讨论了Redis集群的主从同步机制,包括全量同步和增量同步,并提出了优化策略。哨兵机制用于监控和故障恢复,解释了哨兵如何判断节点健康、执行故障转移的步骤。最后,文章提到了Redis分片集群的概念和搭建过程,以及如何通过Java客户端访问分片集群。
摘要由CSDN通过智能技术生成

目录

一        redis单节点故障导致数据丢失的问题---持久化(AOF,RDB)

1.1        RDB

1.1.1        RDB定义

1.1.2        启用及配置方式:

1.1.3        RDB运行原理

1.1.4        总结

1.2        AOF

1.2.1        AOF定义

1.2.2        启用及配置方式:

1.3        AOF和RDB对比

 二:redis集群,提高redis性能和可用性

2.1       配置命令

2.2        主从数据同步原理(全量和非全量同步)  ​编辑

2.3        优化Redis主从就集群

2.4        总结

2.4.1        简述全量同步和增量同步区别?

2.4.2        什么时候执行全量同步?

2.4.3        什么时候执行增量同步?

2.5        一主两从搭建

三       redis哨兵机制

3.1        哨兵基本概念

 3.2        总结

3.2.1         Sentinel的三个作用是什么?

3.2.2        Sentinel如何判断一个redis实例是否健康?

3.2.3        故障转移步骤有哪些?

3.3        搭建哨兵集群

3.4        java客户端配置并使用哨兵集群

3.4.1        引入依赖,并在配置文件中配置哨兵信息以及读写分离

四        Redis分片集群

4.1        分片集群概念

4.2       搭建分片集群

4.3        散列插槽

4.4        集群伸缩

4.5        故障转移

4.6        数据迁移

4.6        java客户端访问分片集群


 本节内容主要围绕上面4个问题进行学习。

注意:分片集群可以认为是主从结构的进阶版,分片集群中有多个主节点,每一个主节点又有各自的从节点,分片集群不需要哨兵来进行监控和故障转移,它自己就能实现

一        redis单节点故障导致数据丢失的问题---持久化(AOF,RDB)

解决方式:对redis中的数据进行持久化,持久化分为RDB和AOF两种方式。

1.1        RDB

1.1.1        RDB定义

        基于快照方式实现,将当前内存中的数据记录到磁盘中,然后在重启的时候进行数据恢复。

1.1.2        启用及配置方式:

        在reids.conf文件中找到save,然后,设置保存频率,如下:

# 900秒内,如果至少有1个key被修改,则执行bgsave , 如果是save "" 则表示禁用RDB
save 900 1

# 是否压缩 ,建议不开启,压缩也会消耗cpu,磁盘的话不值钱
rdbcompression yes

# RDB文件名称
dbfilename dump.rdb  

# 文件保存的路径目录
dir ./ 

时间间隔太长,在这期间如果服务宕机,会丢失数据;

时间间隔太短,如果数据太多,会忙不过来。   

1.1.3        RDB运行原理

        bgsave开始时会fork主进程得到子进程,子进程共享主进程的内存数据,主线程就会去继续执行任务。完成fork后读取内存数据并写入 RDB 文件。

         Linux系统中,进程是无法直接操作物理内存的,只能通过虚拟内存去操作页表,然后通过页表的映射关系去访问物理内存,所以在进行拷贝时,子线程fork的是页表的数据,然后将拷贝过来的页表中的数据写入RDB文件中,最后会替换旧的RDB文件;

        fork采用的是copy-on-write技术: 当主进程执行读操作时,访问共享内存; 当主进程执行写操作时,则会拷贝一份数据(内存会翻倍),然后执行写操作,进行数据覆盖。

需要注意:

        repl_baklog大小有上限的,写满后会覆盖最早的数据。如果slave断开时间过久,导致尚未备份的数据被覆盖了,则无法基于log做增量同步了,只能再次全量同步

1.1.4        总结

RDB方式bgsave的基本流程?

        fork主进程得到一个子进程,共享内存空间 子进程读取内存数据并写入新的RDB文件 用新RDB文件替换旧的RDB文件。

RDB会在什么时候执行?save 60 1000代表什么含义?

         默认是服务停止时。 代表60秒内至少执行1000次修改则触发RDB

RDB的缺点?

        RDB执行间隔时间长,两次RDB之间写入数据有丢失的风险 fork子进程、压缩、写出RDB文件都比较耗时

1.2        AOF

1.2.1        AOF定义

        Redis处理的每一个写命令都会记录在AOF文件,可以看做是命令日志文件。操作命令组成的文件。

1.2.2        启用及配置方式:

        在启用AOF前,我们可以先将AOF的持久化方式注销,save "",设置save为空字符就行。

# 是否开启AOF功能,默认是no
appendonly yes

# AOF文件的名称
appendfilename "appendonly.aof"


Aof命令记录频率,一般用默认即可
# 表示每执行一次写命令,立即记录到AOF文件
appendfsync always 

# 写命令执行完先放入AOF缓冲区,然后表示每隔1秒将缓冲区数据写到AOF文件,是默认方案
appendfsync everysec 

# 写命令执行完先放入AOF缓冲区,由操作系统决定何时将缓冲区内容写回磁盘
appendfsync no



# AOF文件比上次文件 增长超过多少百分比则触发重写
auto-aof-rewrite-percentage 100
# AOF文件体积最小多大以上才触发重写 
auto-aof-rewrite-min-size 64mb 

        优化点:AOF文件中记录的是我们操作的每一个写命令,如果我们操作的是同一个KEY,按理讲,只需要最后一次的写命令就行了,这时,我们可以通过bgrewriteaof命令,可以让AOF文件执行重写功能,可以只保留最后一个命令,并且可以用过mset等命令进行批量写。

1.3        AOF和RDB对比

 二:redis集群,提高redis性能和可用性

2.1       配置命令

有临时和永久两种模式:

- 修改配置文件(永久生效)

  - 在redis.conf中添加一行配置:slaveof <masterip> <masterport>

- 使用redis-cli客户端连接到redis服务,执行slaveof命令(重启后失效):
  slaveof <masterip> <masterport>

2.2        主从数据同步原理(全量和非全量同步)  

        集群搭建成功后,会进行数据同步请求,master会根据从节点传递过来的Replication Id去判断,看传递过来的是不是master的数据集id,

        不是:会进行全量同步,并且将master的信息返回,从节点进行记录,主节点会执行bgsave,进行数据快照,然后将生成的RDb文件发送给从节点,在bgsave期间,可能会有其他的命令,这些会保存在repl_baklog中,后续也会发送到从节点。

        是:说明之前进行过数据同步,从节点会保存自己之前同步的记录,之前同步到了哪里,就是偏移量,后续主节点只需要根据从节点发送过来的offset偏移量,从repl_baklog进行增量同步,这时,会有一个坑,这个repl_baklog是环形存储,长时间未同步,并且这期间有大量的数据生成,数据会被覆盖。

        所以会在1.1的时候,从节点会传递Replication Id和offset,主节点会判断Replication Id是不是自己的数据集id,是或者不是会走上面的两个逻辑。

        全量同步的流程: slave节点请求增量同步 master节点判断replid,发现不一致,拒绝增量同步 master将完整内存数据生成RDB,发送RDB到slave slave清空本地数据,加载master的RDB master将RDB期间的命令记录在repl_baklog,并持续将log中的命令发送给slave slave执行接收到的命令,保持与master之间的同步。

2.3        优化Redis主从就集群

         在master中配置repl-diskless-sync yes启用无磁盘复制,避免全量同步时的磁盘IO。

         Redis单节点上的内存占用不要太大,减少RDB导致的过多磁盘IO

        适当提高repl_baklog的大小,发现slave宕机时尽快实现故障恢复,尽可能避免全量同步

        限制一个master上的slave节点数量,如果实在是太多slave,则可以采用主-从-从链式结构,减少master压力 

2.4        总结

2.4.1        简述全量同步和增量同步区别?

        全量同步:master将完整内存数据生成RDB,发送RDB到slave。后续命令则记录在repl_baklog,逐个发送给slave。

        增量同步:slave提交自己的offset到master,master获取repl_baklog中从offset之后的命令给slave

2.4.2        什么时候执行全量同步?

         slave节点第一次连接master节点时 slave节点断开时间太久,repl_baklog中的offset已经被覆盖时

2.4.3        什么时候执行增量同步?

        slave节点断开又恢复,并且在repl_baklog中能找到offset时

2.5        一主两从搭建

        这里采用的方法会在重启时失效,也可采用在配置文件中直接配置slaveof <masterip> <masterport>,这样就是永久生效。

在mac上进行操作,设置不同的端口,模拟三台机器
1:    首先要安装redis相关命令,之前已安装brew,所以直接安装redis即可
    brew install redis

2:    创建redis主从的存放目录temp,并且在temp下创建3个目录,用来模拟三台机器
    cd docker-data
    midir redisZhuCong
    cd redisZhuCong
    mkdir 7001 7002 7003

3:    修改配置文件,均在redisZhuCong下进行操作,执行命令
    3.1:下载官方配置文件:https://raw.githubusercontent.com/redis/redis/6.2/redis.conf
    然后拷贝到redisZhuCong目录下

    3.2: # 开启RDB,默认就是
    # save ""

    3.3: # 关闭AOF
    appendonly no

    3.4: # 进入redisZhuCong目录,然后将redis.conf文件拷贝到三个目录中
    echo 7001 7002 7003 | xargs -t -n 1 cp redis.conf

    3.5: 修改端口
    sed -i -e 's/6379/7002/g' 7002/redis.conf
    sed -i -e 's/6379/7003/g' 7003/redis.conf
    sed -i -e 's/6379/7001/g' 7001/redis.conf

    3.6: 修改文件保存路径,这个使用命令没有成功,手动一个个替换,搜索《dir加一个空格》,然后将dir后的默认路径替换,/Users/***/docker-data/redisZhuCong/7003/,就是7001到3的pwd


    3.7: # redis实例的声明 IP,实际情况每一个机器的ip是不一样的,这里我们用的是一个机器,只是端口不一样,也是手动替换,快捷命令没生效。
    用的是本地ip,127.0.0.1
    
    replica-announce-ip 自己的ip

    快捷命令:printf '%s\n' 7001 7002 7003 | xargs -I{} -t sed -i '1a replica-announce-ip 自己的ip' {}/redis.conf
    


4:    分别启动三台机器,进入redisZhuCong目录,然后执行下面的启动命令
# 第1个
redis-server 7001/redis.conf
# 第2个
redis-server 7002/redis.conf
# 第3个
redis-server 7003/redis.conf


5:    分别连接三台机器
# 连接 7001, 7002, 7003
redis-cli -p 7001
redis-cli -p 7002
redis-cli -p 7003


6:    这里是将7001作为了主节点
# 在7002和7003的命令界面分别执行slaveof,
# 就可以看到三台机器的启动界面有命令变化,节点注册及数据同步请求
slaveof 127.0.0.1 7001


 测试:在7001主节点set num 666,然后在两个从节点上就可以get num的值了

配置文件:

https://raw.githubusercontent.com/redis/redis/6.2/redis.conf

三       redis哨兵机制

3.1        哨兵基本概念

        哨兵(Sentinel)机制来实现主从集群的自动故障恢复。主要有以下三个功能:

        监控:Sentinel 会不断检查您的master和slave是否按预期工作,基于心跳机制监控集群中每一个redis节点的状态,每隔1秒向集群的每个实例发送ping命令,redis各健康节点会回复pong;

        自动故障恢复:如果master故障,Sentinel会将一个slave提升为master。当故障实例恢复后会作为一个从节点,以新的master为主;

        判断一个节点是分两步的:主观下线和客观下线;

  •         主观下线:如果某sentinel节点发现某实例未在规定时间响应,则认为该实例主观下线。
  •         客观下线:若超过指定数量(quorum)的sentinel都认为该实例主观下线,则该实例客观下线。quorum值最好超过Sentinel实例数量的一半。

        并且如果是master节点挂了,在选举新的master节点时是有四个依据的:

  •         首先会判断slave节点与master节点断开时间长短,如果超过指定值(down-after-milliseconds * 10)则会排除该slave节点;
  •         然后判断slave节点的slave-priority值,越小优先级越高,如果是0则永不参与选举
  •         如果slave-prority一样,则判断slave节点的offset值,越大说明数据越新,优先级越高
  •         最后是判断slave节点的运行id大小,越小优先级越高。

        当选中了其中一个slave为新的master后(例如slave1),故障的转移的步骤如下:       

  •         sentinel给备选的slave1节点发送slaveof no one命令,让该节点成为master
  •         sentinel给所有其它slave发送( slaveof 新master节点IP 新master节点port  )命令,让这些slave成为新master的从节点,开始从新的master上同步数据。
  •         最后,sentinel将故障节点标记为slave,当故障节点恢复后会自动成为新的master的slave节点

        通知:Sentinel充当Redis客户端的服务发现来源,当集群发生故障转移时,会将最新信息推送给Redis的客户端,我们在编写代码的时候,如果redis节点出现故障,哨兵在进行故障恢复时,我们是无感的。

 3.2        总结

3.2.1         Sentinel的三个作用是什么?

        监控         故障转移         通知

3.2.2        Sentinel如何判断一个redis实例是否健康?

        每隔1秒发送一次ping命令,如果超过一定时间没有相向则认为是主观下线,如果大多数sentinel都认为实例下线了,就是客观下线,就会判定该服务下线。

3.2.3        故障转移步骤有哪些?

        首先选定一个slave作为新的master,执行slaveof no one,让此节点成为主节点,然后让所有节点都执行slaveof 新master节点的ip和端口,并且修改之前的故障节点配置,都成为从节点。

3.3        搭建哨兵集群

1: 先创建3个文件夹,用来模拟三个redis哨兵
    cd docker-data/redisZhuCong
    mkdir s1 s2 s3

2:  然后在redisZhuCong目录下创建一个配置文件,sentinel.conf,添加下面的内容
    port 27001
    sentinel announce-ip 127.0.0.1
    sentinel monitor mymaster 127.0.0.1 7001 2
    sentinel down-after-milliseconds mymaster 5000
    sentinel failover-timeout mymaster 60000
    dir "/Users/*****/docker-data/redisZhuCong/s1"

    配置解析:
  - `port 27001`:是当前sentinel实例的端口
  - `sentinel monitor mymaster 127.0.0.1 7001 2`:指定主节点信息
  - `mymaster`:主节点名称,自定义,任意写
  - `127.0.0.1 7001`:主节点的ip和端口
  - `2`:选举master时的quorum值

3:    将配置文件复制到s1,s2,s3目录下,在redisZhuCong目录下执行下面的命令

cp sentinel.conf s1 
cp sentinel.conf s2
cp sentinel.conf s3


4:    修改配置文件
    修改port和dir的保存目录

5:  为了方便查看日志,我们打开3个ssh窗口,分别启动3个redis实例,启动命令:
    在redisZhuCong目录下执行下面的命令
  
# 第1个
redis-sentinel s1/sentinel.conf
# 第2个
redis-sentinel s2/sentinel.conf
# 第3个
redis-sentinel s3/sentinel.conf



3.4        java客户端配置并使用哨兵集群

        哨兵就是用来监控redis集群中各个节点的,所以我们只需要在配置文件中添加上哨兵的信息,就能自动找到我们的redis节点信息,不用我们来细化操作,直接运用就好。

3.4.1        引入依赖,并在配置文件中配置哨兵信息以及读写分离
1:引入依赖:
<dependency>    
    <groupId>org.springframework.boot</groupId>    
    <artifactId>spring-boot-starter-data-redis</artifactId> 
</dependency>

2:配置文件中配置哨兵信息
spring:  
    redis:    
        sentinel:      
            master: mymaster # 指定master名称      
            nodes: # 指定redis-sentinel集群信息         
                - 192.168.150.101:27001        
                - 192.168.150.101:27002        
                - 192.168.150.101:27003

3:配置读写分离
@Bean
public LettuceClientConfigurationBuilderCustomizer configurationBuilderCustomizer(  {    return configBuilder -> configBuilder.readFrom(ReadFrom.REPLICA_PREFERRED);}

这里的ReadFrom是配置Redis的读取策略,是一个枚举,包括下面选择:主要用第四个
MASTER:从主节点读取
MASTER_PREFERRED:优先从master节点读取,master不可用才读取replica
REPLICA:从slave(replica)节点读取
REPLICA _PREFERRED:优先从slave(replica)节点读取,所有的slave都不可用才读取master

四        Redis分片集群

4.1        分片集群概念

        主从和哨兵可以解决高可用、高并发读的问题。但是依然有两个问题没有解决: 海量数据存储问题 高并发写的问题;

        使用分片集群可以解决上述问题,分片集群特征:

  •         集群中有多个master,每个master保存不同数据
  •         每个master都可以有多个slave节点
  •         master之间通过ping监测彼此健康状态
  •         客户端请求可以访问集群任意节点,最终都会被转发到正确节点

4.2       搭建分片集群

搭建三主三从的集群

1:    创建6个文件夹,8001,8002,8003,8004,8005,8006

    cd docker-data
    mkdir redisFenPian
    mkdir 8001 8002 8003 8004 8005 8006

2:    分别在6个文件夹下创建一个配置文件,redis.conf,并且添加配置信息
    vi redis.conf

解析:
port为对应文件夹名
更改配置文件,工作目录,日志保存位置

port 8006
# 开启集群功能
cluster-enabled yes
# 集群的配置文件名称,不需要我们创建,由redis自己维护
cluster-config-file /Users/*****/docker-data/redisFenPian/8006/nodes.conf
# 节点心跳失败的超时时间
cluster-node-timeout 5000
# 持久化文件存放目录
dir /Users/*****/docker-data/redisFenPian/8006
# 绑定地址
bind 0.0.0.0
# 让redis后台运行
daemonize yes
# 注册的实例ip
replica-announce-ip 127.0.0.1
# 保护模式
protected-mode no
# 数据库数量
databases 1
# 日志
logfile /Users/*****/docker-data/redisFenPian/8006/run.log



3:    运行,在redisfenpian目录下执行printf '%s\n' 8001 8002 8003 8004 8005 8006 | xargs -I{} -t redis-server {}/redis.conf

ps -ef | grep redis    ,可以查看是否运行成功


4:    关闭命令,在redisfenpian目录下执行
ps -ef | grep redis | awk '{print $2}' | xargs kill

    
5:    我们使用的是Redis6.2.4版本,集群管理以及集成到了redis-cli中,格式如下:
(运行一次就行了,后续只需要运行上面的启动命令就可了,不需要再次进行分区)


redis-cli --cluster create --cluster-replicas 1 127.0.0.1:8001 127.0.0.1:8002 127.0.0.1:8003 127.0.0.1:8004 127.0.0.1:8005 127.0.0.1:8006

还有一个Redis5.0之前集群命令都是用redis安装包下的src/redis-trib.rb来实现的。因为redis-trib.rb是有ruby语言编写的所以需要安装ruby环境。

 ```sh
 # 安装依赖
 yum -y install zlib ruby rubygems
 gem install redis
# 进入redis的src目录,创建集群
./redis-trib.rb create --replicas 1 192.168.150.101:7001 192.168.150.101:7002 192.168.150.101:7003 192.168.150.101:8001 192.168.150.101:8002 192.168.150.101:8003


解析:
- `redis-cli --cluster`或者`./redis-trib.rb`:代表集群操作命令
- `create`:代表是创建集群
- `--replicas 1`或者`--cluster-replicas 1` :指定集群中每个master的副本个数为1,此时`节点总数 ÷ (replicas + 1)` 得到的就是master的数量。因此节点列表中的前n个就是master,其它节点都是slave节点,随机分配到不同master


6:    查看集群状态,节点可以是任意一个
redis-cli -p 8001 cluster nodes


7:    连接测试
redis-cli -c -p 7001

分片集群客户端连接需要注意,  加。-c     否则我们在set一个不在登陆客户端上对应的卡槽值时会报错,加上-c就会自动切换客户端。

4.3        散列插槽

        Redis会把每一个master节点映射到0~16383共16384个插槽(hash slot)上,查看集群信息时就能看到:

         数据key不是与节点绑定,而是与插槽绑定。redis会根据key的有效部分计算插槽值,分两种情况:

  •         key中包含"{}",且“{}”中至少包含1个字符,“{}”中的部分是有效部分
  •         key中不包含“{}”,整个key都是有效部分

        例如:key是num,那么就根据num计算,如果是{itcast}num,则根据itcast计算。计算方式是利用CRC16算法得到一个hash值,然后对16384取余,得到的结果就是slot值。

        注意:如果要将同一类数据固定的保存在同一个Redis实例,只需要这一类数据使用相同的有效部分,例如key都以{typeId}为前缀

4.4        集群伸缩

redis-cli --cluster提供了很多操作集群的命令,可以通过在命令后追加--help去查看更多的命令:

查看当前集群信息
redis-cli -p 8001 cluster nodes  
查询操作命令      
redis-cli --cluster help


一:    添加节点
1:    新加一个节点,在redisfenpian目录下操作
    mkdir 8008
    cp 8001/redis.conf 8008
    然后修改配置文件中的8001改为为8008

2:    启动8008
    redis-server 8008/redis.conf

3:    查询节点信息,这个时候只是8008还没加入集群中
    redis-cli -p 8001 cluster nodes 

4:    将8008加入到集群中,可查询帮助命令
    redis-cli --cluster add-node 127.0.0.1:8008 127.0.0.1:8001
    再次查询集群信息,8008就已经加入了,但是还没有分槽

5;    给8008节点分槽
    redis-cli --cluster reshard 127.0.0.1:8001
    5.1:    分多少槽
    5.2:    哪个节点接受,集群信息查询命令可知道节点id,复制即可
    5.3:    从哪个节点迁移,同上
    5.4:    只需要一个节点迁移的话就可以done了
    5.5:    yes


二:    删除8008节点
    要先将卡槽迁移到其他节点才能删除
    
1:    8008节点卡槽迁移同上面的第五步
2:    删除节点
    redis-cli --cluster del-node 127.0.0.1:8008 节点id
    

4.5        故障转移

当集群中有一个master宕机会发生什么呢?

  •         首先是该实例与其它实例失去连接
  •         然后是疑似宕机,命令界面会有fail?
  •         最后是确定下线,命令界面直接显示fail,自动提升一个slave为新的master。

4.6        数据迁移

        利用cluster failover命令可以手动让集群中的某个master宕机,切换到执行cluster failover命令的这个slave节点,实现无感知的数据迁移。其流程如下:

        手动的Failover支持三种不同模式:

  •         缺省:默认的流程,如图1~6歩
  •         force:省略了对offset的一致性校验
  •         takeover:直接执行第5歩,忽略数据一致性、忽略master状态和其它master的意见

4.6        java客户端访问分片集群

        RedisTemplate底层同样基于lettuce实现了分片集群的支持,而使用的步骤与哨兵模式基本一致:

  • 引入redis的starter依赖
  • 配置分片集群地址
  • 配置读写分离

与哨兵模式相比,其中只有分片集群的配置方式略有差异,只有在配置文件中的配置数据时不同

只有第二步与配置哨兵时不一样

1:引入依赖:
<dependency>    
    <groupId>org.springframework.boot</groupId>    
    <artifactId>spring-boot-starter-data-redis</artifactId> 
</dependency>

2:配置文件中配置哨兵信息
spring:  
    redis:    
        cluster:      
            nodes: # 指定分片集群的每一个节点信息        
                - 192.168.150.101:7001        
                - 192.168.150.101:7002        
                - 192.168.150.101:7003         
                - 192.168.150.101:8001        
                - 192.168.150.101:8002        
                - 192.168.150.101:8003


3:配置读写分离
@Bean
public LettuceClientConfigurationBuilderCustomizer configurationBuilderCustomizer(  {    return configBuilder -> configBuilder.readFrom(ReadFrom.REPLICA_PREFERRED);}

这里的ReadFrom是配置Redis的读取策略,是一个枚举,包括下面选择:主要用第四个
MASTER:从主节点读取
MASTER_PREFERRED:优先从master节点读取,master不可用才读取replica
REPLICA:从slave(replica)节点读取
REPLICA _PREFERRED:优先从slave(replica)节点读取,所有的slave都不可用才读取master

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值