RocketMQ 的用法,你懂吗?

RocketMQ 消息消费流程 该文所涉及的 RocketMQ 源码版本为 4.9.3。拉取消息 成功之后 会调用 org.apache.rocketmq.client.impl.consumer.ConsumeMessageConcurrentlyService#submitConsumeRequest 组装 消费消息 请求获取 consumeMessageBatchMaxSize,表示一个 ConsumeRequest 包含的消息 数量,默认为 1入参 msgs 为拉取消息的最大值,默认为 32如果 msgs 小于等于 consume 阅读详情

消息中间件是我们工作中使用最频繁的一类中间件,它具有低耦合、可靠投递、广播、流量控制、最终一致性等一系列功能,成为异步RPC的主要手段之一。当今市面上有很多主流的消息中间件,如老牌的ActiveMQ、RabbitMQ,炙手可热的Kafka,阿里巴巴自主开发RocketMQ等。今天,指北君就来详细讲讲RocketMQ生产者和消费者在使用时的一些注意事项。

一. 生产者

1.1 发送消息注意事项

1)消息大小

建议消息大小不要超过512K。

2)异步发送

默认的发送为同步发送,send方法会一直阻塞,等待broker端的响应。如果你关注性能问题,可以通过send(msg, callback)来发起异步调用。

3)生产者组

正常情况下生产者组是没有作用的,但是在发送事务消息时,如果producer中途意外宕机,broker会主动回调producer group 内地任意一台机器来确认事务的状态。(目前开源版本还不支持事务消息)。

4)线程安全问题

生产者实例是线程安全的,在应用中只需要实例化一次即可。

5)性能问题

如果你希望在一个jvm进程内使用多个producer实例来提高发送能,我们建议:

使用异步发送,并且producer实例只需要3 ~ 5个即可 对每一个producer 调用 setInstanceName,区别不同的生产者。

6)发送超时时间

当客户端向broker发送请求超时时,客户端会抛出 RemotingTimeoutException,默认的超时时间是3秒。通过调用send(msg, timeout) 可以设置超时时间。超时时间建议不要设置过小,因为 broker 可能需要时间刷盘或向 slave 同步数据。

7)对于同一个应用最好只使用一个Topic,消息的子类型可以使用 tags 来标识,tags 可以应用自由设置。当发送的消息设置了 tags 时,消费方在订阅消息时可以使用 tags 在 broker 做消息过滤。注意这里的命名虽然是复数,但是一条消息只能有一个tag。

8)消息在业务层面的唯一标识可以设置到 keys 字段,方便根据 keys 来定位消息。broker 会为每个消息创建索引(哈希索引),应用可以通过topic 、key 查询这条消息的内容(MessageExt),以及消息被谁消费(MessageTrack,精确到consumer group)。由于是哈希索引,请尽量保证key 唯一,这样可以避免潜在的冲突。

9)消息发送不管是成功还是失败都要打印消息日志,日志内容务必包含 sendResult 和 key 字段。

10)对于消息不可丢失的应用,务必要有消息重发机制。例如如果消息发送失败,可以将消息存储到数据库,然后通过定时程序或者人工的方式触发重发。

11)调用send 同步发送消息时,假定此时设置了 isWaitStoreMsgOK=true(default is true),只要不抛出异常就代表发送成功,但当 isWaitStoreMsgOK = false 时,发送永远返回 SEND_OK。但是对于发送“成功”会有多个状态,在 SendStatus 中定义如下:

FLUSH_DISK_TIMEOUT

如果 broker 设置的 FlushDiskType = SYNC_FLUSH,当 broker 的在刷盘超时时(
MessageStoreConfig.syncFlushTimeout,默认5秒)会返回该状态。此时消息仍然保存在内存中,只有broker 宕机时消息才会丢失。

FLUSH_SLAVE_TIMEOU

如果 broker 的 role 是 SYNC_MASTER,当 slave 同步数据的时间超过了
MessageStoreConfig.syncFlushTimeout (默认5秒) 时会返回此状态。此时只有主从都宕机,并且主也没有刷盘时,消息才会丢失。

SLAVE_NOT_AVAILABLE

如果 broker 的 role 是 SYNC_MASTER,并且此时 slave 不可用时会返回该状态。

SEND_OK

发送成功。为了保证消息不丢失还需要配置 SYNC_MASTER or SYNC_FLUSH。

12)消息重复

当发送消息时返回
FLUSH_DISK_TIMEOUT/FLUSH_SLAVE_TIMEOUT,若非常不幸的 broker 也宕机了,消息将会丢失。此时如果什么都不做,消息可能会丢失,如果重发消息,消息可能会出现重复。

通常我们建议发送端重发消息,由消费方来保证消息消费的幂等性。

1.2 消息发送失败如何处理

Producer 的 send 方法本身支持内部重试,重试逻辑如下:

至多重试3次 如果发送失败,则轮转到下一个broker 这个方法的总耗时时间不超过 sendMsgTimeout,默认3秒 所以发送消息已经产生超时异常的话就不会再重试。以上策略仍不能保证消息发送一定成功,为保证消息发送一定成功,建议应用这么做:如果调用 send 同步发送失败,则尝试将消息存储到db,由后台线程定时重试,保证消息一定到达 Broker。

1.3 oneway 的发送形式

对于可靠性要求不高的应用,可以采用 oneway 的发送形式,oneway 形式不等待应答。

1.4 发送顺序消息

顺序消息分为分区有序和全局有序。

分区有序要求 producer 在send 时传入 MessageQueueSelector 的实现类,最终将某一类消息发送到同一队列。但是一旦发生通信异常、broker 重启等,由于队列总数发生变化,哈希取模后定位的队列会变化,会产生短暂的顺序不一致。如果业务能容忍在集群异常情况下(如某个 broker 宕机或者重启)消息短暂的乱序,使用分区有序比较合适。

全局严格有序的消息即便在异常情况下也能保证消息的有序性,但是却牺牲了分布式的 failover 特性,即 broker 集群中只有要一台机器不可用,则整个集群都不可用,服务可用性会大大降低。

顺序消息的缺点:

发送顺序消息无法利用集群的 FailOver 特性 消费顺序消息的并行度依赖于队列数量 队列热点问题,个别队列由于哈希不均导致消息过多,消费速度跟不上,产生消费堆积问题 遇到消费失败的消息,无法跳过,当前队列需要暂停 5.发送事务消息 目前暂不支持。

二. 消费者

2.1 消费者组和订阅

不同的消费者组可以独立消费相同的topic,这点类似于ActiveMQ的虚拟 topic. 另外对于相同的消费者组,需要确保组内的消费者订阅消息的规则是一致的!

MQ 里的一个Consumer Group 代表一个 Consumer 实例群组。对于大多数分布式应用来说,一个 Consumer Group 下通常会挂载多个 Consumer 实例。订阅关系一致指的是同一个 Consumer Group 下所有 Consumer 实例的处理逻辑必须完全一致。一旦订阅关系不一致,消息消费的逻辑就会混乱,甚至导致消息丢失。

由于 MQ 的订阅关系主要由 Topic+Tag 共同组成,因此,保持订阅关系一致意味着同一个 Consumer Group 下所有的实例需在以下两方面均保持一致:

订阅的 Topic 必须一致;订阅的 Topic 中的 Tag 必须一致。

技术架构 > Consumer 最佳实践 > image2017-11-15 15:50:13.png

2.2 MessageListener

1)顺序消费 MessageListenerOrderly

顺序消费时消费者会锁定队列,以确保消息被顺序消费,但是这样也会造成一定的性能损耗。当消费出现异常的时候,建议不要抛出异常,而是返回
ConsumeOrderlyStatus.SUSPEND_CURRENT_QUEUE_A_MOMENT,让消费暂停一会,暂停时间由 context.setSuspendCurrentQueueTimeMillis 方法指定。

2)并发消费

并发消费是推荐的消费方式,在此种模式下,消息将被并发的消费。消费出现异常时不建议抛出异常,只需要返回
ConsumeConcurrentlyStatus.RECONSUME_LATER 即可。为了保证消息肯定被至少消费一次,消息将会被重发回 broker (topic不是原topic而是这个消费组的RETRY topic),在延迟的某个时间点(默认是10秒,业务可设置,通过 delayLevelWhenNextConsume 和 MessageStoreConfig.messageDelayLevel 设置)后,再次投递到这个 ConsumerGroup,而如果一直这样重复消费都持续失败到一定次数(默认是16次,DefaultMQPushConsumer.maxReconsumeTimes),就会投递到DLQ队列。应用可以监控死信队列来做人工干预。

3)返回状态

在并行消费时可以通过返回 RECONSUME_LATER 来告诉 Consumer 当前无法消费该消息,等延时一段时间再重新消费,但是此时消费不会停止,你可以继续消费其他消息。但在顺序消费时,因为要保证消费的顺序性,所以你不能跳过失败的消息,此时你可以通过返回
SUSPEND_CURRENT_QUEUE_A_MOMENT 来告诉 Consumer 先暂停一会。

4)阻塞

不建议阻塞Listener,因为这会阻塞住线程池,同时也有可能造成消费者线程终止。

2.3 线程数

consumer 内部通过一个 ThreadPoolExecutor 来消费消息,可以通过 setConsumeThreadMin 和 setConsumeThreadMax 来改变线程池的大小。

2.4 ConsumeFromWhere

当新实例启动的时候,PushConsumer会拿到本消费组broker已经记录好的消费进度(consumer offset),按照这个进度发起自己的第一次Pull请求。

如果这个消费进度在Broker并没有存储起来,证明这个是一个全新的消费组,这时候客户端有几个策略可以选择:

CONSUME_FROM_LAST_OFFSET //默认策略,从该队列最尾开始消费,即跳过历史消息。

CONSUME_FROM_FIRST_OFFSET //从队列最开始开始消费,即历史消息(还储存在broker的)全部消费一遍。

CONSUME_FROM_TIMESTAMP//从某个时间点开始消费,和setConsumeTimestamp()配合使用,默认是半个小时以前 注意:这些配置只对全新的消费组有效,老的消费组都是按已经存储过的消费进度继续消费。

对于老消费组想跳过历史消息可以采用以下几种方法:

1)判断消息的发送时间,太老的消息直接返回 CONSUME_SUCCESS。

2)判断消息的 offset 和 MAX_OFFSET 的差距,如果落后太多,可以直接。返回 CONSUME_SUCCESS。

3)消费者启动前,先调整该消费组的消费进度,再开始消费。可以人工使用命令 resetOffsetByTimeStamp,详见
ResetOffsetByTimeCommand.java。

2.5 消息幂等

由于 RocketMQ 无法避免消费重复,所以如果业务对消息重复非常敏感,务必在业务层面去重。

2.6 消费速度慢处理方式

1)提高消费并行度

大部分消息消费行为都属于 IO 密集型业务,适当的提高并发度可以显著的改善消费的吞吐量。

2)批量方式消费

默认情况下 consumer 的
consumeMessageBatchMaxSize 为1,即一次只消费一个消息,如果应用可以批量消费消息,则可以很大程度上提高消费吞吐量。

3)跳过非重要消息

当消堆积严重时可以丢弃不重要的消息。

4)优化消息消费过程

2.7 打印消费日志

建议在消费入口方法打印消息,方便后续排查问题,消费失败时也打印失败日志。

2.8 利用broker过滤消息,避免多余的消息传输

使用RocketMQ遇到过问题?细数RocketMQ的5个问题 大家好,我是小郭,之前分享一一些关于RocketMQ的源码文章,认识到RocketMQ里面真的非常丰富,在开发的过程中消息中间件已经成为我们常用的技术方案,但是他也给我们带来了很多麻烦。今天主要和大家分享一下在实际使用中遇到遇到的问题,以及如何是如何解决的。主要介绍了RocketMQ在使用中遇到的一些问题,从中认识到使用中间件的时候,需要特别注意它所带来的一些意想不到的影响,不低估每一个功能的实现,进而避免故障的产生。 阅读详情

相关推荐

RocketMQ(22) -- RocketMQ应用 -- 批量消费消息

RocketMQ应用 -- 批量消费消息

姜皓的博客 5579

RocketMQ设置的ConsumeThreadMax无效

问题 RocketMQ设置的ConsumeThreadMax无效,线程数只会达到ConsumeThreadMin值 回答 RocketMQ源码 RocketMQ的线程池是ThreadPoolExecutor,线程池的核心线程数等于mq设置的最小线程数,线程池的最大线程数等于mq设置的最大线程数。 即:ThreadPoolExecutor.corePoolSize == RocketMQ.consumeThreadMin ThreadPoolExecutor.maximumPoolSize.

懒人记录处 6490

Springboot整合Rocketmq系列教程

本教程是基于Springboot2.6.3整合Rocketmq5.0,其中涉及了Rocketmq的安装,消息的发送及消费的代码实现。本文不会对rocketmq的一些概念、原理,及注意事项进行讲解,因为官网已经写的很清楚,又有中文版,详细访问https://rocketmq.apache.org/zh/docs/quickStart/01quickstart。

gzmyh的博客 9111

rocketmq中ConsumeThreadMax不生效原因探究

所以很清晰知道默认队列就是this.consumeRequestQueue,也就是LinkedBlockingQueue,而LinkedBlockingQueue默认大小Integer.MAX_VALUE,所以队列一直没满,也就不会创建新线程。代码追踪:从DefaultMQPushConsumer入手,org.apache.rocketmq.client.consumer.DefaultMQPushConsumer#start方法启动消费者。rocket版本:rocketmq-client-4.9.3。

zzxzzxhao的博客 1349

RocketMQ

RocketMQ能够有效解决系统解耦、流量削峰、异步处理等问题,提高系统的可扩展性和稳定性。

weixin_51040479的博客 2093

Windows 下安装 RocketMQ

RocketMQ 安装内容一、 RocketMQ环境搭建1. 下载RocketMQ2. window的安装配置2.1 使用 rocketmq-4.5.1.zip 解压到指定目录2.2 需要配置环境变量 ROCKETMQ_HOME3. 修改broker的配置文件3.1 打开 broker.conf 文件3.2 添加配置4. 先启动 mqnamesrv5. 启动broker6. 启动管理控制台总结 内容 一、 RocketMQ环境搭建 1. 下载RocketMQ http://rocketmq.apac

zzvar的博客 9736

RocketMQ吐血总结

RocketMQ吐血总结 架构   概念模型 最基本的概念模型与扩展后段概念模型  存储模型   RocketMQ吐血总结 User Guide RocketMQ是一款分布式消息中间件,最初是由阿里巴巴消息中间件团队研发并大规模应用于生产系统,满足线上海量消息堆积的需求, 在2016年底捐赠给Apache开源基金会成为孵化项目,经过不到一年时间正式成为了A...

武汉红喜 15万+

RocketMQ 用法详解

消息中间件是我们工作中使用最频繁的一类中间件,它具有低耦合、可靠投递、广播、流量控制、最终一致性等一系列功能,成为异步RPC的主要手段之一。当今市面上有很多主流的消息中间件,如老牌的ActiveMQ、RabbitMQ,炙手可热的Kafka,阿里巴巴自主开发RocketMQ等。今天,指北君就来详细讲讲RocketMQ生产者和消费者在使用时的一些注意事项。...

20年码农 1261

RocketMq mqadmin 的用法详解

mqadmin是rocketmq自带的命令行管理工具,在bin目录下运行执行即可,比如你要使用查询某个topic下的路由信息: >sh mqadmin topicroute -t topicName { "brokerDatas":[ { "brokerAddrs":{0:"192.168.142.80:10911" }, "brokerName":"bogon"...

蜡笔小明的博客 5353

深度学习---双层神经网络中矩阵的运算及其含义记录

深度学习---双层神经网络中矩阵的运算及其含义记录神经网络的正向传播与反向传播正向传播第一层的权重矩阵第一层的输入矩阵Z^1^ = W^1^X^1^ + b^1^A^1^ = σ(Z^1^)第二层的权重矩阵第二层的输入矩阵Z^2^ = W^2^A^1^ + b^2^反向传播dz^2^ = A^2^ - Ydw^2^ = 1/n dz^2^A^1T^db^2^ = 1/n np.sum(dz^2...

qq_43228441的博客 3747

电力现货交易市场-报价方式

电是一种能源,也是一种商品,既然是商品自然可以在市场中进行自由交易。

qq_38225433的博客 5119

Windows下安装RocketMQ

这里并不打算深入讲解RocketMQ的架构和特性,因为我觉得,针对于初学者,太早地深入知识细节,会让人感到迷惘,学习起来吃力。namesrvAddrs地址就是服务的地址,192.168.10.100是我虚拟主机的ip,如果是window环境下,改成localhost。两个部分,因此,用作本机开发调试用的最小应用,应该分别启动一个NameServer和一个Broker节点。以上的知识都来源于RocketMQ官网的参考文档,需要更多细节的同学, 可以打开。为文件名后缀,linux环境的脚本以。

GSON的博客 1680

Spring Boot 实现多图片上传并回显,涨姿势了~

上传 Controller的代码非常简单,由于用了SpringMVC框架,所以直接用MultipartFile来接即可。由于是多图片上传所以用数组来接。此处应该注意参数名应该和<input>中的name值相对应: @RequestMapping("/pic") @ResponseBody publicResponseEntity<String>pic(MultipartFile[]pictures)throwsException{ ResponseEnti...

weixin_54556126的博客 894

rocketmq相关用法

mq的使用在项目中是很常见的,当我们遇到不需要立即处理的某块业务,或者说某个业务的处理时间过长,那我们就可以使用mq来削减一下业务的立即处理时间。在方法中,我们可以将需要处理的消息发送到Mq中,然后直接给前端做出响应,消费者再异步并发处理相关的业务,这样可以加快响应时间,给用户相对较好的使用体验,当然这只使用于不是立即需要出结果的场景。具体业务还是得具体分析。。。

weixin_43083853的博客 739

SAP SD销售订单抬头自定义字段增强:BADI_SLS_HEAD_SCR_CUS实战指南

SAP ERP系统中的销售订单管理是企业核心业务流程,经常需要扩展标准功能来满足个性化业务需求。在SAP SD模块中,销售订单抬头屏幕的增强是常见需求。通过BADI(Business Add-In)技术,可以在不修改标准代码的前提下,实现自定义字段的添加与数据处理。本文详细介绍了如何使用BADI_SLS_HEAD_SCR_CUS实现销售订单抬头自定义字段,包括函数组子屏幕设计、数据存储表构建以及BADI方法的具体实现。这种增强方式适用于VA01/VA02/VA03等事务,保证了系统升级的兼容性和维护的便捷性

weixin_29758911的博客 350

基于dify平台批量分析excel格式信息

如何以表格形式批量输入一些信息,然后让大模型以对话应用形式逐条进行推理分析?请逐行分析以下数据,给出推理结果:{{input}}这里提供一个分步解决方案,结合。

knightissocool的博客 8012

Rocketmq

由于Rocketmq使用java写的,所以运行环境需要jdk将文件上传到 /root 目录执行解压命令配置环境变量修改 /etc/profile 配置文件, 配置环境变量修改完后, 让环境变量立即生效验证。

asddasddeedd的博客 8112

涨点神器:基于YOLOv8的SPD-Conv小目标检测实战教程——让低分辨率场景检测精度飙升

从代码修改到场景落地,每一步都围绕“提升检测精度”这个核心目标,而实际数据也证明了这项技术的强悍——它不是实验室里的花拳绣腿,而是能真正解决工业痛点的涨点神器。在实际场景中,比如无人机巡检的低分辨率航拍图中,对电线、小设备的检测,YOLOv8-SPD的漏检率降低了70%以上。落地时,只需将训练好的YOLOv8-SPD模型部署到边缘设备或云端,即可享受其在小目标、低分辨率场景下的强大性能。的特征融合模块中,通过插入SPD-Conv,让模型在处理小目标时,既能保留空间细节,又能增强通道维度的特征表达。

m0_71589036的博客 157

RocketMQ用法及原理解析(Producer篇)

文章目录一、基本用法二、消息发送原理2.1 生产者启动2.2 查找主题路由信息2.2.1 几个关键的元数据:2.2.2 查找过程2.3 选择消息队列(MessageQueue)2.4 发送消息三、关键源码3.1 启动源码3.2 查找主题路由元素3.3 选择消息队列 一、基本用法 基本用法主要有同步发送,异步发送和指定队列发送,具体见下。这里主要介绍 // 1. 创建生产者对象,指定生产者group...

weixin_44366439的博客 2709

从零开始学习CANoe(三)—— 系统变量的创建和使用

从零开始学习CANoe(三)—— 系统变量的创建和使用

蚂蚁小兵 1万+

【系统架构设计师】论文模板样例:论软件系统架构风格

本人于年月参与项目,该系统为*,在该项目组中我担任系统架构师岗位,主要负责系统整体架构设计。本文以该车联网项目为例,主要讨论了软件架构风格在该项目中的具体应用。底层架构风格我们采用了虚拟机风格中的解释器,因该公交共有几十种不同的数据协议,使用解释器风格可以满足整车数据协议兼容性需求;中间层关于应用层的数据流转采用了独立构件风格中的隐式调用,以减低系统间耦合度、简化软件架构,提高可修改性方面的架构属性;应用系统层采用了B/S的架构风格,统一解决公交行业性难题“实施推广难、维护难”问题。

数据知道的博客 9929

RocketMQ-初体验RocketMQ(08)-IDEA拉取调测RocketMQ源码

文章目录从Git上迁出源码修改源码,启动namersrv修改源码,启动broker 从Git上迁出源码 Github: https://github.com/apache/rocketmq/ clone ,等待… 完成后,如下 修改源码,启动namersrv 需要ROCKETMQ_HOME , 这里可以通过配置IDEA的方式,也可以通过修改源码直接setRocketmqHome,我们...

小工匠 2万+

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

rocketmq mqadmin 的用法详解

参考文档 http://jameswxx.iteye.com/blog/2091971 1.1.控制台使用 RocketMQ提供有控制台及一系列控制台命令,用于管理员对主题,集群,broker等信息的管理; 登录控制台 首先进入RocketMQ工程,进入/RocketMQ/bin 在该目录下有个mqadmin脚本 查看帮助 在mqadmin下可以查看有哪些命令 ...

ghostxbh‘s blog 6558

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

rocketMQ实战

前言 rocketmq-spring-boot-starter 用法简介 业务案例 环境配置 点赞接口 PraiseListener:点赞消息消费者 附本文相关信息 前言 MQ的主要特点为解耦、异步、削峰,该文章主要记录与分享个人在实际项目中的RocketMQ削峰用法,用于减少数据库压力的业务场景,其中RocketMQ的核心组件概念如下: Producer:生产发送消息 Broker:存储Producer..

lucky的专栏 2544

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

Spring Boot 集成 RocketMQ

RocketMQ 是一款由阿里巴巴开源的分布式消息中间件,最初用于支持阿里巴巴的海量业务。它基于发布-订阅模型,具备高吞吐、低延迟、高可用和强一致性的特点,适用于消息队列、大规模数据流处理等场景。以下是对 RocketMQ 的原理和核心概念的详细介绍,帮助你快速认识和熟悉 RocketMQ。到官网 下载最新版本的 RocketMQ 二进制包(Binary 下载)。将下载的 ZIP 文件解压到您选择的目录,例如 D:\software\rocketmq-all-5.1.4-bin-release。

sunyanchun的专栏 5233
上一篇: Spring事务管理和代理模式
下一篇: Apollo 中的 长轮询 定时机制
Java_ttcd
博客等级 码龄4年 198粉丝 190原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值