【ClickHouse源码】Distributed之表insert流程_一只努力的微服务的博客-CSDN博客_insert_distributed_sync


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

【ClickHouse源码】Distributed之表insert流程_一只努力的微服务的博客-CSDN博客_insert_distributed_sync
【ClickHouse源码】Distributed之表insert流程
一只努力的微服务
于 2020-11-19 13:03:33 发布
1477
收藏
分类专栏:
ClickHouse
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_39992480/article/details/109808356
版权
ClickHouse
专栏收录该内容
34 篇文章
22 订阅
订阅专栏
Distributed表引擎介绍
Distributed表引擎是一种特殊的表引擎,自身不会存储任何数据,而是通过读取或写入其他远端节点上的表进行数据处理的表引擎。该表引擎需要依赖各个节点的本地表来创建,本地表的存在是Distributed表创建的依赖条件,创建语句如下:
CREATE TABLE {teble} ON CLUSTER {cluster}
AS {local_table}
ENGINE= Distributed({cluster}, {database}, {local_table},{policy})
这里的policy一般可以使用随机(例如rand())或哈希(例如halfMD5hash(id))
再来看下clickhouse集群节点配置文件,相关参数如下:
<remote_servers>
<logs>
<shard>
<weight>1</weight>
<internal_replication>true</internal_replication>
<replica>
<priority>1</priority>
<host>example01-01-1</host>
<port>9000</port>
</replica>
<replica>
<host>example01-01-2</host>
<port>9000</port>
</replica>
</shard>
<shard>
<weight>2</weight>
<internal_replication>true</internal_replication>
<replica>
<host>example01-02-1</host>
<port>9000</port>
</replica>
<replica>
<host>example01-02-2</host>
<port>9000</port>
</replica>
</shard>
</logs>
</remote_servers>
Distributed表使用本地配置文件,在读取和写入时就不需要和zookeeper进行交互,并且clickhouse的集群配置是可以动态加载(2秒刷新一次)的,所以Distributed表在使用时很灵活,也可以为Distributed表建立多个cluster,因为Distributed表在查询时一般会向集群中所有的节点都发出请求,如果某个节点上没有相关联的本地表也会接到请求,如果可以将需要查询的节点配置一个集群可以避免一些空请求。当然Distributed表也可以通过prewhere或where设定条件来智能跳过不需要的shard。
Distributed表写入原理
有了上面的基础了解,就将进入主题了,本文主要是对Distributed表如何写入及如何分发做一下分析,略过SQL的词法解析、语法解析等步骤,从写入流开始,其构造方法如下:
DistributedBlockOutputStream(const Context & context_, StorageDistributed & storage_, const ASTPtr & query_ast_, const ClusterPtr & cluster_, bool insert_sync_, UInt64 insert_timeout_);
如果insert_sync_为true,表示是同步写入,并配合insert_timeout_参数使用(insert_timeout_为零表示没有超时时间); 如果insert_sync_为false,表示写入是异步。
同步写入还是异步写入
同步写入是指数据直写入实际的表中,而异步写入是指数据首先被写入本地文件系统,然后发送到远端节点。
BlockOutputStreamPtr StorageDistributed::write(const ASTPtr &, const Context & context)
......
/// Force sync insertion if it is remote() table function
bool insert_sync = settings.insert_distributed_sync || owned_cluster;
auto timeout = settings.insert_distributed_timeout;
/// DistributedBlockOutputStream will not own cluster, but will own ConnectionPools of the cluster
return std::make_shared<DistributedBlockOutputStream>(
context, *this, createInsertToRemoteTableQuery(remote_database, remote_table, getSampleBlockNonMaterialized()), cluster,
insert_sync, timeout);
是否执行同步写入是由insert_sync决定的,最终是由是否配置insert_distributed_sync(默认为false)和owned_cluster值的或关系决定的,一般在使用MergeTree之类的普通表引擎时,通常是异步写入,但在使用表函数时(使用owned_cluster来判断是否是表函数),通常会使用同步写入。这也是在设计业务逻辑时需要注意的。
owned_cluster是什么时候赋值的呢?
StoragePtr TableFunctionRemote::executeImpl(const ASTPtr & ast_function, const Context & context, const std::string & table_name) const
......
StoragePtr res = remote_table_function_ptr
? StorageDistributed::createWithOwnCluster(
table_name,
structure_remote_table,
remote_table_function_ptr,
cluster,
context)
: StorageDistributed::createWithOwnCluster(
table_name,
structure_remote_table,
remote_database,
remote_table,
cluster,
context);
......
StoragePtr StorageDistributed::createWithOwnCluster(
const std::string & table_name_,
const ColumnsDescription & columns_,
ASTPtr & remote_table_function_ptr_,
ClusterPtr & owned_cluster_,
const Context & context_)
auto res = create(String{}, table_name_, columns_, ConstraintsDescription{}, remote_table_function_ptr_, String{}, context_, ASTPtr(), String(), false);
res->owned_cluster = owned_cluster_;
return res;
可以发现在创建remote表时会根据remote_table_function_ptr参数对最终的owned_cluster_赋值为true。
异步写入是如何实现的
了解了什么时候使用同步写入什么时候异步写入后,在继续分析正式的写入过程,同步写入一般场景中涉及较少,这里主要对异步写入逻辑进行分析。outStream的write方法如下:
void DistributedBlockOutputStream::write(const Block & block)
Block ordinary_block{ block };
......
if (insert_sync)
writeSync(ordinary_block);
else
writeAsync(ordinary_block);
其实这个write方法是重写了virtual void IBlockOutputStream::write(const Block & block),所以节点在接收到流并调用流的write方法就会进入该逻辑中。并且根据insert_sync来决定走同步写还是异步写。
写入本地节点还是远端节点
主要还是对异步写入进行分析,其实writeAsync()最终的实现方法是writeAsyncImpl(),如下:
void DistributedBlockOutputStream::writeAsyncImpl(const Block & block, const size_t shard_id)
const auto & shard_info = cluster->getShardsInfo()[shard_id];
if (shard_info.hasInternalReplication())
if (shard_info.getLocalNodeCount() > 0)
/// Prefer insert into current instance directly
writeToLocal(block, shard_info.getLocalNodeCount());
else
if (shard_info.dir_name_for_internal_replication.empty())
throw Exception("Directory name for async inserts is empty, table " + storage.getTableName(), ErrorCodes::LOGICAL_ERROR);
writeToShard(block, {shard_info.dir_name_for_internal_replication});
else
if (shard_info.getLocalNodeCount() > 0)
writeToLocal(block, shard_info.getLocalNodeCount());
std::vector<std::string> dir_names;
for (const auto & address : cluster->getShardsAddresses()[shard_id])
if (!address.is_local)
dir_names.push_back(address.toFullString());
if (!dir_names.empty())
writeToShard(block, dir_names);
其中getShardsInfo()方法就是获取config.xml配置文件中获取集群节点信息,hasInternalReplication()就对应着配置文件中的internal_replication参数,如果为true,就会进入最外层的if逻辑,否则就会进入else逻辑。其中writeToLocal()方法是相同的,是指如果shard包含本地节点,优先选择本地节点进行写入;后半部分writeToShard()就是根据internal_replication参数的取值来决定是写入其中一个远端节点,还是所有远端节点都写一次。
数据如何写入本地节点
当然一般情况Distributed表还是基于ReplicatedMergeTree系列表进行创建,而不是基于表函数的,所以大多数场景还是会先写入本地再分发到远端节点。那写入Distributed表的数据是如何保证原子性落盘而不会在数据正在写入的过程中就把不完整的数据发送给远端其他节点呢?看下writeToShard()方法,如下:
void DistributedBlockOutputStream::writeToShard(const Block & block, const std::vector<std::string> & dir_names)
/** tmp directory is used to ensure atomicity of transactions
* and keep monitor thread out from reading incomplete data
*/
std::string first_file_tmp_path{};
auto first = true;
/// write first file, hardlink the others
for (const auto & dir_name : dir_names)
const auto & path = storage.getPath() + dir_name + '/';
/// ensure shard subdirectory creation and notify storage
if (Poco::File(path).createDirectory())
storage.requireDirectoryMonitor(dir_name);
const auto & file_name = toString(storage.file_names_increment.get()) + ".bin";
const auto & block_file_path = path + file_name;
/** on first iteration write block to a temporary directory for subsequent hardlinking to ensure
* the inode is not freed until we're done */
if (first)
first = false;
const auto & tmp_path = path + "tmp/";
Poco::File(tmp_path).createDirectory();
const auto & block_file_tmp_path = tmp_path + file_name;
first_file_tmp_path = block_file_tmp_path;
WriteBufferFromFile out{block_file_tmp_path};
CompressedWriteBuffer compress{out};
NativeBlockOutputStream stream{compress, ClickHouseRevision::get(), block.cloneEmpty()};
writeVarUInt(UInt64(DBMS_DISTRIBUTED_SENDS_MAGIC_NUMBER), out);
context.getSettingsRef().serialize(out);
writeStringBinary(query_string, out);
stream.writePrefix();
stream.write(block);
stream.writeSuffix();
if (link(first_file_tmp_path.data(), block_file_path.data()))
throwFromErrnoWithPath("Could not link " + block_file_path + " to " + first_file_tmp_path, block_file_path,
ErrorCodes::CANNOT_LINK);
/** remove the temporary file, enabling the OS to reclaim inode after all threads
* have removed their corresponding files */
Poco::File(first_file_tmp_path).remove();
首先来了解下Distributed表在目录中的存储方式,默认位置都是/var/lib/clickhouse/data/{database}/{table}/在该目录下会为每个shard生成不同的目录,其中存放需要发送给该shard的数据文件,例如:
[root@ck test]# tree
├── 'default@ck2-0:9000,default@ck2-1:9000'
│ ├── 25.bin
│ └── tmp
│ └── 26.bin
└── 'default@ck3-0:9000,default@ck3-1:9000'
└── tmp
可以发现每个shard对应的目录名是{darabse}@{hostname}:{tcpPort}的格式,如果多个副本会用,分隔。并且每个shard目录中还有个tmp目录,这个目录的设计在writeToShard()方法中做了解释,是为了避免数据文件在没写完就被发送到远端。数据文件在本地写入的过程中会先写入tmp路径中,写完后通过硬链接link到shard目录,保证只要在shard目录中出现的数据文件都是完整写入的数据文件。
数据文件的命名是通过全局递增的数字加.bin命名,是为了在后续分发到远端节点保持顺序性。
数据如何分发到各个节点
细心的已经发现在writeToShard()方法中有个requireDirectoryMonitor(),这个方法就是将shard目录注册监听,并通过专用类StorageDistributedDirectoryMonitor来实现数据文件的分发,根据不同配置可以实现逐一分发或批量分发。并且包含对坏文件的容错处理。
重点来啦!
分析到这,可能还有人会觉得云里雾里,觉得整个流程串不起来,其实这样写是为了先不影响Distributed表写入的主流程,明白了这个再附加上sharding_key拆分和权重拆分就很好理解了。
如何根据sharding_key和weight拆分数据
上面提到过writeAsync()的最终实现方法是writeAsyncImpl,这个说法是没问题的,但是中间还有段关键逻辑,如下:
void DistributedBlockOutputStream::writeAsync(const Block & block)
if (storage.getShardingKeyExpr() && (cluster->getShardsInfo().size() > 1))
return writeSplitAsync(block);
writeAsyncImpl(block);
++inserted_blocks;
void DistributedBlockOutputStream::writeSplitAsync(const Block & block)
Blocks splitted_blocks = splitBlock(block);
const size_t num_shards = splitted_blocks.size();
for (size_t shard_idx = 0; shard_idx < num_shards; ++shard_idx)
if (splitted_blocks[shard_idx].rows())
writeAsyncImpl(splitted_blocks[shard_idx], shard_idx);
++inserted_blocks;
getShardingKeyExpr()方法就是去获取sharding_key生成的表达试指针,该表达式是在创建表时就生成的,如下:
sharding_key_expr = buildShardingKeyExpression(sharding_key_, global_context, getColumns().getAllPhysical(), false);
那sharding_key和sharding_key_expr是什么关系呢?如下:
const ExpressionActionsPtr & getShardingKeyExpr() const { return sharding_key_expr; }
所以说sharding_key_expr最终主要就是由sharding_key决定的。
一般情况下getShardingKeyExpr()方法都为true,如果再满足shard数量大于1,就会对block进行拆分,由splitBlock()方法实现,如下:
Blocks DistributedBlockOutputStream::splitBlock(const Block & block)
auto selector = createSelector(block);
......
for (size_t col_idx_in_block = 0; col_idx_in_block < columns_in_block; ++col_idx_in_block)
MutableColumns splitted_columns = block.getByPosition(col_idx_in_block).column->scatter(num_shards, selector);
for (size_t shard_idx = 0; shard_idx < num_shards; ++shard_idx)
splitted_blocks[shard_idx].getByPosition(col_idx_in_block).column = std::move(splitted_columns[shard_idx]);
return splitted_blocks;
IColumn::Selector DistributedBlockOutputStream::createSelector(const Block & source_block)
Block current_block_with_sharding_key_expr = source_block;
storage.getShardingKeyExpr()->execute(current_block_with_sharding_key_expr);
const auto & key_column = current_block_with_sharding_key_expr.getByName(storage.getShardingKeyColumnName());
const auto & slot_to_shard = cluster->getSlotToShard();
......
throw Exception{"Sharding key expression does not evaluate to an integer type", ErrorCodes::TYPE_MISMATCH};
**注意啦!**看splitBlock()方法,clickhouse是利用createSelector()方法构造selector来进行后续的处理。在createSelector()方法中最重要的就是key_column和slot_to_shard。
key_column是通过sharding_key间接获得的,是为了根据主键列进行切割;slot_to_shard是shard插槽,这里就是为了处理权重,在后续向插槽中插入数据时就会结合config.xml中的weight进行按比例处理。细节比较复杂这里不做太细致的分析,有兴趣可以自行看下(如template IColumn::Selector createBlockSelector<UInt8>())。
到此,对于Distributed表的写入流程的关键点就大致分析完了。篇幅有限有些细节没有做过多说明,有兴趣的可以自行再了解下。
总结
通过对Distributed表写入流程的分析,了解了该类型表的实际工作原理,所以在实际应用中有几个点还需要关注一下:
Distributed表在写入时会在本地节点生成临时数据,会产生写放大,所以会对CPU及内存造成一些额外消耗,建议尽量少使用Distributed表进行写操作。Distributed表写的临时block会把原始block根据sharding_key和weight进行再次拆分,会产生更多的block分发到远端节点,也增加了merge的负担。Distributed表如果是基于表函数创建的,一般是同步写,需要注意。
了解原理才能更好的使用,遇到问题才能更好的优化。
一只努力的微服务
关注
关注
点赞
收藏
打赏
评论
【ClickHouse源码】Distributed之表insert流程
Distributed表引擎介绍Distributed表引擎是一种特殊的表引擎,自身不会存储任何数据,而是通过读取或写入其他远端节点上的表进行数据处理的表引擎。该表引擎需要依赖各个节点的本地表来创建,本地表的存在是Distributed表创建的依赖条件,创建语句如下:CREATE TABLE {teble} ON CLUSTER {cluster}AS {local_table}ENGINE= Distributed({cluster}, {database}, {local_table},{pol
复制链接
扫一扫
专栏目录
【ClickHouse源码】Distributed之表select流程
一只努力的微服务
04-08
1412
Distributed之表查询流程
Distributed表引擎不会真实存储数据,是ClickHouse提供的一个分布式查询引擎,其查询原理大致概括起来就是将server端接收到的查询请求进行重写,并发送到指定的多个server端去执行查询,最终由接到请求的server端进行汇总,最后返回给client端。这个过程可以通过源码来更清晰的了解以下。
首先,从BlockInputStreams Sto...
Clickhouse INSERT操作
热门推荐
vkingnew 的技术博客
06-16
1万+
参考:
https://www.altinity.com/blog/2018/10/16/updates-in-clickhouse
参与评论
您还未登录,请先
登录
后发表或查看评论
python Clickhouse 分布式表介绍和创建、插入和查询数据,以及解决遇到的问题
最新发布
qq_45956730的博客
11-11
554
Clickhouse 分布式表介绍和创建、插入和查询数据,以及解决遇到的问题
汇编语言如何在rom中写入数据_Sentry:如何从数据存储中获得更强的一致性
weixin_39593340的博客
12-08
350
Sentry的首要工作是接收、解析用户的异常信息。当用户异常信息大量上报时,Sentry的流量将达到高峰。同时,提供近实时的错误追踪,对于用户是有帮助的。这里有两个相互排斥的地方:事件(Event)提取服务必须在各种负载的情况下都具有响应快速且可伸缩的能力。Sentry用户必须近实时地可以看到异常信息。为了能够应对流量高峰,Sentry从客户端接收事件,并异步执行一系列处理。 因此,这些处理不一定...
ClickHouse MergeTree副本表和分布式表(切片)
haveanybody的博客
04-13
998
在前面的文章中我们详细介绍了 MergeTree 表引擎、MergeTree 家族其他表引擎、MergeTree 二级索引等内容,clickhouse数据库都是在单节点上运行的,作为OLAP处理的大数据利器,clickhouse 显然少了两个功能——数据高可用(HA)和横向扩展。HA的目的是为了如果有一个数据副本丢失或者损坏不至于完全丢失数据,至于横向扩展自然是为了提高数据存储能力了。
1. MergeTree副本表
ClickHouse MergeTree 副本表的数据一致性同步是通过Zookeeper实
clickhouse-copier 数据迁移工具介绍
MYSQL轻松学的专栏
01-30
1万+
在使用clickhouse的时候,可能会有不同集群间迁移数据需求,这里可以使用如下几种方式:
DETACH/FREEZE分区,进行SCP拷贝,然后再ATTACH
alter table db.table DETACH PARTITION [partition]; #下线分区
alter table db.table FREEZE PARTITION [partition]; #备份分区...
ClickHouse实战--使用分布式表
zg_hover的专栏
05-03
3367
本文介绍了分布式表的基本操作。包括分布式表的创建,如何向分布式表插入数据,如何更新分布式表的表结构等操作。
Distributed表引擎Insert和Select流程
style_boy的博客
06-07
390
ClickHouse依靠Distributed引擎实现了Distributed(分布式)表机制,在所有分片(本地表)上建立视图进行分布式查询,。它是一种特殊的表引擎,自身不会存储任何数据,而是通过读取或写入其他远端节点上的表进行数据处理的表引擎。该表引擎需要依赖各个节点的本地表来创建,本地表的存在是Distributed表创建的依赖条件,创建语句如下:
CREATE TABLE {teble} ON CLUSTER {cluster}
AS {local_table}
ENGINE= Distributed
ClickHouse系列之集群副本与分片
Jerome Wu の那点事儿
08-11
783
概述
​本文主要为大家介绍ClickHouse三板斧(集群、副本与分片)
集群
​集群是副本和分片的基础,它将ClickHouse的服务拓扑由当前节点延伸到多个节点,但它并不像Hadoop生态某系统那样,要求所有节点组成一个单一的大集群(服务级别)。ClickHouse的集群配置比较灵活,用户既可以组成一个单一集群,也可以按照业务划分为多个小集群(表级别),它们的节点、副本和分片数量可各不相同。
​从作用来看,ClickHouse集群的工作可以理解为是针对逻辑层面的,而执行层面的具体工作则交给副本和分
Clickhouse Distributed分布式表引擎的基本介绍和使用说明
Bulut0907
07-08
4257
目录1. 分布式的本地表1.1 基本语法1.2 分布式的创建本地表1.3 分布式的删除本地表2. Distributed表2.1 创建Distributed表2.2 删除分布式表2.3 Distributed表其它语法3. Distributed表的增删改查3.1 insert3.2 select3.3 分布式本地表mutation3.3 分布式本地表delete
Clickhouse的集群部署可以参考我的Clickhouse版本21.6.5.37的分片和副本分布式安装
Distributed表需要和其它
ClickHouse distributed表引擎
Aiky哇
06-23
302
Distributed Table Engine | ClickHouse DocsTables with Distributed engine do not store any data of their own, but allow distributed query processing on multiple servers.https://clickhouse.com/docs/en/engines/table-engines/special/distributed具有分布式引擎的表不存储自己的任
记录一次ClickHouse数据迁移的过程
weixin_42155491的博客
05-11
775
迁移的背景:
首先目前的集群是4节点,配置为:4分片1副本(也就是没有数据备份),然后其中一个节点由于服务器问太卡访问太慢,需要去掉该节点,再重新加一个节点,然后再把去掉的节点上的数据迁移到新的节点中,然后整个集群还是4个节点。
方案:
借助clickhouse-copier,这是官网提供的一个数据迁移的工具,它可以做整个集群迁移到另一个集群,也可以只把其中一个分片的数据迁移,也可以在集群内部做数据迁移,这次我们的背景是集群内部做迁移。
具体做法:
首先我的想法是,先新增一个节点,就是集群由4节点变成5
拉取数据_快到飞起的分析数据库ClickHouse笔记高可用
weixin_30753697的博客
01-04
473
ClickHouse通过副本保证数据的可用,通过分片来实现数据水平扩展和性能提升。高可用HA(High Availability)是设计分布式系统架构时必须考虑的因素之一 。一般指通过设计减少系统不能提供服务的时间,假设系统一直能够提供服务,我们说系统的可用性是100%。如果系统每运行100个时间单位,会有1个时间单位无法提供服务,我们说系统的可用性是99%。很多公司的高可用目标是4个9...
clickhouse分布表插入数据 异步
KKT
02-08
975
向clickhouse分布表A插入数据后,执行select * from A,发现数据数量不足,但是过了几秒后,在执行select * from A,数量又是正确的了。
经过研究发现,对于clickhouse,不仅delete和update操作是异步,默认情况下分布表的insert也是异步的(本地表的insert是同步的)。
通过设置参数可以让分布表的入库是同步的:
insert_distributed_sync=true
...
clickhouse 参数优化配置
孤傲然的博客
07-01
2569
max_memory_usage_for_user,
max_memory_usage,
max_bytes_before_external_group_by,
max_bytes_before_external_sort,
max_memory_usage_for_all_queries,
max_concurrent_queries_for_user,
max_concurrent_queries_for_all_users,
max_concurrent_queries,
max_serve
ClickHouse集群(1)INSERT、MERGE执行流程
style_boy的博客
07-09
1354
CH集群架构 (metrika.xml)基本由 副本+分片 组成。副本:源数据的冗余,防止数据丢失;分片:数据的水平拆分,提升查询性能。对于ClickHouse而言,集群架构由简单到复杂如下:
来自《ClickHouse原理解析与应用实践》一书
准备环境
集群架构是2分片,1副本
create database testdb;
use testdb;
2.分布式DDL的建表语句
2.1 本地表
create table test_local ON CLUSTER my_cluster (ID Int8
clickhouse 五(分布式表原理解析)
写bug的小哥哥
10-15
6026
1.Distributed引擎介绍
Distributed表引擎是分布式表的代名词,它⾃身不存储任何数据,⽽是作为数据分⽚的透明代理,能够⾃动的
路由数据⾄集群中的各个节点,即分布式表需要和其他数据表⼀起协同⼯作。分布式表会将接收到的读写任务,
分发到各个本地表,而实际上数据的存储也是保存在各个节点的本地表中。
原理如下图:
2.创建分布式表
使用on cluster语句在集群的某台机器上创建一下代码,即可在每台机器上创建本地表和分布式表,
⼀张本地表对应着⼀个数据分⽚,分布式表通常以本地表加“_al
clickhouse Insert 原理
Cincinnati_De的博客
08-19
945
#### 1 ) INSERT的核心执行流程
当需要在ReplicatedMergeTree中执行INSERT以写入数据时,即会进入INSERT核心流程,整个流程从上至下按照时间顺序进行。
1)创建第一个副本实例
```
--clickhouse-sts-0节点执行;
create table replicated(
id Int8,
ctime DateTime,
name String
)ENGINE = ReplicatedMergeTree('/clickhouse/tables/01/re
ClickHouse最佳实战之分布表写入流程分析
京东科技开发者
10-14
1595
云妹导读:前不久,京东智联云正式上线了基于Clickhouse的分析型云数据库JCHDB,一经推出便受到广大用户的极大关注。有兴趣的小伙伴可以回顾上一篇文章《比MySQL快839倍!揭开...
clickhouse集群迁移实践
洽洽老大的专栏
02-09
1888
clickhouse集群迁移实践
原文链接
背景
现有的ck集群没有副本,磁盘是12块盘的stat盘,存在磁盘故障导致数据丢失的风险,而依赖zk的双副本策略又由于zk性能存在瓶颈影响集群的可用性,故而使用带三副本的高效云盘替代stat盘,规避数据丢失的风险。
当前ck的写入程序使用的是统一的域名,由域名查询到对应的ip节点来建立tcp连接。对于ck的查询,使用的是内部的一个代理,该代理配置了集群的ip,由代理去轮询ip进行查询。
在数据迁移的过程中,需要保证集群写入和查询都不受影响,关键在于控制好查询和写入
“相关推荐”对你有帮助么?
非常没帮助
没帮助
一般
有帮助
非常有帮助
提交
©️2022 CSDN
皮肤主题:技术黑板
设计师:CSDN官方博客
返回首页
一只努力的微服务
CSDN认证博客专家
CSDN认证企业博客
码龄5年
暂无认证
64
原创
1万+
周排名
1万+
总排名
20万+
访问
等级
2087
积分
1446
粉丝
145
获赞
50
评论
312
收藏
私信
关注
热门文章
systemctl使用reload及踩坑
32155
SpringBoot中starter原理简介
28713
Collections.unmodifiableMap()用法
9191
【ClickHouse系列】ClickHouse各类函数用法详解
9048
springboot自启动脚本shell、systemctl以及service文件Environment用法
7752
分类专栏
ClickHouse
34篇
Python
3篇
Kafka
2篇
docker
1篇
SpringCloud
2篇
zk
2篇
helm
1篇
helm3
1篇
Golang
8篇
Java
15篇
SpringBoot
6篇
Kubernetes
5篇
Netty
4篇
Linux
6篇
PostgreSQL
5篇
Istio
1篇
最新评论
【ClickHouse系列】基于clickhouse-exporter的ClickHouse监控搭建
看来封建势力附件:
请问你用的什么模版
【ClickHouse系列】使用S3实现ClickHouse的无限量存储
大骨变成汤°:
您好,我配置了配置文件重启后,SELECT * FROM system.storage_policies没有出现配置的S3的存储策略,想问下这个该怎么解决
【ClickHouse系列】clickhouse-copier是如何进行数据迁移的
IceBear_6:
俺也一样,请问兄弟现在解决了吗
【ClickHouse源码】ReplicatedMergeTree之表创建流程
IceBear_6:
// 上面是做一些开始的判断和操作,比如设置is_active,是不是需要clone数据
// 这里开始执行clone的操作,获取log_pointer指针,获取缺少的log(在log节点
// 里的log-xxxxx),将这些log添加到queue节点里
storage.queue.pullLogsToQueue(zookeeper);
storage.queue.removeCurrentPartsFromMutations();
storage.last_queue_update_finish_time.store(time(nullptr));
这里面缺少的log在哪里获取? 你副本重启的时候,原本在ZK上存在的log元数据已经消失了
【ClickHouse源码】ReplicatedMergeTree之表创建流程
IceBear_6:
如何断定 loadDataParts(skip_sanity_checks); 这个函数是开始从其他副本恢复数据?
您愿意向朋友推荐“博客详情页”吗?
强烈不推荐
不推荐
一般般
推荐
强烈推荐
提交
最新文章
【ClickHouse系列】ClickHouse常用聚合函数的使用方法
【ClickHouse实践】将函数应用于多个列
【ClickHouse实践】ClickHouse中HTTP错误码处理
2022年6篇
2021年10篇
2020年22篇
2019年32篇
目录
目录
分类专栏
ClickHouse
34篇
Python
3篇
Kafka
2篇
docker
1篇
SpringCloud
2篇
zk
2篇
helm
1篇
helm3
1篇
Golang
8篇
Java
15篇
SpringBoot
6篇
Kubernetes
5篇
Netty
4篇
Linux
6篇
PostgreSQL
5篇
Istio
1篇
目录
评论
被折叠的 条评论
为什么被折叠?
到【灌水乐园】发言
查看更多评论
打赏作者
一只努力的微服务
你的鼓励将是我创作的最大动力
¥2
¥4
¥6
¥10
¥20
输入1-500的整数
余额支付
(余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付
您的余额不足,请更换扫码支付或充值
打赏作者
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额
抵扣说明:
1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。 2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。
余额充值