ClickHouse Replicated*MergeTree复制表原理、Distributed分布式表原理_我叫周利东的博客-CSDN博客_clickhouse replicated


本站和网页 https://blog.csdn.net/qq_36951116/article/details/105511422 的作者无关,不对其内容负责。快照谨为网络故障时之索引,不代表被搜索网站的即时页面。

ClickHouse Replicated*MergeTree复制表原理、Distributed分布式表原理_我叫周利东的博客-CSDN博客_clickhouse replicated
ClickHouse Replicated*MergeTree复制表原理、Distributed分布式表原理
我叫周利东
于 2020-04-14 15:43:09 发布
6772
收藏
16
分类专栏:
ClickHouse
大数据
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_36951116/article/details/105511422
版权
ClickHouse
同时被 2 个专栏收录
2 篇文章
0 订阅
订阅专栏
大数据
22 篇文章
0 订阅
订阅专栏
一、Replicated*MergeTree复制表原理
复制表通过zookeeper实现,其实就是通过zookeeper进行统一命名服务,并不依赖config.xml的remote_servers配置。
不过虽然不依赖,但我们配置的时候尽可能还是要把复制表配置的分片副本信息与config.xml的remote_servers里的分片副本信息一致。因为使用Distributed分布式表时,是不会使用zookeeper的信息,而是从config.xml的remote_servers获取分片以及副本信息(搞不懂为什么不和复制表一样,蛋疼)
1、复制表引擎
Replicated*MergeTree('shard_name','replicate_name')
如上,复制表要指定两个参数。
第一个参数:当前本地复制表实例所属的分片服务名称。
分片服务名是zookeeper上的目录名称,如果你知道zookeeper实现的统一命名服务,那就好理解了,类似dubbo的服务提供者在zookeeper注册的服务名。在dubbo中同一个服务名有多个实例提供相同的服务。服务调用者只需要通过服务名就能够获取到该服务的所有实例的信息。。
复制表这和dubbo差不多。。分片服务名就是在zookeeper上注册的服务提供者名称。多个复制表的该名称如果一样,那么这些复制表都属于同一个分片服务,只不过表示不同副本而已。同一个分片服务的不同副本之间数据会相互同步,保持一致,具体原理请看第2小节。
第二个参数:当前这张表所属的副本名称,一般用replica1、replica2表示。。如果第一个参数相同,当前第二个参数需要不同。。用以区分当前副本与其他副本。。
使用:
创建本地复制表模板如下:
CREATE TABLE test2.t1_local (`EventTime` Date, `id` UInt32)
ENGINE = ReplicatedMergeTree('/clickhouse/tables/{layer}-{shard}/table_name', '{replica}')
PARTITION BY EventTime ORDER BY id
如果使用大括号表示会从配置文件中获取宏定义的变量。。通过<macros/>标签设置。。这自行百度,很简单。
我没使用大括号获取宏定义变量,而是写死,其实是一样的。后期改成宏变量好维护。如下:
CREATE TABLE test2.t1_local (`EventTime` Date, `id` UInt32)
ENGINE = ReplicatedMergeTree('/snowball/tables/t1_local/shard_2', 'replica_2')
PARTITION BY EventTime ORDER BY id
根据两个参数的结合,使用zookeeper的做统一命名服务。用于表示当前本地复制表是哪个分片服务的哪个副本。
当你create创建复制表时,就会把当前复制表的元数据信息注册到zookeeper上。执行上述create table的sql后,在zookeeper上可以找到相关数据:
然后每个shard下存储对应副本的元数据信息(这个分片的所有副本分别在哪个机器上之类的信息)。如下:
2、复制表同步原理
ClickHouse会把属于同一个分片的所有副本数据进行同步。
这就是根据创建复制表时注册到zookeeper上的信息实现的。
我们知道,其实一个副本就在一个ClickHouse实例上就是一张本地的表,只不过这张表引擎是复制表而已。
比如shard_1分片下有replicat1和replicat1两个副本。就是在两个在不同ClickHouse实例上的本地表,表引擎都是ReplicatedMergeTree。
但这两个复制表的shard分片是一样的(第一个参数是一样的),而第二个参数(副本名)不一样,所以这两个表互为副本。
当你往replicat1执行insert语句插入数据时,ReplicatedMergeTree复制表引擎就会启动同步机制。。我个人猜测同步机制原理是:
(1)当你一个本地复制表执行insert语句插入数据时
(2)该本地复制表引擎会通过对应的分片服务名在zookeeper查询到该分片的其他副本的元数据
(3)把数据insert到本地复制表之后,再把数据发送到该分片的其他副本上也进行insert。直到都insert成功为止。
(4)并且在任一副本的复制表上insert,都会通过上述步骤把数据同步到其他副本。
3、对复制表的使用理解
复制表机制就仅仅只是提供一种副本机制。属于同一个分片服务的不同复制表之间会相互同步数据。
但在查询某个副本时,这个副本宕机了还无法把这个查询自动切换到其他副本查询。需要重新去另外一个未宕机的副本实例上查询那个副本对应的本地复制表。虽然不同副本的数据是一样的,但对用户来说,某个副本宕机了还需要手动切换查询的副本实例。
如果要做到在某个副本宕机时自动切换到其他可用副本,那么就需要结合Distributed分布式表进行使用了。
二、Distributed分布式表
    分布式表其实是一种视图,
    分布式引擎,本身不存储数据,但可以在多个服务器上进行分布式查询。读是自动并行的。读取时,远程服务器表的索引(如果存在)会被使用。
1、首先要了解config.xml的remote_servers配置集群信息
因为分布式表是根据上面的配置信息获取到自定义的集群名、分片、副本等信息的。这些信息不会存到zookeeper。
分布式表根据上面配置的信息才能知道查找和插入分布式表时,实际插入的数据是往哪些分片、副本插入。。已经副本宕机时自动切换到新的可用副本。
我的测试环境配置如下
<remote_servers>
<cluster_all>
<shard>
<internal_replication>true</internal_replication>
<replica>
<default_database>test1</default_database>
<host>node1</host>
<port>9000</port>
</replica>
<replica>
<default_database>test2</default_database>
<host>node2</host>
<port>9000</port>
</replica>
</shard>
<shard>
<internal_replication>true</internal_replication>
<replica>
<default_database>test1</default_database>
<host>node2</host>
<port>9000</port>
</replica>
<replica>
<default_database>test2</default_database>
<host>node3</host>
<port>9000</port>
</replica>
</shard>
<shard>
<internal_replication>true</internal_replication>
<replica>
<default_database>test1</default_database>
<host>node3</host>
<port>9000</port>
</replica>
<replica>
<default_database>test2</default_database>
<host>node1</host>
<port>9000</port>
</replica>
</shard>
</cluster_all>
</remote_server>
      Distributed(cluster_name, database, table, [sharding_key])
      参数解析:
      (1)cluster_name:集群名。
      (2)database:数据库名。可以为空,但为空时,查找某个分片的某个副本对应本地表时会使用上面配置中的default_databases的数据库名。
        为什么这样呢?因为机器不够。我这里是三个分片,每个分片两个副本。总共六个副本,那么就要创建六个本地表。但我只有三台机器。这就意味着每个机器上都得存在两个副本,要创建两个本地表,然后Distributed第(3)个参数指定的本地表名也只能指定一个名字,意味着创建的两个本地表名必须相同。。
在同一个ClickHouse实例的同一个数据库上,肯定无法做到create table两个同名的本地表。。所以在机器有限的情况下,有两种方式解决:
<1>一台机器一个ClickHouse实例,把这两个本地表创建在同一个ClickHouse实例的两个不同数据库上。
<2>一台机器两个ClickHouse实例,把这两个本地表创建在不同ClickHouse实例的同一个数据库中。
因为同一机器上搭建多个ClickHouse实例太复杂,所以选择第一种方式。
这又会出现另一个问题,Distributed引擎的第(2)个参数没办法传递多个数据库名称,这样分布式表就无法确定副本对应的本地表在哪个数据库。这个解决方式如下:
在配置文件中配置每个副本的default_databases,创建分布式表时Distributed引擎的第(2)个参数传入空串,这样当Distributed引擎查找副本时(查看下面ps),发现传入的数据库名称是空串空串,就会根据配置文件的副本的default_databases找到相应的数据库。

ps:Distributed引擎查找副本使用default_databases值的几种情况:
<1>正常查询副本时
<2>副本宕机,查找并切换其他副本
)    
如果机器足够,就没必要这样了。。。比如上面六个副本,那么用六台机器,每台机器一个ClickHouse实例,每个ClickHouse实例的同一个数据库中创建一个本地表,这样就行了。
      (3)table:本地表的表名。。去理解本地表和分布式表的关系
      (4)sharding_key:数据分片键。  
2、internal_replication的配置
可以参考:http://cxy7.com/articles/2019/06/07/1559910377679.html
<1>如果底层是非复制表,那么这个值设为false(默认)。表示insert分布式表时,会在分片的所有副本都写入一份。
<2>如果底层是复制表,那么这个值配置为true。表示分布式表不会往所有副本都写入。。仅写入到一个副本。
internal_replication这个参数是控制写入数据到分布式表时,分布式表会控制这个写入是否的写入到所有副本中。。与复制表的同步是不一样的。为什么<2>中要设置为true,这就是为了避免和复制表的同步复制机制出现冲突,导致数据重复或者不一致。。
因为如果既是复制表、internal_replication又为false,那么写入到分布式表时会写入到同一分片的所有副本,而此时复制表的机制也会把不同副本之间的数据进行同步。。而且分布式表写入到所有副本并不是原子性的,也就是说,写入到所有副本时,写入某个副本失败了,那这个副本就写入失败了,不会矫正。。复制表的同步是会保证同步的。
我叫周利东
关注
关注
点赞
16
收藏
打赏
评论
ClickHouse Replicated*MergeTree复制表原理、Distributed分布式表原理
Replicated*MergeTree复制表原理复制表通过zookeeper实现,其实就是通过zookeeper进行统一命名服务,并不依赖config.xml的remote_servers配置。不过虽然不依赖,但我们配置的时候尽可能还是要把复制表配置的分片副本信息与config.xml的remote_servers里的分片副本信息一致。因为使用Distributed分布式表时,是不会使用...
复制链接
扫一扫
专栏目录
ClickHouse大数据分析与实战
09-16
<p><span style="color: #313d54; font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', Arial, sans-serif; font-size: 16px; background-color: #ffffff;">本课程基于ClickHouse最新稳定版本进行讲解,着重讲解ClickHouse大数据技术理论与实战。课程全面包含ClickHouse核心理论、分布式集群部署、数据实时查询实操以及ClickHouse全流程大数据项目实战等内容,让大家从基础到实战快速掌握ClickHouse大数据分析技术。</span></p>
ClickHouse 副本协同原理:ReplicatedMergeTree引擎
凌桓丶的博客
05-25
2098
文章目录ReplicatedMergeTree引擎特点数据结构ZooKeeper内的节点结构Entry日志对象的数据结构副本协同的核心流程INSERTMERGEMUTATIONALTER
ReplicatedMergeTree引擎
ReplicatedMergeTree是MergeTree的派生引擎,它在MergeTree的基础上加入了分布式协同的能力,只有使用了ReplicatedMergeTree复制表系列引擎,才能应用副本的能力。或者用一种更为直接的方式理解,即使用ReplicatedMergeTr
评论 2
您还未登录,请先
登录
后发表或查看评论
【ClickHouse源码】ReplicatedMergeTree之insert流程
一只努力的微服务
03-30
1612
ReplicatedMergeTree之insert流程
核心方法在:dbms/src/Storages/MergeTree/ReplicatedMergeTreeBlockOutputStream.cpp中的write方法
void ReplicatedMergeTreeBlockOutputStream::write(const Block & block)
last_bl...
clickhouse:mergeTree,replicateMergeTree,Deplicate引擎
最新发布
xiaocaij_icai的博客
09-28
569
在此之后,如果某个待写入的Block数据块与先前已被写入的Block数据块拥有相同的Hash摘要(Block数据块内数据顺序、数据大小和数据行均相同),则该Block数据块会被忽略。ngrambf_v1(N-Gram布隆过滤器):ngrambf_v1索引记录的是指定长度的数据短语的布隆表过滤器,只支持String和FixedString数据类型,同时只能够提升in、notIn、like、equals和notEquals查询的性能。跳数索引的目的与一级索引一样,也是帮助查询时减少数据扫描的范围。
ClickHouse之更新表(ReplicatedReplacingMergeTree)
大道至简
04-01
8998
CK没有更新的方法,但是有一种引擎可以支持去重,它就是ReplicatedReplacingMergeTree;
一种是手工执行optimize table;
另一种是table后面加’final’关键字;
Clickhouse MergeTree系列(Replacing、Summing等)表引擎使用说明
Bulut0907
07-21
2754
目录1. ReplacingMergeTree
更多关于Clickhouse的文章可以查看Clickhouse专栏系列文章
1. ReplacingMergeTree
clickhouse分布式表ReplicatedMergeTree + Distributed引擎的增删改查
huanyue6660的博客
10-09
6128
1、建表语句
(1)、本地表:分别在每个节点都建立本地表,或者使用ON CLUSTER
create table if not exists t_local
ID String,
CreateTime DateTime default now()
)engine = ReplicatedMergeTree('/clickhouse/tables/{layer}-{shard}/t_...
ClickHouse副本表ReplicatedMergeTree实操
qq_35128600的博客
07-17
1043
ClickHouse副本表ReplicatedMergeTree实操
Clickhouse --- Distributed引擎
谷家舟
07-17
1215
Distributed 原理解析
Distributed表引擎是分布式表的代名词,不存储任何数据,只是作为代理,能够自动路由到集群中的各个节点,所以其需要和其他的表引擎一起工作。
一张分片表由两部分组成:
本地表:通常用_local结尾,主要承载数据。
分布式表:通常用_all结尾,其与本地表形成一对多的映射关系,通过分布式表可以操作多张本地表。
1 定义形式
一张Distributed表引擎的定义形式如下:
ENGINE = Distributed(cluster, database, table,
Clickhouse学习之路(五)-- 集群方案研究
BIackMamba的博客
08-16
359
方案一:MergeTree + Distributed
架构图
架构解析:
MergeTree + Distributed的分布式架构方案,利用的是Distributed表的特性+MergeTree表的特性,分布式表不存储数据,数据来自本地表,将分布式表的数据分为3个shard,每台节点存储三分之一的数据,用户查询的时候是从分布式表所在的节点聚合从Ck1,CK2,CK3的查询结果,然后返回用户,写入数据可以写入分布式表,当然这样的写入方式问题很多,一般是禁止写入分布式表的,那么选择写入本地表的化,需要将数
Clickhouse接口表引擎(Merge、Dictionary、Distributed)
Bulut0907
07-31
2129
目录1. Merge表引擎
接口表引擎不储存数据,通过封装其它表实现特定的功能,提供一种统一的数据访问接口
1. Merge表引擎
应用场景:当针对相同的数据做了分表操作后,如果想通过一个表查询所有的分表数据,Merge表就可以实现
Merge表引擎的不足
不支持数据写入
各个分表位于同一个数据库
各个分表表结构也要相同,但表引擎和partition分区(MergeTree)可以不同
城市为Beijing的表创建和数据插入
...
ClickHouse ReplicatedMergeTree家族引擎
qq_28603127的博客
11-17
6399
ClickHouse 中的所有MergeTree家族引擎前面加上Replicated就成了支持副本的合并树引擎.
本文以ReplicatedMergeTree引擎作为演示,其他副本合并树引擎是一个道理.
ReplicatedMergeTree如果有两个副本的话,相当于分布在两台clickhosue节点中的两个表,但是这个两个表具有协调功能,无论是哪个表执行insert或者alter操作,都会同步到另外一张表,这样子很好理解,副本就是相互同步数据的表.
复制合并树只有进行INSERT或者ALTER或者TRUN
ClickHouse的ReplicatedMergeTree副本引擎搭建使用
qq_42437282的博客
07-02
536
文章目录前言一、服务搭建1、准备包2、在两台服务器上分别搭建clickhouse服务二、配置调整1、config.xml2、metrika.xml3、users.xml三、试用1、建表2、插入数据总结
前言
一、服务搭建
1、准备包
官网下载地址:https://clickhouse.yandex
clickhouse-client-20.8.3.18-1.el7.x86_64.rpm
clickhouse-common-static-20.8.3.18-1.el7.x86_64.rpm
clickhou
ClickHouse复制表、分布式表机制与使用方法
LittleMagic's Blog
04-29
9234
Replication & Sharding
在ClickHouse文集的第一篇文章中,笔者介绍了ClickHouse高可用集群的配置方法,并且提到:分布式存储要保证高可用,就必须有数据冗余——即副本(replica)。ClickHouse依靠ReplicatedMergeTree引擎族与ZooKeeper实现了复制表机制,成为其高可用的基础。
另外,笔者也提到,ClickHouse像El...
ClickHouse MergeTree副本表和分布式表(切片)
haveanybody的博客
04-13
998
在前面的文章中我们详细介绍了 MergeTree 表引擎、MergeTree 家族其他表引擎、MergeTree 二级索引等内容,clickhouse数据库都是在单节点上运行的,作为OLAP处理的大数据利器,clickhouse 显然少了两个功能——数据高可用(HA)和横向扩展。HA的目的是为了如果有一个数据副本丢失或者损坏不至于完全丢失数据,至于横向扩展自然是为了提高数据存储能力了。
1. MergeTree副本表
ClickHouse MergeTree 副本表的数据一致性同步是通过Zookeeper实
Clickhouse副本表以及分布式表简单实践
weixin_30273763的博客
11-26
918
集群配置:
192.168.0.106 node3
192.168.0.101 node2
192.168.0.103 node1
  
zookeeper配置忽略,自行实践!
node1配置:
<?xml version="1.0"?>
<yandex>
<logger>
<!-- Possib...
源码分析 | ClickHouse和他的朋友们(13)ReplicatedMergeTree表引擎及同步机制
dbkernel 的博客
07-11
168
本文首发于 2020-09-15 20:15:14在 MySQL 里,为了保证高可用以及数据安全性会采取主从模式,数据通过 binlog 来进行同步。在 ClickHouse 里,我们可以使用 ReplicatedMergeTree 引擎,数据同步通过 zookeeper 完成。本文先从搭建一个多 replica 集群开始,然后一窥底层的机制,简单吃两口。搭建一个 2 replica 测试集群,由于条件有限,这里在同一台物理机上起 clickhouse-server(2个 replica) + zookee
ClickHouse整理
hiddpy的博客
04-11
590
1、什么是ClickHouse?
ClickHouse是一个用于联机分析(OLAP)的列式数据库管理系统(DBMS)。
在传统的行式数据库(如mysql)系统中,数据按如下顺序存储:
Row
WatchID
JavaEnable
Title
GoodEvent
EventTime
#0
89354350662
Investor Relations
2016-05-18 05:19:20
#1
90329509958
Contact us
2016-05-18 08:10:
ClickHouse之ReplicatedMergeTree引擎介绍
bboy66的博客
04-13
2504
clickhouse高可用副本集群搭建
ClickHouse创建分布式表
Jeremy
12-22
4530
ClickHouse创建分布式表
当数据量剧增的时候,clickhouse是采用分片的方式进行数据的存储的,类似于redis集群的实现方式。然后想进行统一的查询的时候,因为涉及到多个本地表,可以通过分布式表的方式来提供统一的入口。由于是涉及到分布式存储,保证高可用就必须有数据冗余—即副本(replica)。Clickhouse依靠ReplicatedMergeTree引擎族与Zookeeper实现了复制表机制,成为其高可用的基础。该引擎和 MergeTree 的不同之处在于它会删除排序键值相同的重复项。
“相关推荐”对你有帮助么?
非常没帮助
没帮助
一般
有帮助
非常有帮助
提交
©️2022 CSDN
皮肤主题:技术黑板
设计师:CSDN官方博客
返回首页
我叫周利东
CSDN认证博客专家
CSDN认证企业博客
码龄6年
暂无认证
201
原创
3万+
周排名
57万+
总排名
57万+
访问
等级
7067
积分
88
粉丝
332
获赞
136
评论
974
收藏
私信
关注
热门文章
java8 list根据元素的某个字段或者根据元素的多个字段去重(多种方式)
21968
mongodb java客户端的使用,即MongoClient
20277
最小生成树算法:普里姆算法和克鲁斯卡尔算法
18721
spring mvc @RequestBody与@Valid或者@Validated一起用
17126
ClickHouse 建表create table时primary by与order by
15231
分类专栏
elasticsearch
12篇
spark
22篇
hive入门学习
5篇
hbase
11篇
nginx
1篇
3篇
spring源码阅读
8篇
flink
2篇
kafka
11篇
scala
8篇
ClickHouse
2篇
flume
3篇
jenkins
6篇
事务
spring
21篇
spring mvc
22篇
tomcat
6篇
mysql
22篇
jdk
8篇
前端
2篇
java8
22篇
java
47篇
数据结构
11篇
排序算法
1篇
设计模式
11篇
多线程/并发
16篇
spring boot
6篇
mybatis
7篇
jvm
11篇
git&github
6篇
spring cloud
8篇
软件工程
4篇
feign
2篇
mongodb
5篇
RabbitMQ
1篇
hystrix
1篇
redis
4篇
eureka
3篇
NIO
9篇
机器学习
1篇
正则
3篇
linux
14篇
hadoop
31篇
大数据
22篇
ssh
2篇
zookeeper
11篇
mapreduce
15篇
log
https
2篇
http
3篇
dubbo
1篇
分布式
2篇
yarn
3篇
网络编程
spring源码
6篇
hive
3篇
最新评论
CAS的ABA问题,ABA问题会导致什么后果?
请把小熊还给我&:
aba问题会导致数据最终不准确吗
什么是CAS?CAS的ABA问题,ABA问题会导致什么后果?
weixin_44368090:
请教一下,乐观锁可以适用于分布式场景中么
docker Failed to get D-Bus connection: Operation not permitted
m0_38103795:
楼上的兄弟道出了真理。。
hive 建表,分桶表(clustered by)、分桶且桶内排序(clustered by+sorted by)、分区表(partitioned by)、分区分桶一起用
daydayup-2016:
clustered by在建表时用为什么就不能实现既分区有排序的效果,而只能在sql语句里使用cluster by才能实现
什么是CAS?CAS的ABA问题,ABA问题会导致什么后果?
QHAOHAN:
一般场景下ABA并不会出现什么问题,但是当涉及到引用的时候就会出问题。
场景是用链表来实现一个栈,初始化向栈中压入B、A两个元素,栈顶head指向A元素。
在某个时刻,线程1试图将栈顶换成B,但它获取栈顶的oldValue(为A)后,被线程2中断了。线程2依次将A、B弹出,然后压入C、D、A。然后换线程1继续运行,线程1执行compareAndSet发现head指向的元素确实与oldValue一致,都是A,所以就将head指向B了。但是线程2在弹出B的时候,将B的next置为null了,因此在线程1将head指向B后,栈中只剩了一个孤零零的元素B。但按预期来说,栈中应该放的是B → A → D → C
您愿意向朋友推荐“博客详情页”吗?
强烈不推荐
不推荐
一般般
推荐
强烈推荐
提交
最新文章
java二维码批量生成并打包为zip下载
spark推测机制及参数设置
elasticsearch 删除某个index的某个字段
2022年2篇
2021年35篇
2020年69篇
2019年159篇
2018年98篇
目录
目录
分类专栏
elasticsearch
12篇
spark
22篇
hive入门学习
5篇
hbase
11篇
nginx
1篇
3篇
spring源码阅读
8篇
flink
2篇
kafka
11篇
scala
8篇
ClickHouse
2篇
flume
3篇
jenkins
6篇
事务
spring
21篇
spring mvc
22篇
tomcat
6篇
mysql
22篇
jdk
8篇
前端
2篇
java8
22篇
java
47篇
数据结构
11篇
排序算法
1篇
设计模式
11篇
多线程/并发
16篇
spring boot
6篇
mybatis
7篇
jvm
11篇
git&github
6篇
spring cloud
8篇
软件工程
4篇
feign
2篇
mongodb
5篇
RabbitMQ
1篇
hystrix
1篇
redis
4篇
eureka
3篇
NIO
9篇
机器学习
1篇
正则
3篇
linux
14篇
hadoop
31篇
大数据
22篇
ssh
2篇
zookeeper
11篇
mapreduce
15篇
log
https
2篇
http
3篇
dubbo
1篇
分布式
2篇
yarn
3篇
网络编程
spring源码
6篇
hive
3篇
目录
评论 2
被折叠的 条评论
为什么被折叠?
到【灌水乐园】发言
查看更多评论
打赏作者
我叫周利东
你的鼓励将是我创作的最大动力
¥2
¥4
¥6
¥10
¥20
输入1-500的整数
余额支付
(余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付
您的余额不足,请更换扫码支付或充值
打赏作者
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额
抵扣说明:
1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。 2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。
余额充值