ClickHouse 如何实现数据一致性

文章目录

    • ReplacingMegreTree 引擎
    • 数据一致性实现方式
      • 1.ReplacingMegreTree 引擎
      • 2.ReplacingMegreTree 引擎 + 手动合并
      • 3.ReplacingMegreTree 引擎 + FINAL 查询
      • 4.ReplacingMegreTree 引擎 + 标记 + GroupBy
      • 5.允许偏差

前言:在大数据中,基本上所有组件都要求做到数据的一致性,因为大多数环境都是分布式的情况,如果数据无法做到一致,最终在进行分析计算时,导致指标出现问题,影响业务。

本篇文章将探讨在 ClickHouse 中实现数据一致性的几种方式。

ReplacingMegreTree 引擎

在 ClickHouse 中,推荐使用 ReplacingMegreTree 作为确保数据一致性的引擎。

与传统的 MergeTree 引擎相比,ReplacingMergeTree 允许更新已有的数据,而不是简单地追加新数据。当有新数据插入到表中时,它会删除排序键值相同的重复项,替换旧数据。

当有新数据替换旧数据时,旧数据并不会被立即删除,而是被标记为过时的版本。它定期会触发数据块合并操作,此时才会将历史数据进行删除,只保留新版本数据,优化性能、减少存储空间,做到最终一致性。

只有在触发合并操作后,数据才会发生真正的替换操作,在这之前,你查询到的都是历史版本数据。

数据一致性实现方式

1.ReplacingMegreTree 引擎

如果我们仅仅依赖 ReplacingMegreTree 引擎是无法做到数据一致性的,虽然它可以做到最终一致性,但是在未进行数据合并前,它可能存在重复数据。

而且官方说明,合并时间是无法预测的,也就是说我们并不知道它具体什么时候会发生合并操作。

那么为什么数据的合并时间无法预测呢?

  • 数据量和数据分布不确定性:合并操作的时间受到数据量和数据分布的影响。如果数据量较大,合并操作可能需要花费更长的时间。此外,数据的分布情况也会影响合并操作的时间,例如数据块的大小和数量、数据块之间的差异等。

  • 系统负载和资源竞争:合并操作需要消耗系统资源,包括 CPU、内存、磁盘等。当系统处于高负载状态时,合并操作可能需要等待资源空闲才能执行,这会导致合并操作的时间不确定。

2.ReplacingMegreTree 引擎 + 手动合并

虽然我们无法预知 ReplacingMegreTree 合并的具体时间,但是我们可以提前触发手动合并。

在新数据写入后,通过如下语句,主动执行合并:

OPTIMIZE TABLE table_name FINAL;# 完成语法
OPTIMIZE TABLE [db.]name [ON CLUSTER cluster] [PARTITION partition | PARTITION ID 'partition_id'] [FINAL] [DEDUPLICATE [BY expression]]

但是手动合并会付出很大的代价,官方建议不要使用 OPTIMIZE TABLE ... FINAL,因为它用于管理(测试),而不是日常操作。

原因是,使用该查询时,它会尝试将指定表计划外的数据部分合并到一个原来的数据部分中。在此过程中,ClickHouse 读取所有数据部分,解压缩、合并、压缩为单个部分,然后重写回对象存储,造成巨大的 CPU 和 IO 消耗。这一优化会重写单个部分,即使它们已经合并为单个部分,所以代价很大,日常避免使用。

3.ReplacingMegreTree 引擎 + FINAL 查询

在进行查询时,添加 FINAL 后缀,如下所示:

SELECT * FROM test FINAL;

当指定 FINAL 时,ClickHouse 会在返回结果之前完全合并数据。但它限制引擎,只适用于从 ReplacingMergeTree、SummingMergeTree、AggregatingMergeTree、CollapsingMergeTree 和 VersionedCollapsingMergeTree 表中选择数据。

FINAL 查询在 v20.5.2.7 之前是单线程操作,十分缓慢,在这之后的版本都是并行执行的,默认采用 16 线程数,如果机器不能满足这么多线程,则默认使用当前机器最大线程数。我们也可以指定线程数运行该语句:

SELECT * FROM test FINAL settings max_threads = n;

当然,它会比日常的查询慢很多,主要原因有:

  • 数据是在查询执行期间才进行合并的。

  • 除了查询中指定的列之外,还会读取主键列的数据。

  • 需要额外的计算和内存资源,因为只有在查询时才会进行合并,所有操作都是在内存中进行的。你虽然可以在查询中使用 FINAL 获得最终所需的结果,但是要注意资源的消耗。

4.ReplacingMegreTree 引擎 + 标记 + GroupBy

在创建表时,我们可以增加一列作为标记,记录该值是否被删除或更新。通过两个字段来完成这一操作:

  • 标记列:使用特殊值标识该行数据是否被删除,例如:0 表示存在,1 表示过期。

  • 时间戳:标记列只能确保数据是否被删除,并不能标识是否发生过更新操作。所以我们可以借助数据中本身存在的时间戳来选择最新的数据,从而避免重复数据,做到数据一致性。

在日常开发中推荐使用这种方式来保证数据的一致性。

实现案例

假设有一个表存储用户的信息,包括用户ID、用户名、邮箱和标记列表示是否被删除。

首先,创建表

CREATE TABLE users (id UInt32,name String,email String,is_deleted UInt8,event_time DateTime
) ENGINE = ReplacingMergeTree(event_time)
ORDER BY (id, event_time);

在这个表中,我使用了 ReplacingMergeTree 引擎,并指定了 event_time 字段作为排序键,以确保数据的时间顺序。is_deleted 字段表示该行数据是否被删除,0 表示存在,1 表示被删除。

接下来,插入一些测试数据:

INSERT INTO users VALUES(1, 'Alice', 'alice@example.com', 0, '2024-04-25 08:00:00'),(2, 'Bob', 'bob@example.com', 0, '2024-04-25 09:00:00'),(3, 'Charlie', 'charlie@example.com', 0, '2024-04-25 10:00:00');

进行查询:

SELECT * FROM users;

在这里插入图片描述

现在,来模拟更新和删除操作的增量写入,假设用户 Bob 的邮箱地址被更新,用户 Charlie 被删除:

-- 更新 Bob 的邮箱地址
INSERT INTO users VALUES(2, 'Bob', 'new_bob@example.com', 0, '2024-04-25 11:00:00');-- 删除 Charlie
INSERT INTO users VALUES(3, 'Charlie', '', 1, '2024-04-25 12:00:00');

增量写入后,表中的数据如下所示:

在这里插入图片描述
可以看到,这种情况就出现了重复数据。

但是,我们现在可以使用标记以及 Group By 语句查询每个用户的最新信息,手动过滤失效信息:

SELECT id,argMax(name,event_time) name,argMax(email,event_time) email,argMax(is_deleted,event_time) is_deleted,max(event_time) max_event_time
FROM users
GROUP BY id
HAVINGis_deleted = 0;

按照用户 ID 进行分组,按 event_time 字段当前的最大值,取对应行所有字段的数据。

这里需要注意的是,最后取 event_time 最大值时,重命名字段必须与之前不同,否则会报错。

例如 max(event_time) event_time 这种写法是错误的,因为该列已经被其它聚合函数 argMax 引用了。

在 ClickHouse 中,可以使用 argMax 函数来获取满足指定条件的某个字段的最大值所在行对应的另一个字段的值。argMax 函数通常与 GROUP BY 结合使用,以便在每个分组中找到满足条件的最大值对应的其他字段的值。

运行结果如下:

在这里插入图片描述

可以看到,我们成功的过滤掉了失效数据(用户 Bob 的邮箱地址被更新,用户 Charlie 被删除)

5.允许偏差

当我们在对某个指标进行计算时,并不关心该指标最终特别准确的值,或者说允许偏差一点,重复的数据量并不大,不会对总体造成影响

那么这种情况我们就不需要去确保该份数据的一致性,只需要确保最终一致性即可,此时选用 ReplacingMegreTree 引擎作为数据去重方案即可,不用大费周章的去花时间设计。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/4580.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Docker创建镜像之--------------基于Dockerfile创建

目录 一、在编写 Dockerfile 时,有严格的格式需要遵循 二、Dockerfile 操作常用的指令 2.1ENTRYPOINT和CMD共存的情形 2.2ENTRYPOINT和CMD的区别 2.3ADD 与COPY的区别 三、Dockerfile案例 3.1构建apache镜像 3.1.1 创建镜像目录方便管理 3.1.2创建编写dock…

深入浅出MySQL-03-【MySQL中的运算符】

文章目录 前言1.算术运算符2.比较运算符3.逻辑操作符4.位运算符5.运算符的优先级 前言 环境: Windows11MySQL-8.0.35 MySQL支持多种类型的运算符,可以用来连接表达式的项。运算符的类型主要包括 算术运算符、比较运算符、逻辑运算符 和 位运算符。 1…

在vue项目中使用TS

在vue项目中使用TS 1. 将vue项目注入ts 引入和使用 webpack的打包配置:vue-cli webnpack 编译时 entry 入口 设置 entry: {app: ./src/maikn.ts }2. resolve: extensions 添加 ts 用于处理尝试的数据尾缀列表 问: 如何在webpack新增处理类型文件&am…

函数递归与迭代

目录 1.递归 1.1递归的思想 1.2递归的限制条件 2.递归与迭代 1.递归 函数递归是什么? 递归是学习C语⾔函数绕不开的⼀个话题,那什么是递归呢? 递归其实是⼀种解决问题的⽅法,在C语⾔中,递归就是函数⾃⼰调⽤⾃⼰。 写⼀个史…

代码随想录算法训练营第五十三天| 1143.最长公共子序列 ,1035.不相交的线,53. 最大子序和 动态规划

题目与题解 1143.最长公共子序列 题目链接:1143.最长公共子序列 代码随想录题解:​​​​​​​1143.最长公共子序列 视频讲解:动态规划子序列问题经典题目 | LeetCode:1143.最长公共子序列_哔哩哔哩_bilibili 解题思路&#xff…

Linux Makefile编写之可执行程序

1 概述 编译工具有很多(make/cmake/BJam)。如果不考虑跨平台的话,还是make比较方便。使用make编译需要编写Makefile。本文编写Makefile来生成C/C可执行程序。 2 Makefile文件命名 Makefile文件首先是一个文本文件,Linux下默认有两种命名方式: Makefil…

DBSCAN算法学习

DBSCAN算法 文章目录 DBSCAN算法概述应用场景优缺点基于sklearn库的样例DBSCAN、分层聚类和K均值聚类比较 概述 DBSCAN算法是一种基于密度的聚类算法,能够自动识别不同的簇,并与噪声数据分开。以下是关于DBSCAN算法的重要知识点概述: 基本概…

vue3中如何父组件中使用弹框,子组件中关闭弹框

子组件: <template><el-dialogv-model"visible"title"Tips"width"500"><div class"left"></div><div class"right"></div><template #footer><div class"dialog-footer…

Learning to Upsample by Learning to Sample

摘要 论文&#xff1a;https://arxiv.org/pdf/2308.15085 我们提出了DySample&#xff0c;一个超轻量级且高效的动态上采样器。虽然最近的基于内核的动态上采样器&#xff0c;如CARAFE、FADE和SAPA&#xff0c;取得了令人印象深刻的性能提升&#xff0c;但它们引入了大量的计算…

前端实现文件下载的方法

一、简介 ​ 之前我分享过《前端实现图片下载的方法》&#xff0c;但那只是针对图片下载的方法。本博客分享的是对于文件的下载方法&#xff0c;包括图片文件和非图片文件的下载&#xff0c;例如png、doc、pdf、ppt等等。 ​ 当然&#xff0c;还是那个大前提&#xff1a;在任…

大模型对数字营销的驱动赋能

一、大模型驱动的营销数智化个信未来发展趋势 1.模型算法能力全面升级 大模型凭借智能化的用户洞察&#xff0c;个性化的需求预测、系统化的数据分析、效率化的营销决策以及实实化的全域检测支持&#xff0c;为营销行业更加准确地把握市场动态和消费者需求提供了强大支持。可以…

Spring Boot 如何实现缓存预热

Spring Boot 实现缓存预热 1、使用启动监听事件实现缓存预热。2、使用 PostConstruct 注解实现缓存预热。3、使用 CommandLineRunner 或 ApplicationRunner 实现缓存预热。4、通过实现 InitializingBean 接口&#xff0c;并重写 afterPropertiesSet 方法实现缓存预热。 1、使用…

数据结构和算法:贪心

贪心算法 贪心算法是一种常见的解决优化问题的算法&#xff0c;其基本思想是在问题的每个决策阶段&#xff0c;都选择当前看起来最优的选择&#xff0c;即贪心地做出局部最优的决策&#xff0c;以期获得全局最优解。 贪心算法和动态规划都常用于解决优化问题。它们之间存在一…

TCP/IP协议族中的TCP(二):解析其关键特性与机制

⭐小白苦学IT的博客主页⭐ ⭐初学者必看&#xff1a;Linux操作系统入门⭐ ⭐代码仓库&#xff1a;Linux代码仓库⭐ ❤关注我一起讨论和学习Linux系统 滑动窗口 在前面我们讨论了确认应答策略, 对每一个发送的数据段, 都要给一个ACK确认应答. 收到ACK后再发送下一个数据段.这样…

力扣HOT100 - 98. 验证二叉搜索树

解题思路&#xff1a; class Solution {public boolean isValidBST(TreeNode root) {return recur(root,Long.MIN_VALUE,Long.MAX_VALUE);}public boolean recur(TreeNode root,long lower,long upper){if(rootnull) return true;if(root.val<lower||root.val>upper) re…

HTTP Host 头攻击 原理以及修复方法

漏洞名称 &#xff1a;HTTP Host头攻击 漏洞描述&#xff1a; 一般通用web程序是如果想知道网站域名不是一件简单的事情&#xff0c;如果用一个固定的URI来作为域名会有各种麻烦。开发人员一般是依赖HTTP Host header&#xff08;比如在php里_SERVER["HTTP_HOST"] …

Ubuntu上的screenfetch

2024年4月28日&#xff0c;周日下午 这些文本是由一个叫做 “screenfetch” 的命令生成的&#xff0c;它会显示一些系统和用户信息&#xff0c;包括操作系统、内核版本、系统运行时间、安装的软件包数量、使用的Shell、分辨率、桌面环境、窗口管理器、主题、图标主题、字体、CP…

K8s: 应用项目部署运维环境搭建

使用 StatefulSet 部署 Mysql 数据库环境准备是应用的前置准备工作 先在 node 节点上安装 mysql $ sudo yum install mysql-server -y 安装$ sudo systemctl start mysqld 启动$ sudo systemctl enable mysqld 设置开启启动$ sudo mysql_secure_installation 设置安全选项$ my…

Matlab进阶绘图第51期—带填充等高线的三维特征渲染散点图

带填充等高线的三维特征渲染散点图是填充等高线图与特征渲染三维散点图的组合。 其中&#xff0c;填充等高线图与特征渲染的三维散点图的颜色用于表示同一个特征。 由于填充等高线图无遮挡但不直观&#xff0c;特征渲染的三维散点图直观但有遮挡&#xff0c;而将二者组合&…

MySQL数据库进阶篇二(优化、视图/存储过程/存储函数/触发器)

目录 一、SQL优化1.1、插入数据1.2、主键优化1.3、order by优化1.4、group by优化1.5、limit优化1.6、count优化1.7、update优化 二、视图/存储过程/存储函数/触发器2.1、视图2.2、存储过程2.3、存储函数2.4、触发器 一、SQL优化 分为&#xff1a;插入数据优化&#xff0c;主键…