【图文详解】RabbitMQ集群搭建、镜像队列、负载均衡HAProxy、故障转移Keepalived

本教程是RabbitMQ系列教程的延续;搭建环境在之前的基础之上。

1、搭建集群

1)克隆三台虚拟机

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

2)SSH连接

在这里插入图片描述

3)修改hostname名称

三台机器分别为node1、node2、node3

不同的系统修改方法不同,CentOS7修改方法:

  • 命令修改
# 修改
hostnamectl set-hostname node1
# 重启
reboot
  • 文件修改
# 修改文件
vim /etc/hostname


# 删除或注释掉原来的,在前面加上node1
node1
# localhost.localdomain 

# 退出保存

# 重启
reboot

4)修改hosts文件

修改每台机器的 /etc/hosts 文件,让各个节点都能互相识别对象

vim /etc/hosts

# 添加
192.168.19.102 node1
192.168.19.103 node2
192.168.19.104 node3

在这里插入图片描述

5)同步cookie文件

以确保各个节点的cookie文件使用的是同一个值:在 node1上执行远程操作命令

scp /var/lib/rabbitmq/.erlang.cookie root@node2:/var/lib/rabbitmq/.erlang.cookie
scp /var/lib/rabbitmq/.erlang.cookie root@node3:/var/lib/rabbitmq/.erlang.cookie

在这里插入图片描述

6)启动RabbitMQ服务

顺带启动Erlang虚拟机和RabbitMQ应用服务;三个节点都执行

rabbitmq-server -detached

7)节点2加入节点1

# rabbitmqctl stop 会将Erlang虚拟机关闭  rabbitmqctl stop_app 只关闭rabbitmq服务
rabbitmqctl stop_app
# 重置
rabbitmqctl reset
# 加入节点1
rabbitmqctl join_cluster rabbit@node1
# 只启动rabbitmq服务
rabbitmqctl start_app

出现端口未开启问题,端口开启后继续执行

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

  • 开启 436925672 端口,并重启防火墙;三个节点都分别开启
# 开启防火墙 4369 端口
firewall-cmd --zone=public --add-port=4369/tcp --permanent

# 开启防火墙 25672 端口
firewall-cmd --zone=public --add-port=25672/tcp --permanent

# 重启
systemctl restart firewalld.service

在这里插入图片描述

  • 继续执行节点2加入节点1

在这里插入图片描述

8)节点3加入节点2

# 停止服务
rabbitmqctl stop_app
# 重置
rabbitmqctl reset
# 加入节点2
rabbitmqctl join_cluster rabbit@node2
# 启动服务
rabbitmqctl start_app

在这里插入图片描述

9)查看集群状态

# 可以在任一节点下查看
rabbitmqctl cluster_status

在这里插入图片描述

10)设置用户

# 在任一节点下设置即可

# 创建账号
rabbitmqctl add_user admin admin
# 设置用户角色
rabbitmqctl set_user_tags admin administrator
# 设置用户权限
rabbitmqctl set_permissions -p "/" admin ".*" ".*" ".*"

11)web界面

在这里插入图片描述

12)集群的关闭与重启

没有一个直接的命令可以关闭整个集群,需要逐一进行关闭。但是需要保证在重启时,最后关闭的节点最先被启动。如果第一个启动的不是最后关闭的节点,那么这个节点会等待最后关闭的那个节点启动,默认进行 10 次连接尝试,超时时间为 30 秒,如果依然没有等到,则该节点启动失败。

这带来的一个问题是,假设在一个三节点的集群当中,关闭的顺序为 node1,node2,node3,如果 node1 因为故障暂时没法恢复,此时 node2 和 node3 就无法启动。想要解决这个问题,可以先将 node1 节点进行剔除,命令如下:

rabbitmqctl forget_cluster_node rabbit@node1 --offline

此时需要加上 -offline 参数,它允许节点在自身没有启动的情况下将其他节点剔除。

13)解除节点

rabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl start_app
rabbitmqctl cluster_status

# 此项命令在node1上执行;node1 忘掉 node2,即 node2 脱离 node1
rabbitmqctl forget_cluster_node rabbit@node2

2、镜像队列

1)使用镜像的原因

如果 RabbitMQ 集群中只有一个Broker节点,那么该节点的失效将导致整体服务的临时性不可用,并且也可能会导致消息的丢失。可以将所有消息都设置为持久化,并且对应队列的durable属性也设置为true,但是这样仍然无法避免由于缓存导致的问题:因为消息在发送之后和被写入磁盘并执行刷盘动作之间,存在一个短暂却会产生问题的时间窗。通过发布确认机制能够确保客户端知道哪些消息己经存入磁盘,尽管如此,一般不希望遇到因单点故障导致的服务不可用。

引入镜像队列(Mirror Queue)的机制,可以将队列镜像到集群中的其他Broker节点之上;如果集群中的一个节点失效了,队列能自动地切换到镜像中的另一个节点上以保证服务的可用性。

2)搭建步骤

(1)启动三台集群节点

(2)随便找一个节点添加policy

在这里插入图片描述

在这里插入图片描述

(3)测试

  • 生产者:向节点node1(192.168.19.102)发送消息
package com.tuwer.rabbitmq.simple;

import com.rabbitmq.client.*;
import com.tuwer.utils.RabbitMqUtils;

import java.io.IOException;
import java.time.LocalDateTime;

/**
 * @author 土味儿
 * Date 2022/3/23
 * @version 1.0
 * -------------
 * 生产者
 * 供应商(provider)
 */
public class Producer {
    public static void main(String[] args) {
        // 工具类
        RabbitMqUtils mqUtils = new RabbitMqUtils();
        // 获取通道
        Channel channel = mqUtils.getChannel(
                "192.168.19.102",
                5672,
                "admin",
                "admin",
                "/",
                "生产者");

        try {
            // 通过通道声明队列queue存储消息
            //String queueName = "queue1";
            String queueName = "mirror.queue";

            channel.queueDeclare(queueName, false, false, false, null);

            // 准备消息
            String message = "Hello World! " + LocalDateTime.now();
            // 发送消息
            channel.basicPublish("", queueName, null, message.getBytes());

            System.out.println("消息发送成功!");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 关闭
            mqUtils.close();
        }
    }
}

在这里插入图片描述

在这里插入图片描述

  • 关闭node1

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

  • 消费者接收消息:只能从 node2 或 node3 接收

在这里插入图片描述

  • 配置了镜像队列后,向任何一个节点发送消息,都可以从任何一个节点接收,只要该节点可以访问
  • 节点重新启动后,需要重启服务 systemctl start rabbitmq-server,或者设置为 开机启动服务 systemctl enable rabbitmq-server

3、负载均衡 HAProxy

1)HAProxy 介绍

  • 免费、快速并且可靠
  • HAProxy 是一个使用C语言编写的自由及开放源代码软件,其提供高可用性负载均衡,以及基于TCP和HTTP的应用程序代理。
  • HAProxy 特别适用于那些负载特大的web站点,这些站点通常又需要会话保持或七层处理。HAProxy运行在当前的硬件上,完全可以支持数以万计的并发连接。并且它的运行模式使得它可以很简单安全的整合进您当前的架构中, 同时可以保护你的web服务器不被暴露到网络上
  • HAProxy 实现了一种 事件驱动, 单一进程模型,此模型支持非常大的并发连接数。多进程或多线程模型受内存限制 、系统调度器限制以及无处不在的锁限制,很少能处理数千并发连接。事件驱动模型因为在有更好的资源和时间管理的用户空间(User-Space) 实现所有这些任务,所以没有这些问题。此模型的弊端是,在多核系统上,这些程序通常扩展性较差。这就是为什么他们必须进行优化以 使每个CPU时间片(Cycle)做更多的工作。
  • 包括 GitHub、Bitbucket、Stack Overflow、Reddit、Tumblr、Twitter和 Tuenti在内的知名网站,及亚马逊网络服务系统都使用了HAProxy。

2)安装运行架构图

在这里插入图片描述

3)安装

yum 源安装目前版本比较低,采用源码安装方式。

  • 下载依赖包
# gcc  c语言环境
# vim  编辑器
# wget 下载工具
yum install gcc vim wget
  • 下载安装包 haproxy-2.5.5.tar.gz

下载地址:https://www.haproxy.org/#down

在这里插入图片描述

  • 上传安装包

可以上传至任意目录下。此处上传到home目录下

[root@node1 /]# cd home
[root@node1 home]# rz

[root@node1 home]# ls
haproxy-2.5.5.tar.gz
  • 解压安装包
tar -zxvf haproxy-2.5.5.tar.gz -C /usr/local

在这里插入图片描述

  • 编译、安装

    在安装根目录下执行,即 /usr/local/haproxy-2.5.5

# 编译
make TARGET=linux-glibc  PREFIX=/usr/local/haproxy-2.5.5
# 安装
make install PREFIX=/usr/local/haproxy-2.5.5
  • 配置环境变量
vim /etc/profile
# 在文件最后加上
export HAPROXY_HOME=/usr/local/haproxy-2.5.5
export PATH=$PATH:$HAPROXY_HOME/sbin

使配置的环境变量立即生效:

# 方式一
source /etc/profile
# 方式二
. /etc/profile

在这里插入图片描述

  • 负载均衡配置

新建配置文件 haproxy.cfg,位置为:/etc/haproxy/haproxy.cfg

# 创建目录
mkdir /etc/haproxy
# 编辑文件内容
vim /etc/haproxy/haproxy.cfg

文件内容:

# 全局配置
global
    # 日志输出配置、所有日志都记录在本机,通过 local0 进行输出
    log 127.0.0.1 local0 info
    # 最大连接数
    maxconn 4096
    # 改变当前的工作目录
    chroot /usr/local/haproxy-2.5.5
    # 以指定的 UID 运行 haproxy 进程
    uid 99
    # 以指定的 GID 运行 haproxy 进程
    gid 99
    # 以守护进程的方式运行
    daemon
    # 当前进程的 pid 文件存放位置
    pidfile /usr/local/haproxy-2.5.5/haproxy.pid

# 默认配置
defaults
    # 应用全局的日志配置
    log global
    # 使用4层代理模式,7层代理模式则为"http"
    mode tcp
    # 日志类别
    option tcplog
    # 不记录健康检查的日志信息
    option dontlognull
    # 3次失败则认为服务不可用
    retries 3
    # 每个进程可用的最大连接数
    maxconn 2000
    # 连接超时
    timeout connect 5s
    # 客户端超时
    timeout client 120s
    # 服务端超时
    timeout server 120s

# 绑定配置
listen rabbitmq_cluster
    # 根据安装节点来定
    #bind :192.168.19.102:5671
    bind :5671
    # 配置TCP模式
    mode tcp
    # 采用加权轮询的机制进行负载均衡
    balance roundrobin
    # RabbitMQ 集群节点配置
    server mq-node1  node1:5672 check inter 5000 rise 2 fall 3 weight 1
    server mq-node2  node2:5672 check inter 5000 rise 2 fall 3 weight 1
    server mq-node3  node3:5672 check inter 5000 rise 2 fall 3 weight 1

# 配置监控页面
listen monitor
    bind :8100
    mode http
    option httplog
    stats enable
    stats uri /stats
    stats refresh 5s

负载均衡的主要配置在 listen rabbitmq_cluster 下,这里指定负载均衡的方式为加权轮询,同时定义好健康检查机制:

server node1 rabbit-node1:5672 check inter 5000 rise 2 fall 3 weight 1

以上配置代表对地址为 node1:5672 的 node1 节点每隔 5 秒进行一次健康检查,如果连续两次的检查结果都是正常,则认为该节点可用,此时可以将客户端的请求轮询到该节点上;如果连续 3 次的检查结果都不正常,则认为该节点不可用。weight 用于指定节点在轮询过程中的权重

4)启动服务

# 启动
haproxy -f /etc/haproxy/haproxy.cfg

# 查看运行
ps aux|grep haproxy

# 停止 没有killall命令, 安装yum -y install psmisc
killall haproxy
  • 开启端口:5671 8100
# 开启监控端口:8100
firewall-cmd --zone=public --add-port=8100/tcp --permanent
# 开启服务端口:5671
firewall-cmd --zone=public --add-port=5671/tcp --permanent
# 重启防火墙
systemctl restart firewalld.service

在这里插入图片描述

  • 打开监控页面

在这里插入图片描述

在这里插入图片描述

所有节点都为绿色,代表节点健康。此时证明 HAProxy 搭建成功,并已经对 RabbitMQ 集群进行监控。

5)测试

由于HAProxy是安装node1下,所以生产者和消费者可以访问192.168.19.102:5671;记着开启 5671 端口

  • 生产者发消息

在这里插入图片描述

在这里插入图片描述

  • 消费者接收消息

在这里插入图片描述

  • 关闭两个节点测试

    关闭node1和node3中的rabbitmq服务 rabbitmqctl stop_app

    node1节点中运行有mq服务,也有HAProxy服务,只关闭mq服务

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

  • 重启node3节点 rabbitmqctl start_app

    重启前发送一条消息,放在队列中不去消费,观察镜像的备份变化

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

至此HAProxy安装完成!但是现在严重依赖于node1,如果node1挂掉了,整个集群也就挂掉了…

4、故障转移 Keepalived

搭建Keepalived前,把HAProxy也安装在node2上,配置与node1类似

接着就可以搭建 Keepalived 来解决 HAProxy 故障转移的问题。这里在 node1 和 node2 上安装 KeepAlived ,两台主机上的搭建的步骤完全相同,只是部分配置略有不同,具体如下:

环境说明

NameIP AddrService NameDescprition
VIP192.168.19.100虚拟 IP
MASTER192.168.19.102node1主服务器 IP
BACKUP192.168.19.103node2备服务器 IP

1)安装运行架构图

在这里插入图片描述

  • 简略图

在这里插入图片描述

2)安装

Keepalived 可以使用 yum 直接安装,在 MASTER 服务器和 BACKUP 服务器执行:

yum -y install keepalived

在这里插入图片描述

3)配置 MASTER 和 BACKUP

(1)确认网卡

ip a

在这里插入图片描述

(2)MASTER 节点配置

vim /etc/keepalived/keepalived.conf
global_defs {
   # 路由id,主备节点不能相同
   router_id node1
   
   notification_email {
     # email 接收方
     acassen@firewall.loc
     failover@firewall.loc
     sysadmin@firewall.loc
   }
   
   # email 发送方
   notification_email_from Alexandre.Cassen@firewall.loc
   # 邮件服务器, smtp 协议
   smtp_server 192.168.200.1
   smtp_connect_timeout 30
   
   vrrp_skip_check_adv_addr
   # 使用 unicast_src_ip 需要注释 vrrp_strict,而且也可以进行 ping 测试
   #vrrp_strict 
   vrrp_garp_interval 0
   vrrp_gna_interval 0
}

# 自定义监控脚本
vrrp_script chk_haproxy {
    # 脚本位置
    script "/etc/keepalived/haproxy_check.sh" 
    # 脚本执行的时间间隔
    interval 5 
    weight 10
}

vrrp_instance VI_1 {
    # Keepalived的角色,MASTER 表示主节点,BACKUP 表示备份节点
    state MASTER 
    
    # 指定监测的网卡,可以使用 ifconfig 进行查看
    interface ens32
    
    # 虚拟路由的id,主备节点需要设置为相同
    virtual_router_id 51
    
    # 优先级,主节点的优先级需要设置比备份节点高
    priority 100 
    
    # 设置主备之间的检查时间,单位为秒 
    advert_int 1 
    
    # 如果两节点的上联交换机禁用了组播,则采用 vrrp 单播通告的方式
    unicast_src_ip 192.168.19.102
    unicast_peer {
        192.168.19.103
    }
    
    # 定义验证类型和密码
    authentication { 
        auth_type PASS
        auth_pass 000000
    }

    # 调用上面自定义的监控脚本
    track_script {
        chk_haproxy
    }

    virtual_ipaddress {
        # 虚拟IP地址,可以设置多个
        192.168.19.100  
    }
}

(3)BACKUP 节点配置

备份节点的配置与主节点基本相同,但是需要修改其 state 为 BACKUP;同时其优先级 priority 需要比主节点低。

vim /etc/keepalived/keepalived.conf
global_defs {
   # 路由id,主备节点不能相同    
   router_id node2  

   notification_email {
     # email 接收方
     acassen@firewall.loc
     failover@firewall.loc
     sysadmin@firewall.loc
   }
   
   # email 发送方
   notification_email_from Alexandre.Cassen@firewall.loc
   # 邮件服务器, smtp 协议
   smtp_server 192.168.200.1
   smtp_connect_timeout 30
   
   vrrp_skip_check_adv_addr
   # 使用 unicast_src_ip 需要注释 vrrp_strict,而且也可以进行 ping 测试
   #vrrp_strict 
   vrrp_garp_interval 0
   vrrp_gna_interval 0
}

vrrp_script chk_haproxy {
    script "/etc/keepalived/haproxy_check.sh" 
    interval 5 
    weight 10
}

vrrp_instance VI_1 {
    # BACKUP 表示备份节点
    state BACKUP 
    
    # 指定监测的网卡
    interface ens32
    
    # 虚拟路由的id,主备节点需要设置为相同
    virtual_router_id 51
    
    # 优先级,备份节点要比主节点低
    priority 50 
    
    # 设置主备之间的检查时间,单位为秒
    advert_int 1 
    
    # 如果两节点的上联交换机禁用了组播,则采用 vrrp 单播通告的方式
    unicast_src_ip 192.168.19.103
    unicast_peer {
        192.168.19.102
    }
    
    authentication { 
        auth_type PASS
        auth_pass 000000
    }
    
    track_script {
        chk_haproxy
    }

    virtual_ipaddress {
        192.168.19.100  
    }
}

注意以下几点

  • state 角色为 BACKUP
  • interface 为网卡的 ID,要根据机器确认
  • virtual_route_id 要与 MASTER 一致,默认为 51
  • priority 要比 MASTER 小
  • unicast_src_ip 要设置正确,组播地址设置之后,要注释 vrrp_strict 选项

4)配置 HAProxy 检查

以上配置定义了 Keepalived 的 MASTER 节点和 BACKUP 节点,并设置对外提供服务的虚拟 IP 为 192.168.19.100。此外最主要的是定义了通过 haproxy_check.sh 来对 HAProxy 进行监控,这个脚本需要我们自行创建,内容如下:

vim /etc/keepalived/haproxy_check.sh
#!/bin/bash

# 判断haproxy是否已经启动
if [ ${ps -C haproxy --no-header |wc -l} -eq 0 ] ; then
    #如果没有启动,则启动
    haproxy -f /etc/haproxy/haproxy.cfg
fi

#睡眠3秒以便haproxy完全启动
sleep 3

#如果haproxy还是没有启动,此时需要将本机的keepalived服务停掉,以便让VIP自动漂移到另外一台haproxy
if [ ${ps -C haproxy --no-header |wc -l} -eq 0 ] ; then
    systemctl stop keepalived
fi

创建后为其赋予执行权限

chmod +x /etc/keepalived/haproxy_check.sh

这个脚本主要用于判断 HAProxy 服务是否正常,如果不正常且无法启动,此时就需要将本机 Keepalived 关闭,从而让虚拟 IP 漂移到备份节点。

5)配置并启动服务

配置 IP 转发,需要修改配置文件 /etc/sysctl.conf,默认只有 root 可以修改,分别在 MASTER 和 BACKUP上修改。

# 切换用户
su -root
# 文件配置
echo "net.ipv4.ip_nonlocal_bind = 1" >> /etc/sysctl.conf
# 生效
sysctl -p

node1 和 node2 上启动 KeepAlived 服务,命令如下:

systemctl start keepalived

设置开机自动启

systemctl enable keepalived

在这里插入图片描述

启动后此时 node1 为主节点,可以在 node1 上使用 ip a 命令查看到虚拟 IP 的情况:

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

漂移规则如下:

  • 默认使用 MASTER 服务器(192.168.19.102),虚拟 IP 为 192.168.19.100,此时 MASTER 服务器会有 2 个IP。
  • 当 MASTER 出问题时,IP 会漂移到 BACKUP 服务器(192.168.19.103),此时 BACKUP 服务器会有 2 个IP。
  • 当 MASTER 重新启动后,虚拟 IP 又会漂移回 MASTER 服务器。

6)验证故障转移

这里我们验证一下故障转移,因为按照我们上面的检测脚本,如果 HAProxy 已经停止且无法重启时 KeepAlived 服务就会停止,这里我们直接使用以下工具进行验证。

安装 tcpdump 包

yum -y install tcpdump
  • 在 MASTER 服务器上执行
tcpdump -i ens32 vrrp -n

在这里插入图片描述

这表明 MASTER 在向 BACKUP 广播,MASTER 在线。此时虚拟 IP 是挂在 MASTER 上的,如果想退出, 按 Ctrl+C

  • 如果 MASTER 停止 keepalived,虚拟 IP 会漂移到 BACKUP 服务器上
# 停止 MASTER 的 keepalived
systemctl stop keepalived
  • 再次在 MASTER 服务器上查看 VRRP 服务

在这里插入图片描述

这表明 MASTER 收到 BACKUP 的广播,此时虚拟 IP 是挂在 BACKUP 服务器上。

  • 使用 ip a 分别查看

在这里插入图片描述
在这里插入图片描述

  • 再次重启 MASTER 服务器,会发现 VIP 又重新漂移回 MASTER 服务器

在这里插入图片描述

7)消息发送接收测试

  • 正常情况:所有服务都运行

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

  • 只保留一个节点,停掉其它两个节点

    因为node1、node2上安装有 HAProxyKeepalived,至少保留一个

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

8)配置日志

注意:此配置为可选步骤

keepalived 默认将日志输出到系统日志/var/log/messages中,因为系统日志很多,查询问题时相对麻烦。

我们可以将 keepalived 的日志单独拿出来,这需要修改日志输出路径。

  • 修改 Keepalived 配置
vim /etc/sysconfig/keepalived

更改如下:

# Options for keepalived. See `keepalived --help' output and keepalived(8) and
# keepalived.conf(5) man pages for a list of all options. Here are the most
# common ones :
#
# --vrrp               -P    Only run with VRRP subsystem.
# --check              -C    Only run with Health-checker subsystem.
# --dont-release-vrrp  -V    Dont remove VRRP VIPs & VROUTEs on daemon stop.
# --dont-release-ipvs  -I    Dont remove IPVS topology on daemon stop.
# --dump-conf          -d    Dump the configuration data.
# --log-detail         -D    Detailed log messages.
# --log-facility       -S    0-7 Set local syslog facility (default=LOG_DAEMON)
#

KEEPALIVED_OPTIONS="-D -d -S 0"

把 KEEPALIVED_OPTIONS=”-D” 修改为 KEEPALIVED_OPTIONS=”-D -d -S 0”,其中 -S 指定 syslog 的 facility

  • 修改 /etc/rsyslog.conf ,末尾添加
vim /etc/rsyslog.conf 

local0.*  /var/log/keepalived.log
  • 重启日志记录服务
systemctl restart rsyslog
  • 重启 keepalived
systemctl restart keepalived

此时,可以从 /var/log/keepalived.log 查看日志了。

参考自:

  • https://blog.csdn.net/qq_28533563/article/details/107932737
  • https://www.bilibili.com/video/BV1cb4y1o7zz
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

土味儿~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值