GaussDB 关键技术原理 | 高可用:两地三中心跨 Region 容灾

接上篇 GaussDB 关键技术原理 | 高可用:逻辑复制从逻辑复制方面对 GaussDB 的高可用能力进行了介绍,本篇将从两地三中心跨 Region 容灾方面继续解读 GaussDB 高可用技术。 4 两地三中心跨 Region 容灾 4.1 概述 两地三中心,顾名思义,两地指的是两座城市,即同城和异地,三中心指的是生产中心,同城容灾中心以及异地容灾中心。近年来,国内外频繁出现自然灾害,以同城双中心加异地灾备中心的 "两地三中心" 的灾备模式也随之出现,这一方案兼具高可用性和灾难备份的能力。

同城双中心是指在同城或邻近城市建立两个可独立承担关键系统运行的数据中心,双中心具备基本等同的业务处理能力并通过高速链路实时同步数据,日常情况下可同时分担业务及管理系统的运行,并可切换运行;灾难情况下可在基本不丢失数据的情况下进行灾备应急切换,保持业务连续运行。

异地灾备中心是指在异地的城市建立一个备份的灾备中心,用于双中心的数据备份,当双中心出现自然灾害等原因而发生故障时,异地灾备中心可以用备份数据进行业务的恢复。数据库实例之间借助存储介质或者不借助存储介质直接实现数据的全量和增量同步。当主数据库实例(即生产数据库实例)出现地域性故障,数据完全无法恢复时,可考虑启用将灾备数据库实例升主,以接管业务。

GaussDB 当前提供基于流式复制的异地容灾解决方案。目前需要通过 om_agent 的 https REST API 来操控数据库实例实现异地容灾。

4.2 异地容灾部署示例 集中式

主集群是同城跨 AZ 的单集群,5 台服务器,4 副本,CMS-4 副本,ETCD-5 副本。Server5 可以看做是仲裁副本,为上海 2 机房脑裂时,提供仲裁能力。

分布式:

分布式示例 主集群是同城跨 AZ 的单集群,33 台服务器,32C32D-4 副本,GTM-4 副本,CMS-4 副本,ETCD-5 副本。server33 可以看做是仲裁副本,为北京 2 机房脑裂时,提供仲裁能力。

容灾集群为 16 台服务器,16C32D-2 副本,需要开启最大可用模式,1 个副本故障时任何对外提供服务,GTM-4 副本,CMS-4 副本,ETCD-3 副本。由于机器数量有限,需要支持单服务器上部署 2 个主 DN 的部署方式。特别说明:图中展示的是合肥地域集群为正常集群时的组网,该集群成为灾备集群后,不会再有主 DN,变为首备与级联备。

4.3 总体设计 集中式部署场景:

主实例和灾备实例副本数可不同,灾备集群最少为 1 副本。

图 两地三中心异地容灾方案集中式部署场景

分布式部署场景:

支持灾备集群的 CN 个数和主集群 CN 个数不对等。 主集群和灾备集群 DN 分片数要求相同,DN 分片内副本数可不同,灾备集群最少为 1 副本。

图 两地三中心异地容灾方案分布式部署场景

容灾方案提供如下操作流程:

容灾搭建:两个正常集群成为容灾状态下的主集群和灾备集群。 

图 两地三中心异地容灾方案集中式部署容灾搭建集群变化

  1. 主备集群副本数可不同。
  2. 灾备集群有首备 + 级联备概念,只有首备从主集群主 DN 拷贝全量数据并建立异地流式复制关系。
  3. 灾备集群内级联备从首备拷贝数据,并与首备建立流式复制关系。

灾备集群升主 failover:无论主集群是否异常,灾备集群都可以通过升主成为正常集群对外提供服务,并脱离容灾。 演练特性 - 主备集群 switchover:主备集群在都是正常的情况下进行倒换,主集群降为备机,备机升为主机。

图 两地三中心异地容灾方案集中式部署 failover 与 switchover 集群变化

主集群容灾解除:用于在灾备集群升主后,主集群删除容灾信息,脱离容灾。 容灾状态查询:容灾状态日常监测,上报集群容灾状态、容灾搭建进度、failover 进度、switchover 进度,集群 RTO,RPO 实时数值。 

 容灾状态下支持如下功能:

流控:通过 GUC 参数设置目标值,对主集群的日志产生速度进行控制,以保证 RPO,RTO。 压缩:主备集群间日志传输可打开压缩,节约带宽,压缩比 70%。

4.4 容灾搭建 容灾搭建总体流程

图 流式容灾集群搭建流程图

图 灾备集群搭建 build 备集群实例流程图

容灾流程图说明

灾备集群搭建主流程:

  1. 管控 A 下发搭建新集群 A,管控 B 下发搭建新集群 B。
  2. 管控 A,B 同时对集群下发灾备集群搭建指令,假设 A 为主集群,B 为灾备集群。B 集群中各实例配置 A 集群中对应节点实例的 IP、PORT 信息,A 集群同样添加 B 集群中主备的 IP、PORT 信息。
  3. 选择 B 集群中首备实例。向 B 集群主备实例下发全量重建指令。
  4. 待 B 集群主备重建完成,建立 A 集群和 B 集群中主备的流复制,并下发 B 集群重建级联备指令。
  5. 待 B 集群所有实例重建成功,且 B 集群主备实例和 A 集群对应备机(分布式下对应分片的备机)建立流复制,其他 B 集群备机(分布式下同分片内)和首备建立连接成功后,返回灾备搭建成功。

容灾集群流式日志复制

图 流式容灾灾备集群流复制复制消息序列图

  1. 在开启容灾阶段:在主集群每个副本上,配置 replconninfo、hadr_recovery_time_target、hadr_recovery_point_target GUC 参数,配置 pg_hba.conf;在灾备集群的每个副本上,配置 replconninfo 参数。
  2. CM 仲裁选举灾备集群中的首备。
  3. 灾备集群首备轮询主集群中所有的副本,直到找到主 DN。
  4. 灾备首备发起日志复制请求,包括:版本校验、对端状态校验、系统一致性校验、日志一致性校验;灾备首备创建和继续流复制槽,流复制槽名称采用 application_name + _hadr 方式拼接,以便和主集群同名副本进行区分。
  5. 主集群主 DN 遍历所有主集群 walsender,获取多数派副本已经同步的日志 LSN 位置的最小值,并将首备请求 LSN 位置到该 LSN 位置之间的日志发送给首备。
  6. 灾备集群首备接受到日志之后,由 walreceiver writer 下盘。
  7. 灾备集群其他副本对首备发起级联复制请求,首备将上述请求 LSN 位置到本地下盘日志 LSN 位置之间的日志,级联发送到各个级联副本。
  8. 级联副本接受到日志之后,将本地的日志下盘位置和日志回放位置反馈给首备。
  9. 首备将灾备集群中所有副本中日志下盘的多数派 LSN 位置和日志回放的多数派 LSN 位置反馈给主集群的主 DN。
  10. 主集群主 DN 将首备反馈的灾备集群多数派日志下盘位置,作为日志回收以及灾备 RPO 流控的判断条件(之一)。
  11. 主集群主 DN 将首备反馈的灾备集群多数派回放下盘位置,作为灾备 RTO 流控的判断条件(之一)。

容灾集群流式日志复制的高可用

主集群少数派副本故障

图 主集群发生少数派副本消息序列图

  1. 主集群 CM 发起锁分片和重新选主。
  2. 灾备集群首备的复制链接中断,wal receiver 线程退出,重新开始轮询主集群各个副本。
  3. 主集群新主选主成功。
  4. 灾备集群轮询到新主,再次开始流式日志复制。
  5. 由于发送给灾备集群首备的日志都是在主集群已经达成多数派的,因此不会发生日志分叉的问题。

灾备集群少数派故障:

图 灾备集群发生少数派副本消息序列图

  1. 灾备首备故障,跨 region 复制中断。
  2. 灾备 CMS 发起首备重新选举,类似主集群选主:首先锁分片,然后从剩余备副本中找到本地日志 term 最大、日志最大的那个副本,选为首备,最后再给剩余级联备副本下发连接新首备的命名。
  3. 先首备轮询主集群各个副本,请求跨 region 日志复制,流程同上。
  4. 灾备集群中,其他副本在从新首备请求日志复制时,可能会出现本地日志大于新首备的情况(故障再加回场景),由于日志不会发生分叉,因此在这种情况下,该日志较多的级联备只需要在日志一致性校验阶段等待新首备的日志超过本地日志即可。

CN 支持流复制机制

根据上述分布式容灾搭建的对应关系,备集群 CN 需要和主集群的 CN 建立一对一的流式容灾关系以保证日志的持续拷贝和回放。该设计的基本思路同集群内的主备关系,但是不要求 CN 间复制是强同步的,所以修改 CN 的 synchronous_commit = off,不阻塞主集群 CN 的提交。在备集群的 CN 和备机一样,以 standby 模式启动,当本地日志回放结束后 0 启动 walreceiver 线程通过解析 replconninfo 参数建立和主集群 CN walsender 的连接。由主集群 CN walsender 开始持续发送 xlog 日志,再由备集群 CN 本地回放日志使数据和主集群 CN 保证一致。故障处理和原集群内主备一致。当备 CN 未连接主 CN 时,备 CN 标记为 disconnected 状态;当日志 crc 校验不一致时备集群 CN 将自己的 build reason 标记为 wal segments removed 状态;当主备断连时标记为 connecting 状态。主要交互流程如图所示。

图 灾备集群搭建备集群 CN 实例 build 流程图

同时对于新增的 CN 流复制应考虑日志回收的逻辑。日志回收总体方案和原 DN 主备逻辑一致,先参考本地日志是否大于 wal_keep_segments 参数,若大于则主集群 CN 参考对应流复制槽,(目前只有备 CN 的槽位)日志落盘位置,保证正向场景下备 CN 所需日志不会被主 CN 回收。考虑到异常的备 CN 断连场景,主 CN 的日志回收应参考最大日志保留量 max_size_for_xlog_prune 参数,保证在不影响主集群 CN 可用性下,为备 CN 保留最多的日志,减少全量 build 的可能。

灾备集群的 CN 个数和主集群 CN 个数不对等场景下建立容灾关系

图中主备集群 CN 对应关系的处理说明:

受限于 replconninfo 配置个数的上限,集群达到一定规模后不可能将对端所有的节点链接信息都配上,所以 OM 在主备集群搭建容灾关系时 CN 依据如下计算方式进行对应。

当前使用 CN instance id 从小到大排序后的 normal CN id list 进行主备集群 CN 配对,比如主集群有 M 个 normal CN,灾备集群有 N 的 normal CN,对 M,N 中较小的值取模对应。可能出现的情况分析如下:

图 主集群 CN 多于灾备集群 CN 容灾搭建示例

(1)、如果主集群的 CN 多(上图 M=5),灾备集群的 CN 少(上图 N=3),以灾备集群的 CN 数量为准, 一对一进行 build 之后建立 replication;主集群多出来的 CN 没有灾备 CN 对应,配置有容灾信息 replconninfo,但不发生作用。灾备集群的 CN 会配置多条容灾使用的 replconninfo,比如主集群的 CN1 挂了,灾备 CN1 可以连到 CN4 上触发 build。 

图 主集群 CN 少于灾备集群 CN 容灾搭建示例

(2)、如果灾备集群的 CN 多(上图 N=5),主集群的 CN 少(上图 M=3)(主要出现场景为计划内 switchover、灾备集群升主后反向搭建容灾关系),此时灾备集群会有多个灾备 CN 同时和主集群相同 CN 建立流式复制的关系,比如上图上 CN1 和 CN4 都是与主集群的 CN1 建立容灾关系。

容灾过程中灾备故障 CN 的处理

  1. 主集群 CN 故障导致灾备 CN 故障的处理机制

主集群处于容灾的 CN 发生剔除,或者主备集群间网络断链导致灾备 CN 处于故障状态,CN 采用 Need_repair (<build_reason>) 上报机制,灾备 CM 对这一状态的 CN 不做剔除处理。

主集群处于容灾的 CN 发生剔除或者网络断链状态,灾备集群对应的 CN 感知到断连,将上报 Need_repair (Disconnected) 状态,并由 CM 显示。 主集群 CN 因为修复等操作发生 build,灾备 CN 试图同步的日志和本地 xlog 日志不一致,灾备 CN 需要上报 Need_repair (wal segment removed) 等状态,灾备 CMS 感知后,会通知 CN 所在 CMA 下发 CN 全量 build(从主集群对应 cn build,build 完成后自动拉起),build 完成后 CN 恢复 Normal 状态。 相关命令 gs_ctl build -b cross_cluster_full -Z coordinator -D <dir_path> -M standby。 灾备 CN build 期间,显示 building 状态,不参与 barrier 推进,也不参与备机只读的接入。 灾备集群的 CN 会将当前连接成功的生产集群 CN 的序号持久化到文件里边,重启后会从文件读取最近一次的 CN 序号,优先连接最近一次连接的成功的对端 CN。在尝试连接失败次数达到一个阈值(当前阈值设定为 3000 次)时候,才会尝试连接下一个 replication info 里边的 CN。

  1. 灾备集群 CN 故障的处理机制

灾备的 CN 故障同主集群有所不同:灾备集群的 CN 是按 standby 起的,不会和其他 CN/DN 联系,满足条件(CN 心跳超时 25s、CN 反复重启)会被剔除,置 Deleted 状态。Deleted 状态的 CN 不参与 barrier 推进,也不参与备机只读的接入。 被剔除 CN 由 CMA 检测满足自动加回条件后进行自动修复,或手动进行 CN 修复。修复期间会触发全量 build。修复完成后 CN 恢复 Normal 状态。要保证最后一个非超前状态的 CN 不触发 build,否则会出现容灾集群无 CN 可用的暂态。

  1. 灾备集群 CN 故障的告警

在容灾状态下,灾备集群 CN 如果出现 Need_repair (Disconnected),上报容灾实例断连告警,并在 Detail 信息中体现本端实例 id 与对端实例 id 的容灾关联性。该告警信息上报管控。详见《3.3.8 系统外部接口 (和其他产品)》

  1. 灾备集群 CN 状态转化汇总

图 灾备集群 CN 状态转换

约束

对应集群只要有一个 CN 还活着,就能提供服务:容灾状态的集群同样保证最后一个 CN 不做剔除。 灾备集群需要始终保持至少一个 CN 不处于 waiting 或者 deleted 状态。

异地容灾集群间日志传输需要支持日志压缩

受客户场景跨集群间的网络带宽限制,将跨集群的 xlog 日志在发送端压缩,接收端解压,以提高传输效率。

  1. 功能实现: 添加控制 xlog 压缩启停的 guc 参数 enable_wal_shipping_compression,描述如下:

enable_wal_shipping_compression

参数说明:在流式容灾模式下设置启动跨集群日志压缩功能。

该参数属于 SIGHUP 类型参数。

取值范围:布尔型

该参数仅作用于跨集群传输的一对 walsender 与 walreceiver 中,作用于主集群 DN。

默认值:false

添加日志类型 type 'C' 用于表示被压缩的 wal 类型,在处理前会执行解压操作。

采用了已在 Gauss 库中的 lz4 无损压缩算法进行日志压缩,使用默认压缩级别 LZ4_compress_default (),具体实现如下:

日志发送方的 Walsender.cpp:

XLogSendPhysical () 中,在 XLogRead () 函数将数据传入 t_thrd.walsender_cxt.output_xlog_message 前先进行压缩,并更改类型表示为 'C',之后将压缩后的数据传入 output_xlog_message,同时更改 pq_putmessage_noblock 中数据长度为压缩后的大小。

日志接收方的 walreceiver.cpp:

XLogWalRcvProcessMsg () 中,type='C' 时,将 buf 中的数据先进行解压,用解压后的 decompressBuf 继续之后的逻辑。 为了减少 cpu 在压缩 / 解压上的性能损失,仅对异地容灾的流式复制开启压缩功能,集群内的流式复制不开启压缩功能。

  1. 压缩率

在流式容灾集中式场景开发环境自测中,使用 8 核虚拟机 tpcc 50 仓 64 并发进行 tpcc 测试,带宽充足场景下,tpcc 执行中测得 xlog 压缩率平均在 64.8% 左右。

异地容灾的流控机制

流式容灾在集中式场景已经添加了流控参数,描述如下:

hadr_recovery_time_target

参数说明:在流式容灾模式下设置 hadr_recovery_time_target 能够让备集群完成日志写入和回放。

该参数属于 SIGHUP 类型参数。

取值范围:整型,0~3600 (秒)

0 是指不开启日志流控,1~3600 是指备机能够在 hadr_recovery_time_target 时间内完成日志的写入和回放,可以保证主集群与备集群切换时能够在 hadr_recovery_time_target 秒完成日志写入和回放,保证备集群能够快速升主。hadr_recovery_time_target 设置时间过小会影响主机的性能,设置过大会失去流控效果。

默认值:0

hadr_recovery_point_target

参数说明:在流式容灾模式下设置 hadr_recovery_point_target 能够让备集群完成日志刷盘的 rpo 时间。

该参数属于 SIGHUP 类型参数。

取值范围:整型,0~3600 (秒)

0 是指不开启日志流控,1~3600 是指备机能够在 hadr_recovery_point_target 时间内完成日志的刷盘,可以保证主集群与备集群切换时日志差距能够在 hadr_recovery_point_target 秒内,保障备集群升主日志量。hadr_recovery_point_target 设置时间过小会影响主机的性能,设置过大会失去流控效果。

默认值:0

这两个参数在客户对于异地容灾 RPO,RTO 有强烈需求的情况下,可以进行配置用于保证在任何时刻 RPO,RTO 都能达到客户要求。在分布式部署场景下,打开流控,流控机制会在分片级别上生效。

比如 RPO 目标是 10s,hadr_recovery_point_target 可配置为 10s,超过这个值的时候,流控生效,会对主集群日志写入速率进行反压,降低业务性能来保证 RPO 达标。

比如 RTO 目标是 10min,hadr_recovery_time_target 可以配置 60s,超过这个值的时候,流控生效,会对日志写入速率进行反压,降低业务性能来保证 RTO 达标。这里 hadr_recovery_time_target 控制灾备升主期间日志回放的耗时,是整个灾备集群升主流程耗时的一部分。

针对异地容灾的 RPO 需求,新增了 RPO 流控与原有的 RTO 流控共同作用,对应修改了系统视图 global_streaming_hadr_rto_and_rpo_stat 与 gs_hadr_local_rto_and_rpo_stat 中的 current_sleep_time 列为 rto_sleep_time 和 rpo_sleep_time。

global_streaming_hadr_rto_and_rpo_stat 参数说明: 

 gs_hadr_local_rto_and_rpo_stat 参数说明: 

集中式场景流控逻辑 rto 计算逻辑是:

通过备机每次返回的最新落盘、回放 lsn,计算备机日志落盘和回放的速度,估算当前备机所有已接收日志全部完成落盘、回放需要的时间,作为 RTO。

rpo 计算逻辑是:

通过主机新生成日志的速度,结合主备落盘日志量差值,估算当前主备日志差相当于主机多少秒的新增,作为 RPO。

分布式场景流控逻辑

在分布式流式容灾中,为了保证分布式一致性采用全局一致性打点,对备机回放做了限制,即每个节点回放到全局 targetBarrier 点后会停止回放,等待下一个 targetBarrier 更新。

而灾备集群升主时,targetBarrier 后的日志会被丢弃,因此不能与普通集群一样按 flush 点计算 RTO/RPO

RTO 新增逻辑是:

在集中式逻辑的基础上,因为灾备集群升主时,targetBarrier 后的日志会被丢弃,所以当节点日志回放到 targetBarrier 后即可视为回放完成,RTO=0。

灾备集群各节点会将当前是否回放到 targetBarrier 点,返回给对应的主集群节点,标记此时 rto=0。

RPO 计算逻辑是:

由于 targetBarrier 后的日志灾备升主时会被丢弃,所以应该以备机 targetBarrier 点与主机最新日志计算 RPO。

barrierId 的最后 13 位为其生成时的时间信息,RPO 算法利用这个时间戳,由灾备返回 targetBarrierID,与主机最新生成的 currentBarrierID 比较,时间差即是灾备升主时丢失日志的时间长度。

周期性全局一致性打点与推进

图 barrier 处理消息序列图

消息序列图说明

如上图所示是一个 barrier 点从生成到删除的整个过程,大致可以分为四个部分:barrier 生成、barrier 解析存储、barrier 推进、barrier 删除。其中 barrier 推进是最重要的一环,有它来确定各备节点恢复的位置来达到一致性要求。

详细设计 Barrier 生成

Barrier 生成是 Barrier 一致性的前提。Barrier 点任一 CN 都可以发起,但由第一个 CN 负责生成。若发起 barrier 生成的 CN 不是第一个 CN,则通知第一个 CN 进行生成。生成后 CN 与 DN 将其落到 xlog 日志中。

负责打点的 CN 会启动 barrier_crearor 线程从 GTM 获取 CSN,来生成 barrier,格式如下: 生成的 CSN 类型 barrier 信息格式为 "csn_%021lu_%013ld",头部信息固定为 csn_,中间 21 位为得到的 csn 号,最后 13 位为时间信息,当前仅用于 RPO 计算。

Barrier 解析存储

Barrier 解析存储是 Barrier 一致性的基础,备集群上对应的备节点通过 walreciever 收到 xlog 日志后,将日志落盘。通过新添加 barrier 解析线程对新落盘的日志进行预解析,并将解析到的 barrier 存储在 hash table 中,并保存当前收到的最大 barrier。Hash table 在创建日志解析线程前进行创建,在集群卸载时进行释放。Hash table 中储存着解析出来的 barrier,这些 barrier 将在回放 xlog 日志时进行删除。

Barrier 推进

Barrier 解析存储是 Barrier 一致性的关键,这部分稍微复杂一些,需要 CN、DN、CMA、CMS、ETCD 相互配合进行。barrier 一致性点的推进需要五步:

CMA 通过 sql 函数查询 CN、DN 的 barrier 最大值上报至 CMS。此处的 barrier 为预解析结果,日志实际还未回放;

CMS 通过收齐各个实例上报的 barrier,将其中的最小值作为 query barrier;

CMA 从 CMS 获取到 query barrier,调用 sql 函数对 CN、DN 进行查询,确认是否存在该 barrier 点,将结果上报给 CMS。CMS 收齐后判断,若该 query barrier 已达到多数派条件,则作为 target barrier 点,否则舍弃;

CMA 读取 CMS 里存放的 target barrier,更新 CMA 本地的 target barrier;

CMA 通过 sql 函数设置 CN,DN 实例的 recovery barrier 设置为 targer barrier。

在一次上报中,CMA 需要查询执行 barrier 最大值的上报、本地查询 querybarrier 是否存在,更新 targetbarrier 这三步;CMS 需要执行 querybarrier 的更新和 targetbarrier 的更新。

其他说明:

Querybarrier 达到多数派成为 target barrier 的条件。 单一 DN 分片内多数派已上报该 barrier。 所有 DN 分片都已上报该 barrier。 CN 多数派已经上报该 barrier。

CN 多数派数目动态调整策略:由于主集群允许 cn 剔除到只有一个 cn,所以在故障场景下 cn 多数派的数目要随时调整,策略为:

CN 多数派初始值为 n_cn=init_cn_number/2 +1。 当发现 barrier 在 1 分钟内因为达不成 cn 多数派无法推进,n_cn--;极限值 n_cn>=1。 当发现 barrier 可以有大于 n_cn 个数的 cn 参与推进 barrier,n_cn++;极限值 n_cn<=init_cn_number/2 +1。

灾备集群 CN 不同状态参与 barrier 推进的情况

容灾过程中灾备集群中被 Deleted,building 的 CN 对 CM 的 barrier 查询请求不会有响应。 由于灾备集群 CN 发生 build 导致 barrier 超前推进,它处于等待其他 CN 的 waiting 状态,或者容灾过程中灾备集群中处于 need repair 态的 CN 是有可能查到 CM 请求的 barrier 的,会参与 barrier 推进。

灾备集群 CN 处于 waiting 状态的条件

改造基于 OBS 异地容灾方案中增加的 sql 函数 gs_get_local_barrier_status () 查询得到当前 CN 实例 redo 的 barrier。CM 通过该函数获得 CN 实例当前 redo 的 localbarrier,与 targetbarrier 进行比较,localbarrier>targetbarrier 时,该 CN 置为 waiting 状态。该状态与 CN 其他状态的转化参见《3.3.6.3 容灾过程中灾备故障 CN 的处理》。

Barrier 删除

Barrier 删除是 barrier 一致性的终点,Barrier 删除发生在 xlog 日志回放中,在日志回放时,回放到 barrier 会对回放位置 recoverybarrier 进行更新,并在 hash table 将该 barrier 点删除,完成 barrier 从生成到删除的全过程。

  • END -
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值