18、Q复制监控与报告指南

Q复制监控与报告指南

1. 监控Q Apply启动

要确认Q Apply是否成功启动,需在Q Apply日志中查找两条特定消息:
- ASN0572I :表明Q Apply已启动。
- ASN7526I :针对每个接收队列,表明Q Apply正在从该队列读取数据。

示例日志消息如下:

<Asnenv:setEnvIpcQRcvHdl> ASN0594I  "Q Apply" :  "ASN" : "Initial" 
The program created an IPC queue with keys "(Global\OSSEIPC48tempDB2.
DB2B.ASN.QAPP.IPC, Global\OSSEIPC49tempDB2.DB2B.ASN.QAPP.IPC, Global\
OSSEIPC50tempDB2.DB2B.ASN.QAPP.IPC".
<asnqapp::main> ASN0572I  "Q Apply" :  "ASN" : "Initial" : The 
program initialized successfully.
<brwzMain> ASN7526I  "Q Apply" :  "ASN" : "BR00000" : The Q Apply 
program has started processing the receive queue "CAPA.TO.APPB.RECVQ" 
for replication queue map "RQMA2B".

若Q Apply成功启动,还需检查所有线程是否正在运行。可使用以下 ASNQCCMD 命令结合 STATUS 选项来检查线程状态:

$ asnqacmd APPLY_SERVER=db2b STATUS

示例命令响应如下:

2009-11-26-17.08.48.984000 ASN0520I  "AsnQAcmd" : "ASN" : "Initial" 
: The STATUS command response: "HoldLThread" thread is in the "is 
resting" state.
2009-11-26-17.08.48.984000 ASN0520I  "AsnQAcmd" : "ASN" : "Initial" 
: The STATUS command response: "AdminThread" thread is in the "is 
resting" state.
2009-11-26-17.08.48.984000 ASN0520I  "AsnQAcmd" : "ASN" : "Initial" 
: The STATUS command response: "MonitorThread" thread is in the "is 
resting" state.
2009-11-26-17.08.49.000000 ASN0520I  "AsnQAcmd" : "ASN" : "Initial" 
: The STATUS command response: "BR00000" thread is in the "is doing 
work" state.

所有线程都应处于运行状态。

2. 检查Q Capture和Q Apply是否活跃

Q Capture和Q Apply可相对独立运行,即Q Capture运行时Q Apply可能停止,反之亦然。但如果Q Apply停止,它将无法从接收队列读取数据,队列深度会不断增加,直到达到 MAXDEPTH 值,此时Q Capture会异常终止,因为它无法再向发送队列放入更多消息。

可使用复制警报监视器或 asnqccmd / asnqacmd 命令来检查Q Capture和Q Apply是否活跃。

3. 检查Q Capture和Q Apply日志文件

浏览日志文件时,需留意任何形式为 ASNxxxxE 的消息,这表示出现错误情况。

4. 检查APPLYTRACE和CAPTRACE表

两个重要的控制表是 IBMQREP_APPLYTRACE IBMQREP_CAPTRACE
- IBMQREP_APPLYTRACE 表包含Q Apply的信息、警告和错误消息。
- IBMQREP_CAPTRACE 表包含Q Capture的信息、警告和错误消息。

需定期从这些表中查询以检查是否有错误。若Q Capture在DB2A上运行,Q Apply在DB2B上运行,则可使用以下查询:

$ db2 "SELECT operation, trace_time, description FROM 
asn.ibmqrep_captrace WHERE operation IN ('ERROR', 'WARNING')"
$ db2 "SELECT operation, trace_time, description,1,100 FROM 
asn.ibmqrep_applytrace WHERE operation IN ('ERROR', 'WARNING')"
5. 检查Q Capture与DB2日志的差距

可使用特定命令检查Q Capture落后于DB2日志的程度。

6. 检查Q Apply与Q Capture的差距

同样使用特定命令检查Q Apply落后于Q Capture的程度。

7. 列出Q订阅状态

使用以下查询检查Q订阅的状态:

$ db2 "select substr(subname,1,10) as subname, state as S, state_time 
from asn.ibmqrep_subs "
8. 列出接收队列状态

使用以下查询检查接收队列的状态:

$ db2 "SELECT recvq, state FROM ASN.IBMQREP_RECVQUEUES WHERE RECVQ = 
'CAPA.TO.APPB.RECVQ' "

示例查询结果如下:
| RECVQ | STATE |
| — | — |
| CAPA.TO.APPB.RECVQ | A |

若要启动接收队列,可使用 ASNQACMD STARTQ 命令。

9. 表同步

若系统未产生错误,需检查源表和目标表是否同步,可采用以下两种方法:
1. 对源表和目标表分别执行 SELECT COUNT(*) 查询,但这最多只能表明行数相同,且在系统使用过程中,行数可能不同,同时该方法只报告行数,不涉及行内容。
2. Q复制提供了 asntdiff asntrepair 两个实用工具,可用于检测和修复源表与目标表之间的差异,无需手动比较表或对目标表进行加载(全量刷新)。使用 asntdiff 工具的最佳时机是源表和目标表稳定时,例如Q Capture到达DB2恢复日志末尾且所有更改都已应用到目标表时。若应用程序仍在更新源表,比较结果可能不准确。

比较由Q订阅 TAB1 标识的表,可执行以下命令:

$ asntdiff DB=db2a SCHEMA=asn WHERE= "WHERE SUBNAME = 'TAB1' "
10. 不同延迟指标

有三种不同的延迟指标存储在 IBMQREP_APPLYMON 表中:
- Q Apply延迟 :来自 IBMQREP_APPLYMON 表的 APPLY_LATENCY 列,是Q Apply从接收队列读取事务到将其提交到目标表的平均毫秒数。
- MQ延迟 :来自 IBMQREP_APPLYMON 表的 QLATENCY 列,是Q Capture将消息放入发送队列到Q Apply从接收队列获取消息的平均毫秒数。
- Q Capture延迟 END2END_LATENCY 列减去 APPLY_LATENCY QLATENCY 列的值。 END2END_LATENCY 是事务提交到源表到提交到目标表的平均毫秒数。

可使用以下命令报告延迟指标:

$ asnqacmd APPLY_SERVER=db2b STATUS SHOW DETAILS

示例命令响应如下:

ASN0600I  "AsnQAcmd" :  "" : "Initial" : Program "asnqacmd 9.1.0" is 
starting.
 Q Apply program status
   Server name                            (SERVER) = DB2B
   Schema name                            (SCHEMA) = ASN
   Program status                         (STATUS) =  Up
   Time since program started            (UP_TIME) =   0d  0h  2m 26s
   Log file location       (LOGFILE) = C:\TEMP\DB2.DB2B.ASN.QAPP.log
   Number of active Q subscriptions         (ACTIVE_QSUBS) = 1
   Time period used to calculate average (INTERVAL_LENGTH) =  0h  2m 
18.266s
   Receive queue : CAPA.TO.APPB.RECVQ
       Number of active Q subscriptions              (ACTIVE_QSUBS) = 
1
 All transactions applied as of (time)         (OLDEST_TRANS) = 2007-
04-06-09.36.03.000000
 All transactions applied as of (LSN) (ALL_APPLIED_AS_OF_LSN) = 
0000:0000:0000:0000:0000
 Oldest in-progress transaction          (OLDEST_INFLT_TRANS) = 1900-
01-01-00.00.00.000       Average end-to-end latency      (END2END 
LATENCY) =  0h  0m  0.0s
       Average Q Capture latency    (CAPTURE_LATENCY) =  0h  0m  0.0s
       Average WSMQ latency              (QLATENCY) =  0h  0m  0.0s
       Average Q Apply latency        (APPLY_LATENCY) =  0h  0m  0.0s
       Current memory                  (CURRENT_MEMORY ) = 0 MB
       Current queue depth                      (QDEPTH) = 0
11. DB2日志延迟

DB2日志延迟是Q Capture落后于DB2日志的时间,可通过 IBMQREP_CAPMON 表中的 monitor_time - current_log_time 计算得出:

$ db2 "SELECT monitor_time, monitor_time-current_log_time AS 
DB2_log_latency_sec FROM asn.ibmqrep_capmon ORDER BY monitor_time DESC 
FETCH FIRST 5 ROWS ONLY "

示例查询结果如下:
| MONITOR_TIME | DB2_LOG_LATENCY_SEC |
| — | — |
| 2006-02-18-17.52.08.562000 | 4.596000 |
| 2006-02-18-17.51.38.519000 | 4.587000 |
| 2006-02-18-17.51.08.466000 | 4.577000 |
| 2006-02-18-17.50.38.383000 | 4.527000 |
| 2006-02-18-17.50.08.339000 | 4.516000 |

12. 基础监控表

基础监控表是指复制警报监视器之外可用的表,Q Capture对应的是 IBMQREP_CAPMON IBMQREP_CAPQMON ,Q Apply对应的是 IBMQREP_APPLYMON
- Q Capture表 IBMQREP_CAPMON 包含Q Capture的整体统计信息, IBMQREP_CAPQMON 包含每个发送队列的统计信息。 IBMQREP_CAPMON 表的 ROWS_PROCESSED 列显示Q Capture从DB2日志读取的所有行,无论这些行是否属于订阅表; IBMQREP_CAPQMON 表的 ROWS_PUBLISHED 列显示Q Capture发送到发送队列的行数。
- Q Apply表 :关注的表是 IBMQREP_APPLYMON ,检查 MEM_FULL_TIME 列可了解是否定义了足够的代理。

13. 历史分析数据收集

前面讨论的策略均为实时策略,还可收集信息进行历史分析,所需信息都在 xxxMON 控制表中,其中 xxx 分别为 CAP APPLY ,对应Q Capture和Q Apply。

历史监控Q Capture

创建一个表来存储历史Q Capture信息,并使用SQL语句填充该表。历史表包含以下列:
| 列名 | 说明 |
| — | — |
| RUNDATE (mm/dd/yyyy) | 条目的日期 |
| hour (int) | 总计的结束小时 |
| COUNT (bigint) | 构成此组合条目的 IBMQREP_CAPMON 表的行数 |
| ROWS_PROCESSED (sum) (bigint) | Q Capture从日志读取的行数(单个插入、更新或删除操作) |
| TRANS_SKIPPED (sum) (bigint) | 未放入队列的事务数(包含更改行),因为更改的列不属于Q订阅或XML发布 |
| TRANS_PROCESSED (sum) (bigint) | Q Capture处理的事务数 |
| TRANS_SPILLED (sum) (bigint) | Q Capture超过 MEMORY_LIMIT 阈值后溢出到文件的事务数 |
| MAX_TRANS_SIZE (max/min) (int) | Q Capture处理的最大事务大小(以兆字节为单位) |
| QUEUES_IN_ERROR (sum) (int) | 不接受消息的队列数 |

创建历史表的SQL语句如下:

$ db2 "create table db2admin.hist_capmon (rundate date not null, hour 
int, count int, sum_rows_processed bigint, sum_trans_skipped bigint, 
sum_trans_processed bigint, sum_trans_spilled bigint, max_max_trans_size 
int, min_max_trans_size int, max_queues_in_error int, min_queues_in_error 
int) "
$ db2 "alter table db2admin.hist_capmon add constraint prid primary key 
(rundate) "

填充Q Capture历史表的SQL语句如下:

$ db2 "INSERT INTO db2admin.hist_capmon SELECT '02/15/2006', 
HOUR(monitor_time)+1, count(*), SUM(rows_processed), SUM(trans_skipped), 
SUM(trans_processed), SUM(trans_spilled), MAX(max_trans_size), MIN(
min_trans_size), MAX(queues_in_error), MIN(queues_in_error) FROM 
asn.ibmqrep_capmon WHERE DATE(monitor_time) = '02/15/2006' GROUP 
BY(hour(monitor_time)"

需根据需要更改日期字段。

历史监控Q Apply

创建一个表来存储历史Q Apply信息,并使用SQL语句填充该表。历史表包含以下列:
| 列名 | 说明 |
| — | — |
| RUNDATE (mm/dd/yyyy) | 条目的日期 |
| HOUR (int) | 总计的结束小时 |
| COUNT(bigint) | 构成此组合条目的 IBMQREP_APPLYMON 表的行数 |
| CURRENT_MEMORY (max/min) (int) | Q Apply浏览器线程从该队列读取事务使用的内存字节数 |
| QDEPTH (max/min) (int) | 队列深度(队列上的消息数) |
| END2END_LATENCY (max/min) (int) | 事务提交到源表到提交到目标表的平均毫秒数 |
| QLATENCY (max/min) (int) | Q Capture将消息放入发送队列到Q Apply从接收队列获取消息的平均毫秒数 |
| APPLY_LATENCY (max/min) (int) | Q Apply从接收队列读取事务到将其提交到目标表的平均毫秒数 |
| TRANS_APPLIED (sum) (bigint) | Q Apply从该接收队列提交到目标表的事务总数 |
| ROWS_APPLIED (sum) (bigint) | Q Apply从该接收队列应用到目标表的插入、更新和删除操作总数 |
| TRANS_SERIALIZED (sum) (bigint) | 与其他事务冲突的事务总数(由于行冲突或引用完整性冲突) |
| RI_DEPENDENCIES (sum) (bigint) | 检测到的引用完整性冲突总数,导致事务序列化 |
| RI_RETRIES (sum) (bigint) | 由于引用完整性冲突,Q Apply重新应用行更改的次数 |
| DEADLOCK_RETRIES (sum) (bigint) | 由于锁超时和死锁,Q Apply重新应用行更改的次数 |
| ROWS_NOT_APPLIED (sum) (bigint) | 无法应用并记录在 IBMQREP_EXCEPTIONS 表中的行数 |
| MONSTER_TRANS (sum) (bigint) | 超过 IBMQREP_RECVQUEUES 表中为接收队列设置的 MEMORY_LIMIT 的事务数 |
| MEM_FULL_TIME (sum) (bigint) | Q Apply由于其代理使用所有可用内存来应用事务而无法从该接收队列构建事务的总秒数 |
| OKSQLSTATE_ERRORS (sum) (bigint) | 导致SQL错误的行更改数,该错误在 IBMQREP_TARGETS 表的 OKSQLSTATES 字段中定义为可接受,Q Apply会忽略这些错误 |
| KEY_DEPENDENCIES (sum) (bigint) | 检测到的复制键约束总数,导致事务序列化 |
| UNIQ_DEPENDENCIES (sum) (bigint) | 检测到的唯一索引约束总数,导致事务序列化 |
| UNIQ_RETRIES (sum) (bigint) | 由于唯一索引约束,Q Apply尝试重新应用未并行应用的行的次数 |

创建Q Apply历史表的SQL语句如下:

$ db2 "create table db2admin.hist_appmon (rundate date, hour int, count 
int, max_current_memory int, min_current_memory int, max_qdepth int, 
min_qdepth int, max_end2end_latency int, min_end2end_latency int, max_
qlatency int, min_qlatency int, sum_trans_applied bigint, sum_rows_
applied bigint, sum_trans_serialized bigint, sum_ri_dependencies bigint, 
sum_ri_retries bigint, sum_deadlock_retries bigint, sum_rows_not_applied 
bigint, sum_monster_trans bigint, sum_mem_full_time bigint) "

填充Q Apply历史表的SQL语句如下:

$ db2 "INSERT INTO db2admin.hist_appmon SELECT '02/15/2006', 
HOUR(monitor_time)+1, COUNT(*),MAX(current_memory), MIN(current_
memory), MAX(qdepth), MIN(qdepth), MAX(end2end_latency), MIN(end2end_
latency), MAX(qlatency), MIN(qlatency), SUM(trans_applied), SUM(rows_
applied), SUM(trans_serialized), SUM(ri_dependencies), SUM(ri_retries), 
SUM(deadlock_retries), SUM(rows_not_applied), SUM(monster_trans), 
SUM(mem_full_time) FROM asn.ibmqrep_applymon WHERE DATE(monitor_time) = 
'02/16/2006' GROUP BY (HOUR(monitor_time)) "

需根据需要更改日期字段。

14. 确定行吞吐量

可通过以下方法确定过去10分钟、5分钟、1分钟和最新的行吞吐量:

C:\asnclp> db2 -tvf quer01.sql
with t1(num) as (select count(*) from asn.ibmqrep_capmon where 
monitor_time > current timestamp - 10 minutes), t2(rowsp) as (select 
sum(rows_processed) from asn.ibmqrep_capmon where monitor_time > current 
timestamp - 10 minutes) select rowsp/num from t1,t2

也可编写存储过程来实现:
创建 sp02.sql 文件,内容如下:

create procedure get_thru (in timeval int, out v1 int, out v2 int, out 
v3 int)
language SQL
P1: begin
select count(*) into v1 from asn.ibmqrep_capmon where monitor_time > 
current timestamp - timeval minutes;
select sum(rows_processed) into v2 from asn.ibmqrep_capmon where 
monitor_time > current timestamp - timeval minutes;
set v3 = v2/v1;
end P1 @

编译该文件:

C:\asnclp> db2 -td@ -vf sp02.sql

运行存储过程:

C:\asnclp> db2 call get_thru(10,?,?,?)

或者创建 sp01.sql 文件,内容如下:

create procedure get_thru2 (in timeval int)
language SQL
begin
declare c1 cursor with return for
with t1(num) as 
(select count(*) from asn.ibmqrep_capmon where monitor_time > current 
timestamp - timeval minutes),
t2(rowsp) as 
(select sum(rows_processed) from asn.ibmqrep_capmon where monitor_time 
> current timestamp - timeval minutes)
select rowsp/num from t1,t2;
open c1;
end @

编译该文件:

C:\asnclp> db2 -td@ -vf sp01.sql

运行存储过程:

C:\asnclp> db2 call get_thru2(10)

通过以上详细的监控和分析方法,可以全面了解Q复制系统的运行状态,及时发现并解决潜在问题,确保系统的稳定运行。

Q复制监控与报告指南(续)

15. 吞吐量计算流程总结

为了更清晰地展示确定行吞吐量的操作流程,以下是一个 mermaid 格式的流程图:

graph LR
    A[开始] --> B[选择计算方式]
    B -->|SQL查询| C[执行 SQL 查询]
    C --> D[计算吞吐量]
    B -->|存储过程| E[创建存储过程文件]
    E --> F[编译存储过程文件]
    F --> G[运行存储过程]
    G --> D
    D --> H[输出吞吐量结果]
    H --> I[结束]

这个流程图展示了两种确定行吞吐量的方式:直接使用 SQL 查询和通过存储过程。用户可以根据实际需求选择合适的方式。

16. 历史数据收集与分析的重要性

历史数据收集对于深入了解 Q 复制系统的性能和行为至关重要。通过收集和分析历史数据,可以:
- 发现趋势 :观察系统在不同时间段的性能变化,例如行吞吐量随时间的波动、延迟指标的长期趋势等。
- 预测问题 :根据历史数据预测潜在的性能问题,提前采取措施进行优化和调整。
- 评估优化效果 :在进行系统优化后,通过对比优化前后的历史数据,评估优化措施的效果。

17. 监控策略总结

为了确保 Q 复制系统的稳定运行,需要综合运用多种监控策略。以下是一个监控策略的总结表格:
| 监控项目 | 监控方法 | 关键指标 |
| — | — | — |
| Q Apply 启动 | 检查日志中的特定消息,使用 ASNQCCMD 命令检查线程状态 | ASN0572I、ASN7526I 消息,线程运行状态 |
| Q Capture 和 Q Apply 活跃状态 | 复制警报监视器或 asnqccmd / asnqacmd 命令 | 系统是否正常运行 |
| 日志文件 | 检查是否存在 ASNxxxxE 消息 | 错误状态 |
| APPLYTRACE 和 CAPTRACE 表 | 定期从表中查询错误消息 | 错误消息数量 |
| Q Capture 与 DB2 日志差距 | 使用特定命令检查 | 差距时间 |
| Q Apply 与 Q Capture 差距 | 使用特定命令检查 | 差距时间 |
| Q 订阅状态 | SQL 查询 | 订阅状态 |
| 接收队列状态 | SQL 查询 | 队列状态 |
| 表同步 | SELECT COUNT(*) 查询或 asntdiff 工具 | 行数是否相同,表差异情况 |
| 延迟指标 | asnqacmd 命令 | Q Apply 延迟、MQ 延迟、Q Capture 延迟 |
| DB2 日志延迟 | SQL 查询 | 延迟时间 |
| 基础监控表 | 检查相关表的列 | 统计信息 |
| 历史数据收集 | 创建历史表并填充数据 | 历史性能指标 |
| 行吞吐量 | SQL 查询或存储过程 | 行吞吐量 |

18. 异常处理建议

在监控过程中,如果发现异常情况,可根据不同的异常类型采取相应的处理措施:
- 错误消息(ASNxxxxE) :在日志文件或 APPLYTRACE CAPTRACE 表中发现错误消息时,首先查看错误消息的详细描述,确定错误的原因。可能的原因包括网络问题、数据库配置错误等。根据错误原因进行相应的修复,例如检查网络连接、调整数据库参数等。
- 队列深度达到 MAXDEPTH :如果接收队列深度达到 MAXDEPTH ,导致 Q Capture 异常终止,需要及时排查 Q Apply 停止的原因。可能是 Q Apply 出现故障、资源不足等。解决方法包括重启 Q Apply、增加系统资源等。
- 延迟指标异常 :如果延迟指标(如 Q Apply 延迟、MQ 延迟、Q Capture 延迟)突然增大,需要检查系统的负载情况、网络状况等。可能是系统负载过高、网络延迟等原因导致。可采取的措施包括优化系统配置、调整网络设置等。

19. 监控频率建议

为了及时发现系统问题,需要合理设置监控频率。以下是一些监控频率的建议:
| 监控项目 | 监控频率 |
| — | — |
| Q Apply 启动和线程状态 | 每次系统启动后检查 |
| Q Capture 和 Q Apply 活跃状态 | 每 5 - 10 分钟检查一次 |
| 日志文件 | 每小时检查一次 |
| APPLYTRACE 和 CAPTRACE 表 | 每天检查一次 |
| Q Capture 与 DB2 日志差距、Q Apply 与 Q Capture 差距 | 每 10 - 15 分钟检查一次 |
| Q 订阅状态和接收队列状态 | 每小时检查一次 |
| 表同步 | 根据系统稳定性和业务需求,每周或每月检查一次 |
| 延迟指标 | 每 5 - 10 分钟检查一次 |
| DB2 日志延迟 | 每 10 - 15 分钟检查一次 |
| 基础监控表 | 每天检查一次 |
| 历史数据收集 | 每天收集一次 |
| 行吞吐量 | 每 5 - 10 分钟检查一次 |

20. 总结与展望

通过全面的监控和分析,可以及时发现 Q 复制系统中的问题,并采取相应的措施进行解决,确保系统的稳定运行。在未来的工作中,可以进一步优化监控策略,提高监控的准确性和及时性。例如,结合自动化工具实现实时监控和自动报警,当系统出现异常时及时通知管理员。同时,持续关注系统的性能变化,根据业务需求和系统发展进行不断调整和优化,以满足日益增长的业务需求。

总之,有效的监控和报告是保障 Q 复制系统稳定运行的关键。通过合理运用各种监控方法和工具,收集和分析相关数据,可以深入了解系统的性能和行为,为系统的优化和管理提供有力支持。

Java是一种具备卓越性能广泛平台适应性的高级程序设计语言,最初由Sun Microsystems(现属Oracle公司)的James Gosling及其团队于1995年正式发布。该语言在设计上追求简洁性、稳定性、可移植性以及并发处理能力,同时具备动态执行特性。其核心特征显著优点可归纳如下: **平台无关性**:遵循“一次编写,随处运行”的理念,Java编写的程序能够在多种操作系统硬件环境中执行,无需针对不同平台进行修改。这一特性主要依赖于Java虚拟机(JVM)的实现,JVM作为程序底层系统之间的中间层,负责解释并执行编译后的字节码。 **面向对象范式**:Java全面贯彻面向对象的设计原则,提供对封装、继承、多态等机制的完整支持。这种设计方式有助于构建结构清晰、模块独立的代码,提升软件的可维护性扩展性。 **并发编程支持**:语言层面集成了多线程处理能力,允许开发者构建能够同时执行多项任务的应用程序。这一特性尤其适用于需要高并发处理的场景,例如服务器端软件、网络服务及大规模分布式系统。 **自动内存管理**:通过内置的垃圾回收机制,Java运行时环境能够自动识别并释放不再使用的对象所占用的内存空间。这不仅降低了开发者在内存管理方面的工作负担,也有效减少了因手动管理内存可能引发的内存泄漏问题。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值