Ray 单机部署&多机部署&docker部署

测试任务选定

本次选择的测试任务为转移概率矩阵的近似极限分布。

性能指标列表

  • 吞吐量(Throughput):指系统在单位时间内能够处理的请求或者任务数量,通常用每秒处理请求数(Requests per Second,RPS)或者每秒完成任务数(Tasks per Second,TPS)来衡量。

  • 延迟(Latency):指系统处理请求或者任务所需的时间,通常用平均响应时间(Average Response Time)或者百分位响应时间(Percentile Response Time)来衡量。

  • 资源利用率(Resource Utilization):指系统在运行过程中所使用的资源占总资源的比例,例如 CPU 使用率、内存使用率等。

  • 可靠性(Reliability):指系统在长时间运行中的稳定性和可靠性,通常用错误率(Error Rate)或者故障率(Failure Rate)来衡量。

  • 扩展性(Scalability):指系统在处理更多请求或者任务时的能力,通常用负载测试(Load Testing)或者压力测试(Stress Testing)来衡量。

我们选用任务延迟和吞吐量作为主要的关注点。

单机版部署及性能测试

1、Ray的安装
1、安装python:
sudo apt-get install python
2、安装pip:
curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
sudo python3 get-pip.py
3、更新:
sudo apt update
4、安装ray:
pip install -U ray
pip install 'ray[default]'
2、测试过程
1、创建head结点

使用命令:

ray start --head

创建节点

2、运行测试程序

例如测试程序命名为test.py且位于当前工作目录下,则运行如下命令来启动运行程序:

python test.py
3、查看结果

运行创建节点命令之后,会出现如下内容:

To monitor and debug Ray, view the dashboard at 
    127.0.0.1:8265

在浏览器中输入该ip地址,即可打开Dashboard查看运行结果

4、退出

输入命令:

ray stop

退出程序

3、用python编写的ray部署测试代码(markov_new.py)
import ray
import time
import sys
import numpy as np
​
ray.init()
​
matrix_size: int = 10    # 10 * 10 matrix
matrix_mul_times: int = 10000000
if len(sys.argv) < 1:
    pc_num: int = 10    # default value = 10
else:
    pc_num: int = int(sys.argv[1])
node_task_num: int = matrix_mul_times // pc_num
​
​
def matrix_mul(matrix1, matrix2):
    return np.matmul(matrix1, matrix2)
​
​
@ray.remote
class Worker(object):
    def __init__(self):
        self.size = matrix_size
        self.matrix0 = self.matrix_init2()
        self.res = self.matrix0.copy()
        self.all_times = matrix_mul_times
​
    def matrix_init2(self):
        # 每行均为正数浮点随机数,单行和为1(归一化)
        matrix = np.random.random((matrix_size, matrix_size))
        for row in range(self.size):
            total = sum(matrix[row])
            for item in matrix[row]:
                item /= total
        # print("Now we have a matrix\n", matrix)
        return matrix
​
    # 转移矩阵的极限分布
    # 计算若干个矩阵的相乘
    def calculate(self, times):
        # print("I start doing my work.")
        cur_time = time.time()
        task_res = self.matrix0.copy()
        for k in range(times-1):
            task_res = matrix_mul(self.res, self.matrix0)
        # print("I have finished my work, duration: ", time.time() - cur_time)
        return task_res
​
​
if __name__ == '__main__':
    cur_time=time.time()
    worker = Worker.remote()
    temps=[]
    for i in range(pc_num):
        temp = worker.calculate.remote(node_task_num)
        temps.append(temp)
​
    result_list = ray.get(temps)
​
    result = result_list[0]
    for m in result_list:
        result = matrix_mul(result, m)
    # print("final matrix: \n", result)
    print("total duration: ", time.time() - cur_time)
4、初步测试(使用不含ray的同规格任务测试)

文件:no_ray.py

单机参数

USTC vlab虚拟机的标准配置。

运行结果

5、Ray单机版分析、测试、优化
单机参数

(实体机linux ubuntu22.04)

(ray) tern@ubuntu:~/Documents/codes/python-codes/trial$ cat /proc/version
Linux version 5.19.0-43-generic (buildd@lcy02-amd64-028) (x86_64-linux-gnu-gcc (Ubuntu 11.3.0-1ubuntu1~22.04.1) 11.3.0, GNU ld (GNU Binutils for Ubuntu) 2.38) #44~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Mon May 22 13:39:36 UTC 2
​
(ray) tern@ubuntu:~/Documents/codes/python-codes/trial$ cat /proc/cpuinfo | grep "cpu cores" | uniq
cpu cores   : 14

部署与运行过程(精简)

程序参数

matrix_size: int = 10    # 10 * 10 matrix
matrix_mul_times: int = 10000000
if len(sys.argv) < 1:
    pc_num: int = 10    # default value = 10
else:
    pc_num: int = int(sys.argv[1])

部署与运行(simplified,详见rec.md)

tern@ubuntu:~/Documents/codes/python-codes/trial$ conda init bash
modified      /home/tern/.bashrc
​
tern@ubuntu:~/Documents/codes/python-codes/trial$ source ~/.bashrc
(base) tern@ubuntu:~/Documents/codes/python-codes/trial$ conda activate ray
(ray) tern@ubuntu:~/Documents/codes/python-codes/trial$ ray start --head
    
(ray) tern@ubuntu:~/Documents/codes/python-codes/trial$ python markov_new.py 100000
2023-06-20 11:29:11,978 INFO worker.py:1342 -- Connecting to existing Ray cluster at address: 114.214.252.223:6379...
total duration:  27.68019461631775
​
(ray) tern@ubuntu:~/Documents/codes/python-codes/trial$ python markov_new.py 10000
2023-06-20 11:29:56,011 INFO worker.py:1342 -- Connecting to existing Ray cluster at address: 114.214.252.223:6379...
total duration:  11.307637929916382
​
(ray) tern@ubuntu:~/Documents/codes/python-codes/trial$ python markov_new.py 10
2023-06-20 11:30:27,501 INFO worker.py:1342 -- Connecting to existing Ray cluster at address: 114.214.252.223:6379...
total duration:  9.69461703300476
​
(ray) tern@ubuntu:~/Documents/codes/python-codes/trial$ python markov_new.py 1
2023-06-20 11:30:51,152 INFO worker.py:1342 -- Connecting to existing Ray cluster at address: 114.214.252.223:6379...
total duration:  9.28380298614502

Dashboard

性能改进与提升

延迟测试:

  1. 总吞吐量30000000(执行30000000次矩阵乘法):

任务分配数10000010000101
测试时间46.2630.7128.0826.96

(下一参数对应运行内容即上面的文本内容,记录在rec.md中)

  1. 总吞吐量10000000:

任务分配数10000010000101
测试时间27.6811.319.709.28

  1. 总吞吐量500000:

任务分配数10000010000101
测试时间17.962.410.750.70

可见任务数增大时,时间开销大量增大。这是由于进程间通讯耗费了大量的时间。

对于第二种情况,即任务数为10000000时,最初任务拆分数为100000,运行效果很差,后来将只任务切分为10份,性能优化了185%以上。

同样的,对于第一种情况,即任务总数增加到30000000时,任务拆分数10相对于任务拆分数100000性能提高了65%

而当任务总数降低到500000时,性能的提升就更为显著,主要是由于此时在拆分数100000的情形下每一个任务实际上只进行了五次矩阵乘法,而在合并运算结果时要进行100000次运算,因此并行性能极差,所以任务拆分数减少时性能的提升极为显著(超过五倍)。

关于吞吐量:

在固定任务拆分数为1时,

第一种情形下即任务总数为30000000时,吞吐率为1112759次运算/秒。

第二种情形下即任务总数为10000000时,吞吐率为1077586次运算/秒。

第三种情形下即任务总数为500000时,吞吐率为714286次运算/秒。

在固定任务拆分数为10时,

第一种情形下即任务总数为30000000时,吞吐率为1068376次运算/秒。

第二种情形下即任务总数为10000000时,吞吐率为1030928次运算/秒。

第三种情形下即任务总数为500000时,吞吐率为666667次运算/秒。

在固定任务拆分数为10000时,

第一种情形下即任务总数为30000000时,吞吐率为976880次运算/秒。

第二种情形下即任务总数为10000000时,吞吐率为884173次运算/秒。

第三种情形下即任务总数为500000时,吞吐率为207469次运算/秒。

在固定任务拆分数为100000时,

第一种情形下即任务总数为30000000时,吞吐率为648508次运算/秒。

第二种情形下即任务总数为10000000时,吞吐率为361272次运算/秒。

第三种情形下即任务总数为500000时,吞吐率为27840次运算/秒。

吞吐量随着任务数增多而增加,这一点可能是由于测试中的延迟时间包括合并任务时间,而这一处理是串行的,不可以并行执行,所以导致相对来说任务总数比较多时花费在合并上的时间较少,故而吞吐量较大。因而当拆分数较少时第一和第二种情形下的吞吐量十分相近。(这里在测第三种情形时因为出现了溢出的问题,所以对部分乘法加了一步归一化,导致单次运算执行时间变长了一些,;吞吐量有相应减少)

另外,在单机上,明显在任务拆分数较少的时候吞吐量表现较好,但当拆分数降到1000以下时差距已经很小,因为此时花费在合并任务上的时间已经相对较少,对吞吐量影响很小。

分布式部署及性能测试(基于docker)

这里使用了4台运行Ubuntu的虚拟机服务器(实际上就是vlab),由于处于同一局域网下,连接比较方便。 1台作为头结点和客户端,其余3台作为工作节点。

1、准备结点:头节点和工作节点
1、安装OpenSSH Server (Linux Ubuntu)

输入如下命令在ubuntu上安装和配置OpenSSH Server:

sudo apt update
sudo apt install openssh-server

以下命令用于查看是否安装成功:

sudo systemctl status ssh

(正确安装可以看到active)

使用防火墙(即 ufw)打开 SSH 22/TCP 端口

sudo systemctl status ssh

检查端口22是否正确打开

sudo ufw status

(正确打开可以看到ALLOW)

2、安装和配置Docker(Linux Ubuntu)

安装Docker

sudo apt update
sudo apt install docker.io

将用户添加到docker组

sudo usermod -aG docker $USER

验证Docker安装

docker --version

(正确安装后可以看到Docker的版本)

拉取并运行"hello-world"docker镜像以验证docker可以正常运行

docker run hello-world
2、准备客户端工作站
1、安装Docker

由于结点使用相同的docker镜像可以更好的使用Ray进行工作,因此最好在客户机上也安装Docker。

安装Docker软件:

sudo apt update
sudo apt install docker.io

将用户添加到docker群组

sudo usermod -aG docker $USER

验证Docker的安装

docker --version

(正确安装可以看到Docker的版本)

2、运行Ray Docker镜像

拉取Ray docker镜像:

docker pull rayproject/ray-ml:latest-cpu

这里没有使用支持GPU的镜像,因为这些虚拟机都没有GPU,如果你的服务器支持GPU,你可以改用rayproject/ray-ml:latest-gpu

运行Ray docker容器:

docker run -i -t rayproject/ray-ml

在docker容器中,我们需要获取python和ray的版本,这样让客户端使用同样的版本才能正常运行。 获取python版本:

python --version

获取Ray python包版本:

首先输入如下命令进入python 解释器:

python

然后在python解释器中键入以下python脚本:

import ray
print(ray.__version__)

此时输出ray的版本,然后退出python解释器,输入命令:

quit()

最后退出docker容器:

exit
3、设置SSH客户端

要部署 Ray 集群,需要使用 ssh-keygen 为 SSH 创建新的身份验证密钥对,以自动登录、单点登录和验证主机。创建密钥后,需要使用 ssh-copy-id 将公钥复制到 Ray 集群中的每个节点。

为SSH创建新的身份验证密钥对:

ssh-keygen

使用ssh-copy-id将公钥复制到每个节点。以一个头结点和三个工作节点为例,命令如下:

示例:

ssh-copy-id -i ~ /.ssh/i d_rsa. pub ssh_user@172.31.223.167
ssh-copy-id -i ~ /.ssh/i d_rsa. pub ssh_user@172.31.176.122
ssh-copy-id -i ~ /.ssh/i d_rsa. pub ssh_user@172.31.132.69
ssh-copy-id -i ~ /.ssh/i d_rsa. pub ssh_user@172.31.218.156

其中ssh_user是之后用SSH连接到这些节点时将会使用的用户名。请注意对工作节点和头结点使用的用户名都是相同的,你需要手动创建这些用户。每条命令的最后需要使用工作节点的实际IP地址。可以使用hostname -I来查看本机的IP。

4、安装和配置Miniconda

这里将安装和配置Miniconda,这样客户端就能方便地使用与节点的docker镜像中相同的Python版本和ray版本。

Miniconda下载地址:Miniconda下载

安装Miniconda:

bash ~/Downloads/Miniconda3-py310_22.11.1-1-Linux-x86_64.sh

安装完成之后,需要为Ray创建一个conda环境:

conda create --name ray python=3.7.13

接下来激活"Ray"环境:

conda activate ray

安装Ray python包:

pip install "ray[default]"==2.1.0
3、使用Ray Up部署Ray集群
1、下载YAML文件
wget https://raw.githubusercontent.com/ray-project/ray/master/python/ray/autoscaler/local/example-full.yaml _ _ _
2、修改并重命名example-full.yaml文件

修改YAML文件的以下部分(以红色表示):

provider:
    type: local
    head_ip: YOUR_HEAD_NODE_HOSTNAME
    # You may need to supply a public ip for the head node if you need
    # to run `ray up` from outside of the Ray cluster's network
    # (e.g. the cluster is in an AWS VPC and you're starting ray from your laptop)
    # This is useful when debugging the local node provider with cloud VMs.
    # external_head_ip: YOUR_HEAD_PUBLIC_IP
    worker_ips: [WORKER_NODE_1_HOSTNAME, WORKER_NODE_2_HOSTNAME, ... ]
    # Optional when running automatic cluster management on prem. If you use a coordinator server,
    # then you can launch multiple autoscaling clusters on the same set of machines, and the coordinator
    # will assign individual nodes to clusters as needed.
    #    coordinator_address: "<host>:<port>"
  • head_ip:将成为头节点的计算机的 IP 地址(例如,172.31.223.167)。

  • worker_ips:将成为工作节点的计算机的 IP 地址(例如,[172.31.176.122,172.31.132.69,172.31.218.156])。

修改YAML文件的以下部分(以红色表示):

# How Ray will authenticate with newly launched nodes.
auth:
    ssh_user: YOUR_USERNAME
    # You can comment out `ssh_private_key` if the following machines don't need a private key for SSH access to the Ray
    # cluster:
    #   (1) The machine on which `ray up` is executed.
    #   (2) The head node of the Ray cluster.
    #
    # The machine that runs ray up executes SSH commands to set up the Ray head node. The Ray head node subsequently
    # executes SSH commands to set up the Ray worker nodes. When you run ray up, ssh credentials sitting on the ray up
    # machine are copied to the head node -- internally, the ssh key is added to the list of file mounts to rsync to head node.
    # ssh_private_key: ~/.ssh/id_rsa
  • ssh_user:将用于登录头节点计算机和工作节点计算机的用户名(例如,ray_client)。

修改YAML文件的以下部分(以红色表示):

# The minimum number of workers nodes to launch in addition to the head
# node. This number should be >= 0.
# Typically, min_workers == max_workers == len(worker_ips).
# This field is optional.
min_workers: TYPICALLY_THE_NUMBER_OF_WORKER_IPS
​
# The maximum number of workers nodes to launch in addition to the head node.
# This takes precedence over min_workers.
# Typically, min_workers == max_workers == len(worker_ips).
# This field is optional.
max_workers: TYPICALLY_THE_NUMBER_OF_WORKER_IPS
# The default behavior for manually managed clusters is
# min_workers == max_workers == len(worker_ips),
# meaning that Ray is started on all available nodes of the cluster.
# For automatically managed clusters, max_workers is required and min_workers defaults to 0.
  • min_workers:worker_ips中IP地址的个数或3个。

  • max_workers:worker_ips中IP地址的个数或3个。

保存更改并将文件重命名为“default-full.yaml”,因为集群名称是“default”。

3、激活Ray Conda环境

运行以下命令以激活conda环境:

conda activate ray
4、运行"ray up"

最后使用如下命令来部署Ray集群:

ray up default-full.yaml

使用如下命令来检查Ray集群的状态:

ray exec default-full.yaml 'ray status'

使用如下命令启动dashboard:

ray dashboard default-full.yaml

在浏览器中输入以下地址以打开Ray Dashboard

http://127.0.0.1:8265

运行一个microbenchmark来确保Ray集群按预期的工作:

ray exec default-full.yaml 'ray microbenchmark'
4、向ray集群提交任务

为了方便编程,建议将VScode连接到本地的docker容器“rayproject/ray-ml”,这样你就可以看到该容器中安装的所有的包。

假设你写好的python文件叫做my_script.py,那么可以使用如下命令将它提交到ray集群并运行:

RAY_ADDRESS='http://127.0.0.1:8265' ray job submit --working-dir . -- python my_script.py

需要确保my_script.py在当前工作目录下。

这里进行测试时使用的命令如下:

Desktop目录下
​
RAY_ADDRESS='http://127.0.0.1:8265' ray job submit --working-dir . -- python markov.py 1000 10000
​
RAY_ADDRESS='http://127.0.0.1:8265' ray job submit --working-dir . -- python markov.py 100 10000
​
RAY_ADDRESS='http://127.0.0.1:8265' ray job submit --working-dir . -- python markov.py 10 10000
​
RAY_ADDRESS='http://127.0.0.1:8265' ray job submit --working-dir . -- python markov.py 1 10000

注意这里由于vlab虚拟机硬件资源的限制,没有办法做到和其他情形下的运算规模相同的地步,事实上,在规模达到10000000时就必然会报出内存不足的错误而后自动终止程序。所以这里只能够使用很小的参数。

另外,由于虚拟机似乎不能够很好的支持dashboard,所以经过多次失败后最终是使用命令行界面进行部署的,也尝试了ssh终端登陆多开,在运行时用命令查看状态,不过还是达不到dashboard的效果。所以最终我们只选用任务规模、拆分数、运行时间(程序输出)作为主要关注对象。

使用ray down来关闭Ray集群:

ray down default-full.yaml

需要注意的是,关闭了Ray集群并没有关闭Ray容器,需要手动关闭Ray容器。

Ray docker部署的运行结果(命令如上)

Summary

total: 10000

pc_num1000100101
time(s)4.482.562.612.36

这里的分布趋势仍然与此前的解释相符。

5、分布式部署的性能测试

多机配置

三台虚拟机,USTC Vlab的标准配置。

Dashboard

6、分布式部署的性能分析、优化

初始pc_num=100000,单位秒(s),pc_num为任务拆分数

任务分配数:pc_numpc_num=100000pc_num=100pc_num = 30pc_num=12
无Ray45.20691394805908(+/-2s)
单机版ray185.8933646678924645.634271621704148.5124063491821346.83416128158569
多机ray集群(3个结点)171.6869783401489350.9740636348724443.5671117305755649.56426119804382

任务规模在100000时,多机部署相对于单机部署有百分之十五的性能提升。

这里单机版我们得到了与此前在另一台计算机上运行相似的结果,单机调参优化最高达到307%

多机版本不同的是,在任务柴分数进一步减小,从30减少到12时性能出现了百分之四十的回降,这是由于计算资源没有得到充分利用,这一点抵消了进程间通讯的开销。可以想见,如果任务规模大幅扩大,则多机的性能会较大幅度的优于单机。多机调参优化最高达到294%

&lt;think&gt;好的,我现在需要帮助用户寻找关于大模型管理平台的实现方案或工具推荐。首先,用户之前的问题是关于大模型管理平台的信息或解决方案,所以我要围绕这个主题展开。根据用户提供的系统级指令,我需要确保回答结构清晰,使用正确的中文,并生成相关问题。同时,还要参考给定的引用内容,但要注意用户提到这些引用仅供参考,可能需要结合之前的对话。 首先,我需要确定大模型管理平台的关键组成部分。根据引用[1]中提到的插件服务,平台需要支持自定义插件,比如训练、推理和优化插件,这些能帮助用户扩展和定制服务。另外,引用[2]讨论了预训练大模型(PTM)的数学基础和性能提升工具,这可能涉及到模型训练和优化的工具。引用[3]提到了智能体架构,这可能与平台的架构设计有关。 接下来,我应该列举几个主流的平台或工具。例如,文心千帆、Hugging Face的Transformers、Microsoft的DeepSpeed、NVIDIA的NeMo、Meta的PyTorch Ecosystem,以及开源项目如Colossal-AI。这些工具各有特点,需要分别说明它们的核心功能和适用场景。 然后,我需要考虑实现方案的关键要素。比如模态支持、分布式训练、模型压缩、安全合规,这些方面都是大模型管理中的重要部分。每个要素需要简要解释,并可能引用相关内容。例如,模型压缩可以结合引用[2]中的提升性能的工具,如Prompt Engineering、Fine-tuning和RAG。 工具推荐部分需要详细描述每个工具的特点,特别是文心千帆,因为引用[1]专门提到了它的插件服务,应该强调这一点。其他工具如DeepSpeed的ZeRO优化和NeMo的语言支持也是重点。 最后,生成相关问题需要考虑用户可能的后续疑问,比如选型对比、开源方案、部署挑战和安全性问题。这些问题应该与之前的回答内容相关,帮助用户深入探索。 需要检查是否符合所有格式要求:行内公式用$...$,独立公式用$$...$$,但当前内容中没有数学公式,可能不需要。确保中文回答,结构清晰,分点说明。同时,引用标记要正确添加,例如在提到文心千帆时引用[^1],智能体架构引用[^3],模型优化工具引用[^2]。 现在组织内容,确保每个部分自然衔接,引用标记恰当,并且生成的相关问题有针对性。&lt;/think&gt;### 大模型管理平台实现方案与工具推荐 #### 一、核心实现方案 1. **平台架构设计** 典型的大模型管理平台需包含以下模块: - **模型训练与调优**:支持分布式训练框架(如PyTorch、TensorFlow),集成ZeRO优化、混合精度训练等技术 - **模型部署服务**:提供容器化部署Docker/K8s)、API网关、负载均衡和自动扩缩容 - **监控运维系统**:实时监控$GPU$利用率、推理延迟$T_{latency}$、请求成功率等关键指标 - **插件扩展制**:如引用[^1]所述,支持自定义训练/推理插件,例如: $$ \text{插件功能} = f(\text{数据预处理}, \text{模型压缩}, \text{服务编排}) $$ 2. **关键技术要素** - **模态支持**:融合文本、图像、语音的统一处理框架(参考智能体架构[^3]) - **模型压缩技术**:量化(8-bit/4-bit)、知识蒸馏、剪枝,解决大模型$M_{params}&gt;10^{9}$的部署难题 - **安全合规制**:数据脱敏、模型水印、伦理审查,满足$\text{GDPR}$等法规要求 #### 二、主流工具推荐 1. **文心千帆(Baidu)** - 核心优势:完整的插件生态(引用[^1]),提供预训练模型库+可视化调试工具 - 适用场景:企业级私有化部署,支持国产化芯片适配 2. **Hugging Face Model Hub** - 特点:开源社区驱动,集成$2.5\text{w}$+预训练模型 - 扩展性:支持$\text{Transformers}$库+自定义$\text{Pipeline}$ 3. **NVIDIA NeMo** - 技术亮点: $$ \text{训练效率} = \frac{\text{GPU吞吐量}}{\text{显存占用}} \times \text{Megatron-LM优化} $$ - 专长领域:语音/语言大模型开发 4. **DeepSpeed(Microsoft)** - 创新技术: - ZeRO-Offload(CPU+GPU混合训练) - 3D并行(数据/模型/流水线并行) - 实验数据:可训练$10^{12}$参数模型[^2] 5. **开源方案对比** | 工具名称 | 分布式训练 | 量化支持 | 服务部署 | |---------|------------|---------|----------| | Colossal-AI | 3D并行 | LoRA | Triton推理 | | FastAPI+Ray | 数据并行 | ONNX | K8s集群 | #### 三、实施路径建议 ```mermaid graph TD A[需求分析] --&gt; B(训练需求/推理需求/合规需求) B --&gt; C{模型规模选择} C --&gt;|参数量&lt;10B| D[单机卡方案] C --&gt;|参数量&gt;100B| E[节点集群] E --&gt; F[选择并行策略] F --&gt; G[评估工具链兼容性] G --&gt; H[开发定制插件] ```
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值