Lago - 使用 ClickHouse 扩展事件引擎

图片

本文字数:4540;估计阅读时间:12 分钟

作者:Mathew Pregasen

本文在公众号【ClickHouseInc】首发

图片

本周,我们欢迎来自 Lago 的一篇博客文章,介绍了他们如何使用 ClickHouse 扩展一个事件引擎,并在此过程中将查询速度最高提高了 137 倍!这篇博客文章的原始版本发布在 Github 上。

【https://github.com/getlago/lago/wiki/Using-Clickhouse-to-scale-an-events-engine】

介绍

像许多公司一样,我们在扩展核心产品 Lago (一个开源的基于使用量计费平台)时,不得不在过程中更换数据库堆栈。随着我们逐渐受到欢迎,我们每分钟开始接收数百万个事件。我们初期使用的仅 Postgres 的简单堆栈已经无法满足需求。我们遭遇了严重的加载时间问题,影响了整个应用的性能。

经过一些探索,我们决定使用一个分布式的 ClickHouse 实例专门处理我们的流事件。我们的分析服务现在可以直接查询这个 OLAP 数据库 ClickHouse。对于所有其他数据需求,我们保留了 Postgres。

这个策略非常成功。自重构后,我们从未回头。

今天,我们将探讨这个混合数据库堆栈的决策,特别是为什么我们选择 ClickHouse。

OLTP 与 OLAP 数据库

大多数开发者,包括初级开发者,都有使用 OLTP (在线事务处理)数据库(如 Postgres)的经验。顾名思义,OLTP 数据库专为处理事务而设计。事务是一个独立的工作单元,可能包括以下操作:(i) 读取,(ii) 插入,(iii) 更新,和 (iv) 删除。

OLTP 数据库通常是通用数据库。由于它们支持各种类型的数据处理,可以在一定程度上解决任何数据问题。即使在大规模使用时,OLTP 数据库对于需要以下功能的软件来说也是非常出色的:

  • 原子性事务,其中一组事务要么全部发生,要么根本不发生

  • 一致性,其中写入和更新之间的查询是确定的和可预测的

对于大多数问题,这些都是重要的特征。对于一些问题,它们是绝对关键的。例如,银行应用程序在账户之间转账时不能有任何差错。对于这些问题,需要 OLTP 数据库来实现精确到分的准确性。

今天,我们仍然使用 Postgres 作为我们的主数据库,通过我们的 database.yml 文件进行配置。鉴于我们使用 Ruby on Rails,我们的 Postgres 模式由 Rails 的 Active Record 自动生成,这是一个 ORM,管理着我们各种模型,如费用、信用票据、发票、邀请、费用、优惠券等等。我们编写了一些自定义查询(考虑到 ORM 的性能限制),但在大多数事务中主要依赖 Active Record。

那么 OLAP (在线分析处理)数据库(如 ClickHouse)在哪里派上用场呢?Postgres 被设计为严格的原子性和一致性,这两个属性要求在任何查询处理之前,数据必须完全摄取。这对每分钟插入数百万行数据的表(例如,可计费事件,特别是那些基础设施服务如托管服务器的事件)造成了问题。具体来说,问题不在于插入数据,而在于同时处理复杂的分析查询而不锁定队列。这些数据汇总问题正是 OLAP 数据库(如 ClickHouse)大显身手的领域。

OLAP 数据库设计用于解决两个主要问题:(i) 以近似准确性高效回答复杂的读取查询和 (ii) 批处理大量写入查询。然而,OLAP 数据库历史上不擅长变更数据(通常需要重写整个数据库)或删除数据。

不同的 OLAP 解决方案(例如 ClickHouse、QuestDB、Druid)各有其优势。在下一节中,我们将深入探讨使 ClickHouse 成为最佳解决方案的具体特性。但所有 OLAP 解决方案都有一个共同特点——数据相对于像 Postgres 这样的 OLTP 数据库是以倒置布局存储的。

图片

从用户的角度来看,表格的列和行仍然只是列和行。但在内存和磁盘上,数据是按列而不是按行进行扫描的。这使得聚合操作(例如将某个字段中的所有值相加)非常快,因为相关数据是顺序读取的。

介绍 ClickHouse,我们选择的 OLAP 解决方案

ClickHouse 于 2016 年开源,如今在 AWS 和 GCP 上作为无服务器云服务提供。它是采用最广泛的 OLAP 数据库之一。

ClickHouse 有三个显著特点,使其成为满足我们需求的强大分析工具:(i) 动态物化视图,(ii) 专用引擎,和 (iii) 向量化查询执行。

总结如下:

  • 动态物化视图。物化视图是从基础表中的原始数据生成的可查询视图。虽然许多数据库都支持物化视图,包括 Postgres,但 ClickHouse 的物化视图是一种特殊的触发器,当数据插入时执行查询。查询结果然后被分派到目标表,在那里合并和更新。这使得工作从查询时间转移到插入时间:因为目标表通常更小,查询结果更简单。这与普通的物化视图不同,普通物化视图只是特定时间点的快照,刷新代价非常高(这些在 ClickHouse 中也得到支持,称为“可刷新的物化视图”)。

  • 专用引擎。许多数据库使用单一引擎来利用硬件处理查询/事务。然而,ClickHouse 有专用引擎用于数学函数,例如求和或平均数。

  • 向量化查询执行。ClickHouse 的专用引擎利用向量化查询执行,硬件通过多个单元并行处理来实现共同结果(称为 SIMD——单指令多数据)。

结合其列式存储,这些特性使 ClickHouse 能够轻松地对数据库值进行求和、平均和聚合。

需要注意的是,Postgres 并非完全不能实现类似的结果,但这只能通过大量优化来实现。例如,有一个为 Postgres 设计的第三方向量化执行器,模仿 ClickHouse 的原生特性。还有一个快速刷新模块,使用 Postgres 的日志来动态更新物化视图。结合 Postgres 触发器,开发者可以创建一个类似 ClickHouse 的环境。但所有这些技术都需要大量设置工作和额外列,才能达到与 ClickHouse 相当的效率。

图片

来自我为 PostHog 编写的 Postgres 与 ClickHouse 指南中的相关表情包

当然,将分析过程迁移到 ClickHouse 只是战斗的一半。接下来是将 ClickHouse 实际部署到生产环境中,可以采用几种策略。

我们如何利用 ClickHouse

在讨论我们的 ClickHouse 实现时,主要涉及两个不同的主题:(i) 我们使用 ClickHouse 的用途,以及 (ii) 我们的 ClickHouse 实例如何部署和维护。

我们在 ClickHouse 中查询什么

我们的 ClickHouse 实例接收由用户派发的原始可计费事件。虽然我们不自行编写 ClickHouse 模式(因为它是由 Active Record 自动生成的),但它被写入一个文件,该文件在我们的开源库中可用。我们的 ClickHouse 实例只有两个表——raw_events 和 raw_events_queue——以及一个物化视图 events_raw_mv。仅此而已。我们不在 ClickHouse 中存储任何不需要用于分析查询的“业务关键”数据。

图片

具体而言,我们的 raw_events_queue 表使用 Kafka 表引擎从 Apache Kafka(一种开源事件流软件)读取行。events_raw_mv 在 raw_events_queue 表接收插入时被触发,将事件的元数据从 JSON blob 映射到字符串数组,并将这些数据推送到 raw_events 表。这是一个为大量写入设计的 MergeTree 表。raw_events 是 Lago 的一般代码库通过我们的 ClickHouseStores 类与之交互的表,在聚合可计费指标时调用它。raw_events 使用一个由 organization_id、external_subscription_id 和 code 组成的元组——加上一个时间戳——作为主键;鉴于 ClickHouse 对主键元组的复杂支持,这使得 ClickHouse 能够非常快速地定位行数据。

我们如何部署 ClickHouse

由于 ClickHouse 是一个开源数据库,可以在任何普通的 Linux 服务器上进行自托管。然而,许多公司更信赖托管数据库解决方案,因为它们 (i) 通常可以降低总体成本,(ii) 使数据库更容易扩展,以及 (iii) 负责安全的复制和备份。

目前,我们使用 ClickHouse Cloud,这是一种由 ClickHouse Inc. 提供的托管解决方案,部署了一个无服务器的 ClickHouse 实例,具有解耦的计算和存储功能。ClickHouse Cloud 使我们更容易扩展,而无需担心扩展带来的问题。

ClickHouse 性能与 Postgres 的对比

我们对比了 Postgres 和 ClickHouse 在几个关键聚合操作上的性能:

加权求和聚合

Postgres: 6.6秒

图片

Clickhouse: 48毫秒

图片

计数和求和操作

Postgres: 6.5秒

图片

Clickhouse: 350毫秒

图片

如图所示,迁移到 ClickHouse 后,我们的主要查询性能至少提高了 18 倍,最高可达 137 倍!

其他使用 ClickHouse 的著名开源项目

我们并不是唯一使用 ClickHouse 的开源项目。事实上,我们甚至不是唯一一个从 Postgres 迁移到 ClickHouse 的开源项目。另一个著名的例子是 PostHog,一个开源分析套件,由于每秒处理大量网络事件而从 Postgres 切换到 ClickHouse。

另一个典型的例子是 GitLab,它在其可观测性套件中使用 ClickHouse 存储流事件的数据。一般来说,当开源公司(和闭源项目)开始扩展时,通常会发现通用数据库如 Postgres 或 MySQL 不太适合。

即使是一些闭源解决方案,如 HTTP 数据流产品 Tinybird,也对 ClickHouse 做出了开源贡献,因为它们依赖于 ClickHouse。慢慢地,ClickHouse 在 OLAP 领域取得了与 Postgres 在 OLTP 领域相同的成功。

总结

由于倒置表布局的硬件优化,随着应用程序的扩展,没有一种数据库可以满足所有需求。在我们的旅程中,由于产品的事件密集特性,我们相当早就遇到了这个问题。然而,这并不意味着每个团队都需要从 OLTP + OLAP 堆栈开始——只需在时机到来时准备好。

征稿启示

面向社区长期正文,文章内容包括但不限于关于 ClickHouse 的技术研究、项目实践和创新做法等。建议行文风格干货输出&图文并茂。质量合格的文章将会发布在本公众号,优秀者也有机会推荐到 ClickHouse 官网。请将文章稿件的 WORD 版本发邮件至:Tracy.Wang@clickhouse.com

联系我们

手机号:13910395701

邮箱:Tracy.Wang@clickhouse.com

满足您所有的在线分析列式数据库管理需求

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

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

相关文章

学习react-Provider解决props需要层层传递问题

1.组件数据传递问题 数据传递:A(顶级组件)-》B组件(子组件)、C组件(孙子组件)…很多组件 这样得通过props层层传递到下面的组件 还有另一种解决方法,即通过全局对象来解决,使用Prov…

堆的实现-适用于算法竞赛

首先讲一下能够实现的操作。 插入一个数查找最小值删除最小值删除任意一个元素修改任意一个元素 什么是堆? 堆其实是一棵完全二叉树。 即处理叶子节点和倒数第一层节点,其他节点都有两个子节点,而且顺序是从上到下,从左到右。 …

使用VMware安装Linux虚拟机

一、下载 通过百度网盘分享的文件:CentOS系统安装包 链接:https://pan.baidu.com/s/1_eqYl8HcNt2GcGDjgOElgg 提取码:cu07 二、安装 (1)双击打开软件 (2) 创建新的虚拟机 (3&…

PyQt ERROR:ModuleNotFoundError: No module named ‘matplotlib‘

Solution:打开cmd输入指令下载malplotlib pip install matplotlib

微软第四季度财报预览:增长动力追踪

微软公司即将在2024年7月30日(周二)美国市场收盘后发布第四季度财务结果。 微软的收益 - 预期如何 美股券商开户通道 市场预计,微软即将到来的2024年第四季度的收入将年增长14.5%,达到644亿美元,高于2023年第四季度…

linux添加普通用户后无法使用K8S的kubectl命令怎么办/Linux普通用户管理K8S/Linux下普通用户无法使用K8S命令

1.给Linux添加普通用户 sudo useradd mqq #添加mqq账号 sudo passwd mqq #给mqq账号设置密码,需要输入2次,我输入密码是Admin1232.利用mqq用户输入K8S命令报错 3.给mqq用户提权 suduers文件位于路径/etc/sudoers #编辑文件/etc/sudoers vim /etc/su…

Matlab编程资源库(10)离散傅立叶变换

一、离散傅立叶变换算法简要 给定一个N点的离散信号序列x(n),其中n表示时刻,n 0, 1, 2, ..., N-1。 定义离散傅立叶变换的频域序列X(k),其中k表示频率,k 0, 1, 2, ..., N-1。 通过以下公式计算每个频率对应的复数值&#xff…

03。正式拿捏ArkTS语言第一天

1, 打印日志命令 : console.log() 2, 三种基本数据类型: number 数字类型 (数字) string 字符串类型(例如:“我是字符串”) boolean 布尔类型 (true 或者 false) ***…

【C语言报错已解决】Use of Uninitialized Variable

🎬 鸽芷咕:个人主页 🔥 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想,就是为了理想的生活! 引言: 在编程中,未初始化的变量是一个常见的问题,它可能导致程序的行为变得不可预测。未初…

Matlab更换主题颜色附代码

解压后参考记录本教程 GitHub - scottclowe/matlab-schemer: Apply and save color schemes in MATLAB with ease. 本博客绑定了资源

【前端 08】简单学习js字符串

JavaScript中的String对象详解 在JavaScript中,字符串(String)是一种非常基础且常用的数据类型,用于表示文本数据。虽然JavaScript中的字符串是原始数据类型,但它们的行为类似于对象,因为JavaScript为字符…

windows 安装 Linux 子系统 Ubuntu,并编译安装nginx

1. 安装Ubuntu 首先可以在 Microsoft Store 自行搜索安装 Ubuntu,个人建议安装 22 版本的即可。Ubuntu安装完成后,以管理员身份打开CMD,运行如下命令: wsl --install 此时打开Ubuntu已经可以正常使用了。 2. 安装C/C编译器 对于…

java算法day25

java算法day25 广度优先搜索岛屿数量深搜岛屿数量广搜 广度优先搜索 核心:从起点出发,以起始点为中心一圈一圈进行搜索,一旦遇到终点,记录之前走过的节点就是一条最短路。搜索的方式是上下左右 一张图说明白模拟过程&#xff1…

【C语言】深入探讨数组传参

一、数组传参简介 在C语言中,数组传参是一个常见的操作,尤其是在处理大量数据或需要多次访问相同数据集时。理解如何传递数组以及这些方法之间的差异是编写高效和安全代码的关键。在这篇博客中,我们将详细讨论C语言中数组传参的几种常见方法&…

rhce THE homework of first

ssh远程免密登录成功 下载httpd和nginx 关闭防火墙 查看selinux的状态 为服务器配置ip 填充网站的内容 添加服务器配置

Python爬虫入门01:在Chrome浏览器轻松抓包

文章目录 爬虫基本概念爬虫定义爬虫工作原理爬虫流程爬虫类型爬虫面临的挑战 使用Chrome浏览器抓包查看网页HTML代码查看HTTP请求请求头(Request Header)服务器响应抓包的意义 爬虫基本概念 爬虫定义 爬虫(Web Crawler 或 Spider&#xff0…

MongoDB教程(二十三):关于MongoDB自增机制

💝💝💝首先,欢迎各位来到我的博客,很高兴能够在这里和您见面!希望您在这里不仅可以有所收获,同时也能感受到一份轻松欢乐的氛围,祝你生活愉快! 文章目录 引言一、MongoD…

数字孪生在奥运会上的应用

数字孪生是一种精确的虚拟空间表示,能够实时模拟场馆内的各种变化或场景。国际奥委会正在确定高价值的应用案例和技术要求,将应用案例分为六个主要领域:场馆规划、利益相关者支持与参与、操作准备、粉丝体验、遗产和运营效率。每个案例将基于…

【前端 13】Vue快速入门

Vue快速入门 在现代Web开发中,尽管通过HTML、CSS和JavaScript我们能够构建出美观且功能丰富的页面,但随着项目规模的增大,这种传统的开发方式在效率上逐渐显得力不从心。为了提高开发效率,前端开发者们引入了多种框架和库&#x…

MySQL环境的配置文件json

突然了解到,使用json文件去进行环境的配置,这样修改参数的时候就只需要去改json文件中的内容,不需要去修改代码中的内容,其他人的MySQL和我的MySQL也不同,这时其他人只需要修改json文件中的内容,清晰明了&a…