分库分表会带来读扩散问题?怎么解决?

啥?分库分表会带来读扩散问题?怎么解决??? mysql在单表数据过大时,查询性能会变差,因此当数据量变得巨大时,需要考虑水平分表。水平分表需要选定一个分片键,一般选择主键,然后根据id进行取模,或者根据id的范围进行分表。mysql水平分表后,对于非分片键字段的查询会有读扩散的问题,可以用普通索引列作分片键建一个新表,先查新表拿到id后再回到原表再查一次原表。这本质上是借鉴了倒排索引的思路。如果想要支持更多维度的查询,可以监听mysql的binlog,将数据写入到es,提供近实时的查询能力。当然,用tidb替换mysql也是个思路。...... 阅读详情

今天这篇文章,其实也是我曾经面试中遇到过的真题。

分库分表大家可能听得多了,但读扩散问题大家了解吗?

这里涉及到几个问题。

分库分表是什么?

读扩散问题是什么?

分库分表为什么会引发读扩散问题?

怎么解决读扩散问题?

能不能不要在评论区叫我刁毛?

图片

不好意思,失态了。

这些问题还是比较有意思的。

相信兄弟们也一定有机会遇到哈哈哈。

我们先从分库分表的话题聊起吧。

分库分表

我们平时做项目开发。一开始,通常都先用一张数据表,而一般来说数据表写到2kw条数据之后,底层B+树的层级结构就可能会变高,不同层级的数据页一般都放在磁盘里不同的地方,换言之,磁盘IO就会增多,带来的便是查询性能变差。如果对上面这句话有疑惑的话,可以去看下我之前写的文章。

于是,当我们单表需要管理的数据变得越来越多,就不得不考虑数据库分表。而这里的分表,分为水平分表和垂直分表。

垂直分表的原理比较简单,一般就是把某几列拆成一个新表,这样单行数据就会变小,B+树里的单个数据页(固定16kb)内能放入的行数就会变多,从而使单表能放入更多的数据。

垂直分表没有太多可以说的点。下面,我们重点说说最常见的水平分表。

水平分表有好几种做法,但不管是哪种,本质上都是将原来的 user 表,变成 user_0, user1, user2 .... uerN这样的N多张小表。

从读写一张user大表,变成读写 user_1 … userN 这样的N张小表。

图片

分表

每一张小表里,只保存一部分数据,但具体保存多少,这个自己定,一般就订个500w~2kw。

那分表具体怎么做?

根据id范围分表

我认为最好用的,是根据id范围进行分表。

我们假设每张分表能放2kw行数据。那user0就放主键id为1~2kw的数据。user1就放id为2kw+1 ~ 4kw,user2就放id为4kw+1 ~ 6kw, userN就放 2N kw+1 ~ 2(N+1)kw。

图片

根据id范围分表

假设现在有条数据,id=3kw,将这个3kw除2kw = 1.5,向下取整得到1,那就可以得到这条数据属于user1表。于是去读写user1表就行了。这就完成了数据的路由逻辑,我们把这部分逻辑封装起来,放在数据库和业务代码之间。

这样。对于业务代码来说,它只知道自己在读写一张 user 表,根本不知道底下还分了那么多张小表。

对于数据库来说,它并不知道自己被分表了,它只知道有那么几张表,正好名字长得比较像而已。

这还只是在一个数据库里做分表,如果范围再搞大点,还能在多个数据库里做分表,这就是所谓的分库分表。

不管是单库分表还是分库分表,都可以通过这样一个中间层逻辑做路由。

还真的就应了那句话,没有什么是加中间层不能解决的。

如果有,就多加一层。

至于这个中间层的实现方式就更灵活了,它既可以像第三方orm库那样加在业务代码中。

图片

通过orm读写分表

也可以在mysql和业务代码之间加个proxy服务。

如果是通过第三方orm库的方式来做的话,那需要根据不同语言实现不同的代码库,所以不少厂都选择后者加个proxy的方式,这样就不需要关心上游服务用的是什么语言。

图片

通过proxy管理分表

根据id取模分表

这时候就有兄弟要提出问题了,“我看很多方案都对id取模,你这个方案是不是不完整?”。

取模的方案也是很常见的。

比如一个id=31进来,我们一共分了5张表,分别是user0到user4。对31%5=1,取模得1,于是就能知道应该读写user1表。

图片

根据id取模分表

优点当然是比较简单。而且读写数据都可以很均匀的分摊到每个分表上。

但缺点也比较明显,如果想要扩展表的个数,比如从5张表变成8张表。那同样还是id=31的数据,31%8 = 7,就需要读写user7这张表。跟原来就对不上了。

这就需要考虑数据迁移的问题。很头秃。

为了避免后续扩展的问题,我见过一些业务一开始就将数据预估得很大,然后心一横,分成100张表,一张表如果存个2kw条,那也能存20亿数据了。

也不是说这样不行吧,就是这个业务直到最后放弃的时候,也就存了百万条数据,每次打开数据库表能看到茫茫多的user_xx,就是不太舒服,专业点,叫增加了程序员的心智负担。

而上面一种方式,根据id范围去分表,就能很好的解决这些问题,数据少的时候,表也少,随着数据增多,表会慢慢变多。而且这样表还可以无限扩展。

那是不是说取模的做法就用不上了呢?

也不是。

将上面两种方式结合起来

id取模的做法,最大的好处是,新写入的数据都是实实在在的分散到了多张表上。

而根据id范围去做分表,因为id是递增的,那新写入的数据一般都会落到某一张表上,如果你的业务场景写数据特别频繁,那这张表就会出现写热点的问题。

这时候就可以将id取模和id范围分表的方式结合起来。

我们可以在某个id范围里,引入取模的功能。比如 以前 2kw~4kw是user1表,现在可以在这个范围再分成5个表,也就是引入user1-0, user1-2到user1-4,在这5个表里取模。

举个例子,id=3kw,根据范围,会分到user1表,然后再进行取模 3kw % 5 = 0,也就是读写user1-0表。

这样就可以将写单表分摊为写多表。

这在分库的场景下优势会更明显,不同的库,可以把服务部署到不同的机器上,这样各个机器的性能都能被用起来。

图片

根据id范围分表后再取模

读扩散问题

我们上面提到的好几种分表方式,都用了id这一列作为分表的依据,这其实就是所谓的分片键。

实际上我们一般也是用的数据库主键作为分片键。

这样,理想情况下我们已知一个id,不管是根据哪种规则,我们都能很快定位到该读哪个分表。

但很多情况下,我们的查询又不是只查主键,如果我的数据库表有一列name,并且加了个普通索引。

这样我执行下面的sql

select * from user where name = "小白";

由于name并不是分片键,我们没法定位到具体要到哪个分表上去执行sql。

于是就会对所有分表都执行上面的sql,当然不会是串行执行sql,一般都是并发执行sql的。

如果我有100张表,就执行100次sql。

如果我有200张表,就执行200次sql。

随着我的表越来越多,次数会越来越多,这就是所谓的读扩散问题。

图片

读扩散问题

这是个比较有趣的问题,它确实是个问题,但大部分的业务不会去处理它,读100次怎么了,数据增长之后读的次数会不断增加又怎么了?但架不住我的业务不赚钱啊,也根本长不了那么多数据啊。

话是这么说没错,但面试官问你的时候,你得知道怎么处理啊。

引入新表来做分表

问题的核心在于,主键是分片键,而普通索引列并不分片。

那好办,我们单独建个新的分片表,这个新表里的列就只有旧表的主键id和普通索引列,而这次换普通索引列来做分片键。

图片

通过新索引表解决读扩散问题

这样当我们要查询普通索引列时,先到这个新的分片表里做一次查询,就能迅速定位到对应的主键id,然后再拿主键id去旧的分片表里查一次数据。这样就从原来漫无目的的全表扩散查询,缩减为只查固定几个表了。

举个例子。比如我的表原本长下面这样,其中id列是主键,同时也是分片键,name列是非主键索引。为了简化,假设三条数据一张表。

此时分表里 id=1,4,6 的都有name="小白" 的数据。

当我们执行 select * from user where name = "小白"; 则需要并发查3张表,随着表变多,查询次数会变得更多。

图片

举例说明读扩散问题

但如果我们为name列建个新表(nameX),以name为新的分片键。

这样我们可以先执行 select id from nameX where name = "小白";

再拿着结果里的ids去查询 select * from user where id in (ids); 这样就算表变多了,也可以迅速定位到某几张具体的表,减少了查询次数。

图片

举例说明通过新索引表解决读扩散问题

但这个做法的缺点也比较明显,你需要维护两套表,并且普通索引列更新时,要两张表同时进行更改。

有一定的开发量

有没有更简单的方案?

使用其他更合适的存储

我们常规的查询是通过id主键去查询对应的name列。而像上面的方案,则通过引入一个新表,倒过来,先用name查到对应的id,再拿id去获取具体的数据。这其实就像是建立了一个新的索引一样,像这种,通过name列反查原数据的思想,其实就很类似于倒排索引。

相当于我们是利用了倒排索引的思路去解决分表下的数据查询问题。

回想下,其实我们的原始需求无非就是在大量数据的场景下依然能提供普通索引列或其他更多维度的查询。

这种场合,更适合使用es,es天然分片,而且内部利用倒排索引的形式来加速数据查询。

哦?兄弟萌,又是它,倒排索引,又是个极小的细节,做好笔记。

图片

举个例子,我同样是一行数据 id,name,age。在mysql里,你得根据id分片,如果要支持name和age的查询,为了防止读扩散,你得分别再建一个name的分片表和一个age的分片表。

而如果你用es,它会在它内部以id分片键进行分片,同时还能建一个name到id,和一个age到id的倒排索引。这是不是就跟上面做的事情没啥区别。

而且将mysql接入es也非常简单,我们可以通过开源工具 canal 监听mysql的binlog日志变更,再将数据解析后写入es,这样es就能提供近实时的查询能力。

图片

mysql同步es

觉得es+mysql还是繁琐?有没有其他更简洁的方案?

有。

别用mysql了,改用tidb吧,相信大家多少也听说过这个名称,这是个分布式数据库。

它通过引入Range的概念进行数据表分片,比如第一个分片表的id在02kw,第二个分片表的id在2kw4kw。

哦?有没有很熟悉,这不就是文章开头提到的根据id范围进行数据库分表吗?

它支持普通索引,并且普通索引也是分片的,这是不是又跟上面提到的倒排索引方案很类似。

又是个极小的细节。

图片

并且tidb跟mysql的语法几乎一致,现在也有非常多现成的工具可以帮你把数据从mysql迁移到tidb。所以开发成本并不高。

图片

用tidb替换mysql

总结

  • mysql在单表数据过大时,查询性能会变差,因此当数据量变得巨大时,需要考虑水平分表。

  • 水平分表需要选定一个分片键,一般选择主键,然后根据id进行取模,或者根据id的范围进行分表。

  • mysql水平分表后,对于非分片键字段的查询会有读扩散的问题,可以用普通索引列作分片键建一个新表,先查新表拿到id后再回到原表再查一次原表。这本质上是借鉴了倒排索引的思路。

  • 如果想要支持更多维度的查询,可以监听mysql的binlog,将数据写入到es,提供近实时的查询能力。

  • 当然,用tidb替换mysql也是个思路。tidb属实是个好东西,不少厂都拿它换个皮贴个标,做成自己的自研数据库,非常推荐大家学习一波。

  • 不要做过早的优化,没事别上来就分100个表,很多时候真用不上。

参考资料

《图解分库分表》

https://mp.weixin.qq.com/s/OI5y4HMTuEZR1hoz9aOMxg

最后

当年我还在某个游戏项目组里做开发的时候,从企鹅那边挖来的策划信誓旦旦的说,我们要做的这款游戏老少皆宜,肯定是爆款。要做成全球同服。上线至少过亿注册,十万人同时在线。要好好规划和设计。

我们算了下,信他能有个1亿注册。用了id范围的方式进行分片,分了4张表。

搞得我热血沸腾。

那天晚上下班,夏蝉鸣泣,从赤道吹来的热风阵阵拂过我的手臂,我听着泽野弘之的歌,就算是开电瓶车,我都感觉自己像是在开高达。

一年后。

游戏上线前一天通知运维加机器,怕顶不住,要整夜关注。

后来上线了,全球最高在线人数58人。其中有7个是项目组成员。

还是夏天,还是同样的下班路,想哭,但我不能哭,因为骑电瓶车的时候擦眼泪不安全。


最近原创更文的阅读量稳步下跌,思前想后,夜里辗转反侧。

我有个不成熟的请求。

离开广东好长时间了,好久没人叫我靓仔了。

大家可以在评论区里,叫我一靓仔吗?

我这么善良质朴的愿望,能被满足吗?

如果实在叫不出口的话,能帮我点下右下角的点赞和在看吗?

别说了,一起在知识的海洋里呛水吧

关注公众号:【小白debug】

不满足于在留言区说骚话?

加我,我们建了个划水吹牛皮群,在群里,你可以跟你下次跳槽可能遇到的同事或面试官聊点有意思的话题。就超!开!心!
图片

文章推荐:

浅谈分库分表的“读扩散”问题 mysql在单表数据过大时,查询性能会变差,因此当数据量变得巨大时,需要考虑水平分表。水平分表需要选定一个分片键,一般选择主键,然后根据id进行取模,或者根据id的范围进行分表。mysql水平分表后,对于非分片键字段的查询会有读扩散的问题,可以用普通索引列作分片键建一个新表,先查新表拿到id后再回到原表再查一次原表。这本质上是借鉴了倒排索引的思路。如果想要支持更多维度的查询,可以监听mysql的binlog,将数据写入到es,提供近实时的查询能力。当然,用tidb替换mysql也是个思路。 阅读详情

相关推荐

面试官:分库分表有什么缺点,会带来什么问题?

分库分表 根据id范围分表 根据id取模分表 将上面两种方式结合起来 读扩散问题 引入新表来做分表 使用其他更合适的存储 总结

416

朋友圈微博feed流,推拉实践

上一篇《feed流拉取,读扩散,究竟是啥?》关于feed流的拉取还是推送,只写了一半“拉取”,今天把另一半“推送”(写扩散)的坑填完。为了对比“拉”“推”两种方案,同时也...

架构师之路 4956

feed流拉取,读扩散

优点: • 存储结构简单,数据存储量较小,关系数据与feed数据都只存一份 • 取消关注,发布feed的业务流程非常简单 • 存储结构,业务流程都比较容易理解,非常适合项目早期用户量、数据量、并发量不大时的快速实现 缺点也显而易见: • 拉取朋友圈feed流列表的业务流程非常复杂 • 有多次数据访问,并且要进行大量的内存计算,大量数据的网络传输,性能较低

什么是读扩散和写扩散

写扩散是指在分布式系统中,由于数据的复制和缓存等原因,当一条数据被更新后,需要将该数据的更新操作同步到多个节点中的副本,以保证数据的一致性。读扩散是指在分布式系统中,由于数据的复制和缓存等原因,当一条数据被更新后,在多个节点中都存在该数据的副本,这时候其他节点请求该数据时,可能会读取到过期的数据,因为该节点上的数据还未被更新。因此,读扩散就是指一条数据在更新后,由于分布式系统中数据的复制和缓存等原因,可能会导致其他节点上的数据过期,读取到过期数据的现象。

qq_30503389的博客 3310

Bioinformatics2021 | FraGAT+:基于分子原始片段的多尺度图注意力机制的分子性质预测模型

Bioinformatics2021 | FraGAT:基于分子原始片段的多尺度图注意力机制的分子性质预测模型

justBeHerHero 1999

用AI从0开始量化交易-制定学习计划安装学习环境

量化小白,利用AI从零开始学量化

weixin_52285994的博客 2112

架构设计-读扩散和写扩散

读扩散和写扩散

white_while的博客 1276

团结引擎+OpenHarmony 记录 (持续更新中)

获取不到的原因是因为二者不在同一个线程中,所以数据没有同步。而 globalThis.context 数据进行了同步。(TuanjieMainWorkerHandler.ts中可以看到)在进行绘制 UI 的时候 ,如果组件有 Native API 就可能不会显示出来,例如 web 控件就不能展示出来,刚加上权限的时候 会报错 因为缺少 reason ,添加上就不会报错了。只有纯 UI 控件是可以展示出来的,注释掉 web控件后就可以。

m_cainiaokuaifei的博客 1491

周末小技 | 开发一个Feeds流系统——写扩散模式

点个关注????跟腾讯工程师学技术导语 | 本文主要针对Feeds流进行介绍,将从Feeds流的演变入手,带你一步步了解Feeds流,而后学习如何从开发角度入手,对其进行建模,抽象出Feeds流常见的架构,最终搭建高可用、高扩展、高性能的Feeds流应用。了解Feeds流在学习如何开发Feeds流应用前,我们需要先了解什么是Feeds流。一、什么是Feeds流Feeds流是一个持续更新并展示给用户的信息...

QcloudCommunity的博客 1015

matebookego win11 arm 系统安装安卓子系统

一般的x86电脑如果安装android子系统,运行安卓子系统,由于要将android arm代码转译为x86代码,所以效率不一定高,但是如果电脑是arm架构的,通过安卓子系统运行android的程序执行效率就会 高不少,本文参考,都是在win11 home版本下的。两者跑分在cpu上差不太多了,大约是枭龙855的水平了,这个水平的子系统就有一定的实用性了,玩个一般游戏,刷个抖音都很流畅的。启动子系统后,点击左上角的设置,启用 “开发人员模式”。然后就可以再通运运行华为应用商店来进行安装其它应用了。

babytiger的专栏 1万+

使用PyTorch设计卷积神经网络(CNN)来处理遥感图像Indian Pines数据集

使用PyTorch设计卷积神经网络(CNN)来处理遥感图像Indian Pines数据集

XAX520_1314的博客 2490

来聊聊分库分表

为保证分库分表后数据能够被准确的定位并查询到,分表的策略也是很重要的,这里笔者列出几种比较常见的分表方案:range法hash法range+hash法进行分表后,对于「非partition key」的查询就由为的复杂,因为「非partition key」和没有任何关联如果没有采取任何措施的话,查询效率就会十分低下。最简单的例子就是上文600w那条数据,他记录着一个用户的个人信息,假如我们希望通过用户名定位到他又该如何做呢?很明显在没有任何措施的情况下,只能通过逐表遍历查询解决了。

竹林幽深 94

盲孔、埋孔、通孔、一阶HDI、二阶HDI概念

文章目录1. 盲孔和埋孔2. 一阶、二阶HDI3. PADS软件设置盲埋孔 1. 盲孔和埋孔 HDI板是高密度互连(High Density Interconnector)的缩写,是生产印制板的一种技术,使用微盲埋孔技术的一种线路分布密度比较高的电路板,也被称为盲埋孔板,下图就是一个6层HDI板,其中C和D就是盲孔,B是埋孔,A是通孔。 盲孔(Blind Via)指连接外层到内层的金属化孔,D是V13孔,连接顶层和第3层,C是V56孔,连接第5层和底层。 埋孔(Buried Via)指连接内层到内层的金属

记得诚 3万+

分库分表后的读扩散问题怎么解决?

作者简介:大家好,我是码炫码哥,前中兴通讯、美团架构师,现任某互联网公司CTO,兼职码炫课堂主讲源码系列专题代表作:《jdk源码&多线程&高并发》,《深入tomcat源码解析》,《深入netty源码解析》,《深入dubbo源码解析》,《深入springboot源码解析》,《深入spring源码解析》,《深入redis源码解析》等联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬。

smart_an的专栏 561

Unity大世界流式加载:工业级架构与优化秘籍

游戏大厂Unity大世界流式加载框架全景解析:从《原神》《和平精英》等标杆案例出发,深入剖析工业级流式加载的完整技术架构。文章系统介绍了大世界分区块管理、异步加载机制、资源优化策略、多平台适配方案,以及业务联动与团队协作流程。重点阐述了Addressable与AssetBundle应用、空间触发器设计、性能自适应等核心技术,并展望AI预测加载、云游戏等未来方向。全面展现了大厂如何通过流式加载技术实现无缝开放世界体验的技术路径与实践经验。

本博客聚焦游戏开发技巧、创业实战心得及大学热门课程干货。这里既有技术深度,也有思维广度,无论你是开发者、创业者还是高校学子,都能在这里找到适合自己的成长之路! 607

基于Simulink的固态变压器(SST)多级协同控制​

本文介绍了基于Simulink的固态变压器(SST)多级协同控制方法。SST作为智能电网关键设备,其三级架构(AC-DC整流、DC-DC隔离、DC-AC逆变)存在级间耦合问题。文章提出纵向解耦与横向联动相结合的协同控制策略,详细推导了各级控制算法,并通过Simulink实现了10kV/400V级联型SST系统建模。仿真结果显示,在±20%电网波动和0-100%负载跳变下,系统能保持直流母线电压波动<2%。文章还提供了工程部署建议和代码生成方法,为SST的研发提供了实用指导。

amy_mhd的博客 301

数据库分库分表是啥?读写热点是什么?读扩散又是什么?

我们在上面的分库分表中,都用这个id去分,这其实就是所谓的分片键,实际上我们一般也是用数据库的主键作为分片键,这样理想情况下我们已知一个ID,不管是那个规则,我们根据ID都能很快的知道该去查询那张表。

qq_42268998的博客 1001

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

分库分表带来了什么问题?

当年我还在某个游戏项目组里做开发的时候,从企鹅那边挖来的策划信誓旦旦的说,我们要做的这款游戏老少皆宜,肯定是爆款。要做成全球同服。上线至少过亿注册十万人同时在线。要好好规划和设计。我们算了下,信他能有个1亿注册。用了id范围的方式进行分片,分了4张表。搞得我热血沸腾。那天晚上下班,夏蝉鸣泣,从赤道吹来的热风阵阵拂过我的手臂,我听着泽野弘之的歌,就算是开电瓶车,我都感觉自己像是在开高达。一年后。游戏上线前一天通知运维加机器,怕顶不住,要整夜关注。后来上线了,全球最高在线人数58人。其中有7。

IT界那些事儿 230

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

什么是读扩散、写扩散、读写扩散混合?

本文以举例子的方式通俗易懂的介绍了什么是读扩散、写扩散、读写扩散混合模式

qq_42901937的博客 997

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

玩原神学编程:数据库分库分表是啥?读扩散又是啥?

本文用原神游戏类比数据库分库分表技术,生动形象地解释了核心概念。垂直分表相当于拆分角色技能,水平分表类似按ID分散角色到不同队伍。重点分析了"读扩散"问题——查询非主键字段需要扫描多张表,并提出建立索引表或新主键的解决方案。最后总结了分库分表的最佳实践:预估数据量、选择合适分片键、避免热点问题等。全文通过游戏场景类比数据库技术,使复杂概念通俗易懂,强调技术方案需要结合实际场景灵活选择。

自律即自由 577

分库分表会带来什么问题?

那user0就放主键id为1~2kw的数据。一开始,通常都先用一张数据表,而一般来说数据表写到2kw条数据之后,底层B+树的层级结构就可能会变高,不同层级的数据页一般都放在磁盘里不同的地方,换言之,磁盘IO就会增多,带来的便是查询性能变差。也不是说这样不行吧,就是这个业务直到最后放弃的时候,也就存了百万条数据,每次打开数据库表能看到茫茫多的user_xx,就是不太舒服,专业点,叫增加了程序员的。而上面一种方式,根据id范围去分表,就能很好的解决这些问题,数据少的时候,表也少,随着数据增多,表会慢慢变多。

提供各种学习资源及帮助 838

数据库应该怎样分库分表?

数据库分库分表的具体做法

lp15929801907的博客 4645
上一篇: mysql查询 limit 1000,10 和limit 10 速度一样快吗?如果我要分页,我该怎么办?
小白debug
博客等级 码龄11年 294粉丝 40原创
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值