HBase系列(三)、读写原理,Flush刷写,HFile Compact合并,Region Split切分

【HBase-读写流程】HBase的读写流程与内部执行机制 1、客户端发起写入数据的请求,然后首先要连接 zookeeper,通过 zookeeper 去找到 HBase 中的 meta 文件对应的 region 所对应的 regionserver 的地址,连接 meta 文件所在的 regionserver,通过要写入数据的 rowkey,找到 rowkey 对应的 region(底层是根据 region 的范围去寻找的),然后找到 region 对应的 regionserver 的地址。 阅读详情

目录

写原理

读原理

Flush流程

HFile合并流程

Region拆分流程

数据删除时间


HBase系列:


写原理

客户端请求HBase写请求(PUT,DELETE)流程如下:

  1. Client 先访问ZK中的/hbase/meta-region-server 这个Znode,获取 hbase:meta 表所在的RegionServer;
  2. ZK返回META表所在的RS01信息;
  3. Client 访问META所在的RS01,查询hbase:meta;
  4. RS01将HBase元数据信息meta返回给客户端;
  5. Client 将得到的元数据信息进行缓存,之后再有读取请求时可以免去步骤1~5节约时间和资源;
  6. Client 向目标表所在的RS02发送写请求(PUT/DELETE);
  7. RS02将数据顺序追加到WAL(HLog)内;
  8. RS02将数据写入对应的Region内的MemStore,数据会在MemStore 进行排序;
  9. RS02向Client 返回应答信息完成写操作;
  10. 当满足Flush策略时,memstore内的数据会被刷写至HFile内;

读原理

客户端请求HBase读请求(GET)流程如下: 前面1~5步骤和写请求一样。

  1. Client 先访问ZK中的/hbase/meta-region-server 这个Znode,获取 hbase:meta 表所在的RegionServer;
  2. ZK返回META表所在的RS01信息;
  3. Client 访问META所在的RS01,查询hbase:meta;
  4. RS01将HBase元数据信息meta返回给客户端;
  5. Client 将得到的元数据信息进行缓存,之后再有读取请求时可以免去步骤1~5节约时间和资源;
  6. Client 向目标表所在的RS02发送读请求(GET);
  7. 从BlockCache(块缓存),MemStore 和 StoreFile(HFile)中查询目标数据,然后根据RowKey和时间戳进行数据合并;
  8. 将从StoreFile(HFile)中读到的数据缓存到BlockCache内供下次查询时使用,免去再次读取文件的磁盘IO消耗;
  9. 将合并后的结果返回给客户端;

注意:

  • 这里并不是先读内存,如果内存没有该数据再读磁盘,而是同时查询内存(BlockCache,MemStore)以及磁盘(StoreFile)。这样做的原因是当相同的rowkey在StoreFile文件内的数据时间戳大于MemStore中的时间戳时,如果先读MemStore的话会给客户端返回一个旧的数据,因此需要同时读内存和磁盘里的数据,然后根据rowkey为主键,以timestamp为版本进行数据合并;
  • 同时,在读磁盘的时候会将磁盘中的HFile缓存到BlockCache内,这样的话在下一次访问该HFile时就可以先到BlockCache中拿了,如果BlockCache内没有该文件,再去StoreFile中取。这里不必担心万一缓存到BlockCache之后又修改了该rowkey的数据会不会与BlockCache内的数据不一致,因为当数据被修改之后再次读取时:
    • 如果在此期间没有触发flush,该数据会在MemStore内,下次读取数据时会将BlockCache和MemStore中的该rowkey的数据进行合并;
    • 如果在此期间触发了flush,新的数据会在StoreFile中另一个新的HFile内,此时客户端再次请求读该RowKey的数据时会同时访问BlockCache内的包含旧版本数据的HFile以及StoreFile中的新HFile进行数据合并,然后会再将新的HFile缓存至BlockCache;
  • 也即是说每次读HBase时,如果该数据不在内存中,都会产生一次磁盘IO,而写数据是直接追加写WAL和内存,因此HBase是写比读更快。

Flush流程

上面多次提到了Flush刷写机制,表示的就是将内存中的MemStore数据持久化到HDFS内,即可以避免内存压力过大又可以保证数据安全,我们知道一个Region内包含多个列族,即在同一个Region内的每个Store表示了不同的列族,而每次Flush都会将MemStore持久化到HDFS内的一个HFile中,因此一个Store的数据最终会落到很多HFile中。

MemStore触发Flush刷写的条件如下,基本上就是按时间和容量:

  1. 当Region内某个MemStore 的大小达到了参数( hbase.hregion.memstore.flush.size)的值(默认值 128M),该Region内所有 MemStore 都会刷写;
  2. 当MemStore 的大小达到了公式 [hbase.hregion.memstore.flush.size(默认128MB) * hbase.hregion.memstore.block.multiplier(默认4)] 时,会阻止继续往该MemStore中写数据;
  3. 当 RegionServer 中 MemStore 的总大小达到公式[java_heapsize * hbase.regionserver.global.memstore.size(默认值 0.4)*hbase.regionserver.global.memstore.size.lower.limit(默认值 0.95)] 时,Region会按照其所有MemStore 的大小顺序(由大到小)依次进行刷写。直到 该RegionServer 中所有 MemStore 的总大小减小到上述值以下。
  4. 当 RegionServer 中 MemStore 的总大小达到公式[java_heapsize * hbase.regionserver.global.memstore.size(默认值 0.4)] 时,会阻止继续往该RegionServer 中所有MemStore中写数据;
  5. 通过配置参数(hbase.regionserver.optionalcacheflushinterval)进行自动刷写(默认 1 小时);
  6. 当 WAL 文件的数量超过最大数量 hbase.regionserver.max.logs,region 会按照时间顺序依次进行刷写,直到 WAL 文件数量减小到 hbase.regionserver.max.log 以下(该属性名已经废弃,现无需手动设置,默认值为 32)。

HFile合并流程

由于MemStore 每次刷写都会生成一个新的HFile,且同一个字段的不同版本(timestamp)和不同类型(Put/Delete)有可能会分布在不同的 HFile 中,因此查询时需要遍历很多 HFile文件。为了减少 HFile 的个数,以及清理掉过期和删除的数据,HBase会对StoreFile 进行Compaction(合并)。

Compaction 分为两种:

  • Minor Compaction:将临近的若干个较小的 HFile 合并成一个较大的 HFile,但不会清理过期和删除的数据;minor的过程一般较快,而且IO相对较低。当HFile数量达到参数(minFilesToCompact,默认3个)最低标准时,此命令才会触发,否则忽略本次操作。当待合并的HFile大小超过参数(maxCompactSize)时会将多的文件过滤掉不进行合并。
  • Major Compaction:将一个 Store 下的所有的 HFile 合并成一个大 HFile,并且会清理掉过期和删除的数据;由于此合并策略影响读写性能,因此一般在生产环境中,都会禁用major自动合并操作(参数hbase.hregion.majorcompaction设为0,默认是7天),只在空闲的时段手动或定时执行;

HBase会将队列中的HFile 按照文件年龄排序(older to younger),Minor Compaction总是从older HFile 开始选择,然后将选择出来的HFiles进行Minor Compaction:

  1. 如果该文件小于hbase.hstore.compaction.min.size(为memestoreFlushSize)则一定会被添加到合并队列中。
  2. 如果该文件大于hbase.hstore.compaction.max.size(Long.MAX_VALUE)则一定会被排除,这个值很大,一般不会有。
  3. 如果该文件的大小 小于它后面hbase.hstore.compaction.max(默认为10) 个HFile 的大小之和乘以一个ratio(配置项是hbase.hstore.compaction.ratio,默认为1.2),则该HFile 也将加入到minor compaction 中。如果他后面不足10个文件,那么也就是取他后面几个文件总和*ratio。

相关参数:

参数名配置项

默认值

含义
minFileToCompacthbase.hstore.compactionThreshold3最低合并HFile数量
maxFileToCompacthbase.hstore.compaction.max10最大合并HFile数量
minCompactSizehbase.hstore.compaction.min.sizememstoreFlushSize最小合并HFile文件大小
maxCompactSizehbase.hstore.compaction.max.sizeLong.MAX_VALUE最大合并HFile文件大小
majorCompactionhbase.hregion.majorcompaction7天

自动触发Major 间隔时间

Region拆分流程

默认情况下,每个 Table 起初只有一个 Region,随着数据的不断写入,Region 会越来越大然后自动进行拆分(Split)。刚拆分时,两个子 Region 都位于当前的 RegionServer,但出于负载均衡的考虑,HMaster 有可能会将某个 Region 转移给其他的 RegionServer。 

Region 拆分时机:

  1. 当1个region中的某个Store下所有StoreFile的总大小超过hbase.hregion.max.filesize(默认10GB),该 Region 就会进行拆分(0.94 版本之前)。
  2. 当1个region 中的某个 Store 下所有 StoreFile 的总大小超过公式Min(R^2 * "hbase.hregion.memstore.flush.size(默认128MB)",hbase.hregion.max.filesize(默认10GB)"),该 Region 就会进行拆分,其中 R 为当前 RegionServer 中属于该 Table 的Region个数(0.94 版本之后)。

可以看出,在新版之后,Region的拆分条件会默认从128MB不断的变大一直到10GB,这样就会导致某个表的不同Region内的数据不均衡的情况,因此在实际应用中都会提前设置预分区以及RowKey优化,避免因自动拆分导致的数据倾斜的情况。  

数据删除时间

当HBase中执行PUT修改相同RowKey的数据或者执行DELETE删除RowKey的数据时,我们可以通过命令查看到历史版本,那么什么时候这些过期数据和删除数据才会被删除呢?

其实失效数据在Flush和Compact都会被删除,但它们实现的地方不一样:

  • Flush刷写时:
    • Flush将MemStore内的数据进行合并然后去除小于该列族设置的VERSION号以前的数据,将剩余数据持久化到HFile;
    • 当执行DELETE时,Flush操作不会删掉MemStore里的该删除标记记录,只会删掉MemStore内该RowKey的在该删除标记操作的timestamp之前的操作,原因是可能在之前已持久化到HFile物理文件中也有该RowKey记录的历史版本,如果把内存里的删除标记也删除的话,再次查询就会将物理文件中的历史版本查出来,这样就不对了,因此Flush不会删除MemStore内的删除标记记录。
  • Compact合并时:
    • Compact命令会真正将内存和磁盘上的文件进行merge,去除小于该列族设置的VERSION号以前的数据,将剩余数据合并为一个新的HFile;

 

希望本文对你有帮助,请点个赞鼓励一下作者吧~ 谢谢! 

【信息科学与工程学】【数据科学】第一百二十二篇 大数据产品中的函数与算法01 它通常指。下面按照你给出的表格列💡 说明:下表中的"产品"以开源/主流商业组件为具象载体(Hadoop、Spark、Flink、Kafka、Hive、HBase、Iceberg、Atlas、Ranger、TensorFlow 等),它们共同构成一个完整的大数据产品家族;代码为实现示例,用于说明算法在工程系统中的落地方式。 阅读详情

相关推荐

UE4-(IK)实现人物脚贴合地面解决斜坡上脚无旋转无法贴合地面问题

在斜面上脚陷入模型中,需要设置旋转值对脚的骨骼进行一个旋转。 解决思路:在射线检测中可以获取到检测点的法线方向,根据法线方向来计算出脚应该向哪个方向进行适当的旋转,在斜坡上,人物脚需要旋转的轴为x轴和y轴以便来贴合地面,z轴方向的旋转是不需要进行修改的。 如图所示,我们需要求得水平面与斜坡的夹角用来得出人物在x轴上的脚旋转量,在蓝图中提供反正切函数,反正切 = 锐角的邻边/对边 所以 反正切值(脚x轴值(roll)) = 法线Y轴值/法线Z轴 值。 现在将上图的人物想象成面向屏幕,脚需...

Stone的博客 3317

HBase2.x(十二)HBase 文件合并机制

MinorCompaction会将临近的若干个较小的 HFile 合并成一个较大的 HFile,并清理掉部分过期和删除的数据,有系统使用一组参数自动控制,Major Compaction 会将一个 Store 下的所有的 HFile 合并成一个大 HFile,并且会清理掉所有过期和删除的数据,由参数 hbase.hregion.majorcompaction控制,默认 7 天。(2)hbase.hstore.compaction.min(默认 3) 为 Minor Compaction 的最少文件个数。

weixin_45417821的博客 1579

二次规划问题(qp)和序列二次规划问题(sqp)的简单理解

当二次规划的约束为非线性约束时,通常会采用sqp进行求解,用连续求解qp的方法来得到非线性约束条件下的最优解,上述的qpoases和osqp均无法直接求解非线性约束问题,所以如果使用这两个库的话,注意,sqp是结果,而不是原因,只有在非线性约束的情况下才会考虑sqp求解,如果问题本身就是线性约束,则直接用qp解就行。对于工程师而言,我们在编写代码的时候,并不关心二次规划问题的求解细节,所以一般是把二次规划问题建立好后,直接调用三方库进行求解。因为约束为非线性约束,所以先将约束进行线性化,约束原方程为。

zmhzmhzm的博客 1万+

HBase学习笔记(四)——HBase的flush、compact机制

在HBase中数据被写入 WAL 和 MemStore 后就可以说数据已经被成功写入到 Hbase 了。MemStore 中的数据达到一定的阈值,会被 Flush 成 HDFS 中的 HFile 文件。但是随着 Flush 次数的不断增多,HFile 的文件数量也会不断增多。从多个 HFile 文件中读取记录,将导致更多的 IOPS,这会使得读取时延不断增大。 Compaction 可以将一些 HFile 文件合并成为较大的 HFile 文件,也可以把所有的 HFile 文件合并成为一个大的 HFi

u011047968的专栏 2401

足球赛事数据API:开发者生存指南(附真实踩坑记录)

作为一个既爱看球又爱写代码的老宅男,我这些年用过的足球API比看过的比赛还多。从最初被各种API文档折磨到怀疑人生,到现在能闭着眼睛调接口,中间的血泪史够写本书了。今天就把这些经验(和教训)分享给各位同好,特别是那些正在为"老板要做个足球App"而秃头的同行们。文档清晰免费层可用响应格式规范API-Sports免费额度大方支持GraphQL有中文文档(难得!Sportmonks数据全面有Webhook支持按需付费。

Happy0970的博客 2192

【LTspice】005 伯德图绘制

目录 1 伯德图介绍 2 LTspice 截止频率验证 3 LTspice中如何添加光标 4 LTspice中如何将 幅频 和 相频曲线分开 1 伯德图介绍 Bode图由对数幅频特性和对数相频特性两张图组成。伯德图_百度百科 (1)对数幅频特性曲线 对数幅频特性是频率特性的对数值L(ω)=20lgA (ω)(dB)与频率ω的关系曲线;对数幅频特性的纵轴采用线性分度,为幅值的分贝数,即 L(ω)=20lgA(ω),A(ω)每增加10倍,L(ω)增加20dB;横坐标采用对数分度,即横轴上的ω取

m0_59642765的博客 1万+

HBase Region管理(拆分+合并+负载均衡)

每个 RegionServer 包含多个 Region,而每个 Region 又对应多个 Store,每一个 Store 对应表中一个列族的存储,且每个 Store 由一个 MemStore 和多个 StoreFile 文件组成。StoreFile 在底层文件系统中由 HFile 实现,也可以把 Store 看作由一个 MemStore 和多个 HFile 文件组成。...

因上努力,果上随缘。但行好事,莫问前程。 2398

用STM32F407做个USB声卡:从CubeMX配置到播放录音全功能实战(附源码)

本文详细介绍了如何使用STM32F407开发板实现USB音频设备的全功能实战,包括CubeMX配置、硬件连接、音频流处理和性能优化。通过双缓冲DMA机制和音频数据处理流程,开发者可以构建高质量的USB声卡系统,适用于录音和播放场景。附源码,助力快速上手STM32音频开发。

weixin_30301449的博客 516

HBase篇(6)-HFile合并过程详解

简单地说Compaction 合并是指一个 region 的一个 store 中的一些 HFile 合为一个 HFile 的操作。过程是先从这些待合并的数据文件中读出 KeyValues...

wujiandao的专栏 2992

数字IC后端设计实现 | PR工具中到底应该如何控制density和congestion?(ICC2&Innovus)

数字IC后端设计实现中到底应该如何控制cell density和congestion?(ICC2和Innovus两种解决方案)

weixin_37584728的博客 7113

Altium Designer(AD24)导入DDB库文件(Protel 99SE)方法

Altium Designer和Protel均为Altium公司开发的软件。本文介绍Altium Designer 24软件导入DDB库文件(Protel 99SE)方法。

fydar的博客 1981

Apache HBase 三个重要机制 Flush Compact Split

Flush机制 1.(hbase.regionserver.global.memstore.size)默认;堆大小的40% regionServer的全局memstore的大小,超过该大小会触发flush到磁盘的操作,默认是堆大小的40%, 而且regionserver级别的flush会阻塞客户端读写 2.(hbase.hregion.memstore.flush.size)默认:128M 单个r...

大数据流浪法师的学习笔记与分享 642

vue2 - elementUI表格table树形结构复选框勾选父子联动示例,el-table树状表格tree复选框checkbox多选框全选/反选取消children(当子级全选中,父级自动勾选)

vue2,elementui,el-table树状表格多选,树形结构结合多选框使用,实现单选父子联动全选反选,勾选联动父级勾选,表格多选check父子联动,table表格children如何嵌入复选框,el-table使用多选框与树形数据写一个有半选全选功能的表格,el-table树形表格实现复选框多选效果,表格树状结构多选,每一个row都可以选中并且联动全选按钮,table选父带子选子带父,树形数据与懒加载,Table表格树形结构多选框选中父级时会选中子级,elementUI表格里树形结构嵌套复选框全选全

✅ 精选推荐文章 1万+

【HBase】HBase入门详解(五)

(图片来源于网络,侵删) 一、Master、RegionServer的上下线以及Region的管理 Master上线 1) 从Zookeeper上获取唯一一个代表Active Master的锁,用来阻止其他Master成为真正的Master 2) 扫描Zookeeper上的/hbase/rs节点,获取当前可用的Region server列表 3) 和每个RegionServer通信,获得当...

Together 4441

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

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

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

Hbase三个重要机制

Hbase三个重要机制 文章目录Hbase三个重要机制1、flush机制2、compact机制3、split机制 1、flush机制 1.(hbase.regionserver.global.memstore.size)默认;堆大小的40% regionServer的全局memstore的大小,超过该大小会触发flush到磁盘的操作,默认是堆大小的40%,而且regionserver级别的flu...

Mr_Yang888的博客 1万+

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

Hbase compact以及split跟踪

  2017年06月30日 10:13:48 tom_fans 阅读数:847 版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.youkuaiyun.com/tom_fans/article/details/73937375 为了准确了解HBASE内部工作原理,我们需要做一些测试,在大量数据插入的情况下,HBASE内部到底有什么表现?  比如插入速度,  hstore c...

大JAVA解决方案 417

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

HBase三个重要机制

1、flush机制 1.(hbase.regionserver.global.memstore.size)默认;堆大小的40% regionServer的全局memstore的大小,超过该大小会触发flush到磁盘的操作,默认是堆大小的40%,而且regionserver级别的flush会阻塞客户端读写 2.(hbase.hregion.memstore.flush.size)默认:128M 单个...

weixin_44361667的博客 245

hbase的hfile compaction 以及region的split

hfile compaction 由于memstore每次刷写都会生成一个新的HFile,且同一个字段的不同版本(timestamp)和不同类型(Put/Delete)有可能会分布在不同的HFile中,因此查询时需要遍历所有的HFile。为了减少HFile的个数,以及清理掉过期和删除的数据,会进行StoreFile Compaction。 Compaction分为两种,分别是Minor Compa...

sghuu的博客 538

深入理解 HBase Compaction 机制

HBase有很多话题可以聊,包括读写路径上涉及到的一些数据结构,性能优化以及优化读写做的一些设计等。今天要探讨的Compaction机制就是HBase架构上做的一个重要优化!

Focus on Lakehouse 1万+

HBase的架构和原理(四)--MemStore的Flush动作和HFile的Compaction机制

Hbase中MemStore的Flush动作和HFile的Compaction机制

weixin_37536020的博客 423

hbase-memstore flush剖析

memstore是hbase中一个非常重要的组件,对于hbase的读写操作的性能起到举足轻重的作用,下面讲从memstore概述、memstore flush触发条件、memstore flush流程、memstore flush流程源码四个方面对memstore进行说明 memstore概述 一个RegionServer上对应多个Region,一个Region对应多个Store,一个Store对应一个Memstore和多个HFile,几者之间的关系如下图 Regionserve...

zfs_sir的博客 507

HBase MemStore flush执行流程

前言 上一篇博客中(https://blog.youkuaiyun.com/qq_35542970/article/details/109390109),我们分析了memstore flush的几种触发条件,从中可以看出HBase将需要flush的请求存放于MemStoreFlusher中定义的flushQueue中。那么队列中的flush请求又是如何处理的呢? 1、flush队列的处理 1.1、flush请求队列的处理流程: 以put等操作触发的flush为例,流程如下: (图片来自链接https://blog.cs

qq_35542970的博客 752

memstore的flush流程分析

memstore的flush流程分析 memstore的flush发起主要从以下几个地方进行:  a.在HRegionServer调用multi进行更新时,检查是否超过全局的memstore配置的最大值与最小值,    如果是,发起一个WakeupFlushThread的flush请求,如果超过全局memory的最大值,需要等待flush完成。  b.在HRegionServer进行数据...

隔壁老杨的专栏 350

HFile的合并

一.之前说到了BlockBache的优化以及MemStore的优化 这篇文章主要介绍一下HFIle的合并 我们首先要明白的是,为什么HFile要进行合并? 1.StoreFile是HFile的抽象,MemStore的每一次刷写都会产生一个HFile,如果HFile数量过多会产生什么问题?读取速度下降,因为读取数据涉及到一个操作:寻址 如果是传统硬盘那就是磁头的移动。 寻址,这是一个很慢的动作。当H...

qq_38304320的博客 1595

Region使用全解

代码地址如下:http://www.demodashi.com/demo/14799.html ####前言 Region,即为区域,它表示的是canvas图层上的某一块封闭的区域。很多时候,我们会利用Region来构造一个图形。 今天要讲的内容有: Region的直接构造方法 Region的间接构造方法 Region的setPath(Path path, Region clip)方法介绍 ...

findhappy117的博客 1万+

hbase的写和读,大合并和小合并

hbase写: 客户端向hbase服务器端发送写的请求时,hbase会同时进行两个动作,把记录写在WAL(write ahead log)日志文件中,每台服务器所有表都共享这个WAL文件。然后会写到memStore内存中,memStore是内存中的写入缓存区,如果memStore写满就刷新写到硬盘,生成HFile文件。当服务器宕机时memStore内存中的内容就没了,这时可以通过回放WAL日志文件

share_free的博客 9006
上一篇: HBase系列(二)、架构原理
下一篇: HBase系列(四)、HBase优化之RowKey 设计
王义凯_Rick
王义凯_Rick 领域专家: 大数据技术领域 领域专家: 大数据技术领域
博客等级 码龄14年 858粉丝 162原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

打赏作者

王义凯_Rick

遇见即是缘,路过就给个评论吧~

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

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

打赏作者

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

抵扣说明:

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

余额充值