使用 ClickHouse 做日志分析

原作:Monika Singh & Pradeep Chhetri 

这是我们在 Monitorama 2022 上发表的演讲的改编稿。您可以在此处找到包含演讲者笔记的幻灯片和此处的视频。

20231007162314

当 Cloudflare 的请求抛出错误时,信息会记录在我们的 requests_error 管道中。错误日志用于帮助解决特定于客户或网络范围的问题。

我们,站点可靠性工程师 (SRE),负责管理日志平台。我们已经运行Elasticsearch集群很多年了,这些年来日志量急剧增加。随着日志量的增加,我们开始面临一些问题。查询性能慢、资源消耗高等。我们的目标是通过提高查询性能并提供经济高效的日志存储解决方案来改善日志消费者的体验。这篇博文讨论了日志记录管道的挑战以及我们如何设计新架构以使其更快且更具成本效益。

在我们深入探讨维护日志管道的挑战之前,让我们先了解一下日志的特征。

日志的特征

20231007162651

不可预测:当今世界,微服务数量众多,集中式日志系统将收到的日志量非常难以预测。日志体量估算如此困难的原因有多种。主要是因为新应用程序不断部署到生产中,现有应用程序会自动扩展或缩小以满足业务需求,或者有时应用程序所有者启用调试日志级别并忘记将其关闭。

上下文:对于调试问题,通常需要上下文信息,即事件发生之前和之后的日志。单个日志行几乎没有帮助,通常,是一组日志行有助于构建上下文。此外,我们经常需要将多个应用程序的日志关联起来以绘制全貌。因此,必须保留日志在数据源处填充的顺序。

写入密集型:任何集中式日志系统都是写入密集型的。超过 99% 的已写入日志从未被读取。它们占用空间一段时间,并最终被保留策略清除。剩下的不到1%的被读取的日志非常重要,我们不能错过它们。

日志管道

与大多数其他公司一样,我们的日志记录管道由生产者、路由转发器、队列、消费者和存储组成。

20231007163358

在 Cloudflare 全球网络上运行的应用程序(生产者)生成日志。这些日志以 Cap’n Proto 序列化格式在本地写入。 Shipper(内部解决方案)通过流将 Cap’n Proto 序列化日志推送到 Kafka(队列)进行处理。我们运行 Logstash(消费者),它从 Kafka 消费并将日志写入 ElasticSearch(数据存储)。然后使用 Kibana 或 Grafana 可视化数据。我们在 Kibana 和 Grafana 中内置了多个仪表板来可视化数据。

Cloudflare 的 Elasticsearch 瓶颈

在 Cloudflare,我们多年来一直运行 Elasticsearch 集群。多年来,日志量急剧增加,在优化 Elasticsearch 集群以处理此类量时,我们发现了一些限制。

Mapping 爆炸

20231007163724

Mapping 爆炸是 Elasticsearch 众所周知的局限性之一。 Elasticsearch 维护一个映射,决定如何存储和索引新文档及其字段。当此映射中的键太多时,可能会占用大量内存,从而导致频繁的垃圾回收。防止这种情况的一种方法是使 schema 严格,这意味着任何不遵循此严格 schema 的日志行最终都会被删除。另一种方法是使其成为半严格的,这意味着不属于此映射的任何字段都将不可搜索。

多租户支持

20231007164039

Elasticsearch 没有很好的多租户支持。一个坏用户很容易影响集群性能。无法限制查询可以读取的文档或索引的最大数量或 Elasticsearch 查询可以占用的内存量。错误的查询很容易降低集群性能,即使查询完成后,它仍然会留下影响。

集群维护工作

管理Elasticsearch集群并不容易,尤其是多租户集群。一旦集群降级,就需要花费大量时间才能使集群恢复到完全健康的状态。在Elasticsearch中,更新索引模板意味着重新索引数据,这是一个相当大的开销。我们使用冷热分层存储,即最近的数据存储在 SSD 中,较旧的数据存储在机械硬盘中。虽然Elasticsearch每天都会将数据从热存储移动到冷存储,但它会影响集群的读写性能。

垃圾回收

20231007164506

Elasticsearch 使用 Java 开发并在 Java 虚拟机 (JVM) 上运行。它执行垃圾收集以回收由程序分配但不再引用的内存。Elasticsearch 需要垃圾收集调整。最新的 JVM 中默认的垃圾回收是 G1GC。我们尝试了其他 GC,例如 ZGC,这有助于减少 GC 暂停,但在读写吞吐量方面并没有给我们带来太多性能优势。

20231007165155

Elasticsearch 是一个很好的全文搜索工具,这些限制对于小型集群来说并不重要,但在 Cloudflare 中,我们每秒处理超过 35 到 4500 万个 HTTP 请求,其中每秒有超过 500K-800K 的请求失败。这些失败可能是由于不正确的请求、源服务器错误、用户配置错误、网络问题和各种其他原因造成的。

我们的客户支持团队使用这些错误日志作为定位客户问题的起点。错误日志包含有关 HTTP 请求所经过的各种 Cloudflare 产品的许多字段元数据。我们将这些错误日志存储在 Elasticsearch 中。我们对它们进行了大量采样,因为存储所有内容需要花费数百 TB 的空间,超出了我们的资源分配预算。此外,基于它构建的仪表板非常慢,因为它们需要对各个字段进行大量聚合。根据调试要求,我们需要将这些日志保留几周。

建议的解决方案

我们希望完全取消采样,即存储保留期内的每条日志行,为如此庞大的数据量提供快速查询支持,并在不增加成本的情况下实现这一切。为了解决所有这些问题,我们决定进行概念验证,看看是否可以使用 ClickHouse 来满足我们的要求。

Cloudflare 是 ClickHouse 的早期采用者,我们多年来一直在管理 ClickHouse 集群。我们已经拥有许多内部工具和库,用于将数据插入 ClickHouse,这使我们可以轻松进行概念验证。让我们看一下 ClickHouse 的一些功能,这些功能使其非常适合存储日志,并使我们能够构建新的日志管道。

20231007170002

ClickHouse 是一个面向列的数据库,这意味着与特定列相关的所有数据在物理上彼此相邻存储。即使在普通商用硬件上,这种数据布局也有助于快速顺序扫描。这使我们能够从老一代硬件中获得最大性能。

20231007170412

ClickHouse 专为分析工作负载而设计,数据可以有很多列。我们能够设计具有大量列的新 ClickHouse 表,而不会牺牲性能。

20231007170548

ClickHouse 索引的工作方式与关系数据库中的索引不同。在关系数据库中,主索引非常密集,并且每个表行包含一个条目。因此,如果表中有 100 万行,主索引也将有 100 万个条目。而在 ClickHouse 中,索引是稀疏的,这意味着每几千行只有一个索引条目。ClickHouse 索引使我们能够动态添加新索引。

ClickHouse 默认使用 LZ4 压缩所有内容。高效的压缩不仅有助于最大限度地减少存储需求,还可以让 ClickHouse 有效地使用页面缓存。

ClickHouse 的一项很酷的功能是可以按列配置压缩编解码器。我们决定为所有列保留默认的 LZ4 压缩。我们对 DateTime 列使用了 Double-Delta,对 Float 列使用了 Gorilla,对固定大小的 String 列使用了 LowCardinality。

ClickHouse是线性可扩展的;也就是说,写入可以通过添加新分片来扩展,读取可以通过添加新副本来扩展。ClickHouse 集群中的每个节点都是相同的。没有任何特殊节点有助于轻松扩展集群。

让我们看一下我们用来提供更快的读/写吞吐量和更好的日志数据压缩的一些优化。

Inserter

拥有高效的插入器与拥有高效的数据存储一样重要。在 Cloudflare,我们一直在运行相当多的分析管道,在编写新的插入器时我们借用了大部分概念。我们使用 Cap’n Proto 消息作为传输数据格式,因为它提供快速的数据编码和解码。扩展插入器很容易,可以通过添加更多 Kafka 分区并生成新的插入器 Pod 来完成。

20231007171504

Batch Size

将数据插入 ClickHouse 时的关键性能因素之一是批量大小。当批量较小时,ClickHouse 会创建许多小分区,然后将其合并为更大的分区。因此,较小的批量大小会给 ClickHouse 在后台带来额外的工作,从而降低 ClickHouse 的性能。因此,将其设置得足够大,以便 ClickHouse 可以愉快地接收数据批次,而不会达到内存限制,这一点至关重要。

20231007173016

数据模型

ClickHouse 提供内置的分片和复制,无需任何外部依赖。ClickHouse 的早期版本依赖于 ZooKeeper 来存储复制信息,但最新版本通过添加 clickhouse-keeper 消除了对 ZooKeeper 的依赖。

为了跨多个分片读取数据,我们使用分布式表,一种特殊的表。这些表本身不存储任何数据,而是充当存储实际数据的多个基础表的代理。

20231007174045

与任何其他数据库一样,选择正确的表 schema 非常重要,因为它将直接影响性能和存储利用率。我们想讨论将日志数据存储到 ClickHouse 中的三种方法。

20231007174133

第一个是最简单且最严格的表模式,您可以在其中指定每个列名称和数据类型。任何具有此预定义 schema 之外的字段的日志行都将被删除。根据我们的经验,此架构将为您提供最快的查询性能。如果您已经知道前面所有可能字段的列表,我们建议使用它。您始终可以通过运行 ALTER TABLE 查询来添加或删除列。

第二种模式使用 ClickHouse 的一个非常新的功能,它完成了大部分繁重的工作。您可以将日志作为 JSON 对象插入,在幕后,ClickHouse 将了解您的日志架构并动态添加具有适当数据类型和压缩的新列。仅当您可以很好地控制日志架构并且总字段数小于 1,000 时,才应使用此架构。一方面,它提供了自动添加新列作为新日志字段的灵活性,但与此同时,一个糟糕的应用程序可以轻松地破坏 ClickHouse 集群。

第三种模式将相同数据类型的所有字段存储在一个数组中,然后使用 ClickHouse 内置数组函数来查询这些字段。即使字段超过 1,000 个,此架构也能很好地扩展,因为列数取决于日志中使用的数据类型。如果某个数组元素被频繁访问,可以利用ClickHouse的物化列功能将其取出作为专用列。我们建议采用此模式,因为它可以防止应用程序记录过多字段。

数据分区

20231007174706

分区是 ClickHouse 数据的一个单位。 ClickHouse 用户常犯的一个错误是分区键过于细化,导致分区过多。由于我们的日志管道每天都会生成 TB 级的数据,因此我们创建了使用toStartOfHour(dateTime)分区的表。通过这种分区逻辑,当查询在 WHERE 子句中带有时间戳时,ClickHouse 就会知道分区并快速检索它。它还有助于根据数据保留策略设计有效的数据清除规则。

主键选择

20231007175126

ClickHouse 将数据按主键排序存储在磁盘上。因此,选择主键会影响查询性能并有助于更好的数据压缩。与关系数据库不同,ClickHouse 不需要每行都有唯一的主键,我们可以插入具有相同主键的多行。拥有多个主键会对插入性能产生负面影响。ClickHouse 的重要限制之一是,一旦创建表,主键就无法更新。

Data skipping indexes

20231007175532

ClickHouse 查询性能与评估 WHERE 子句时是否可以使用主键成正比。我们有很多列,所有这些列都不能成为主键的一部分。因此,对这些列的查询将必须进行全面扫描,从而导致查询速度变慢。在传统数据库中,可以添加二级索引来处理这种情况。在 ClickHouse 中,我们可以添加另一类索引,称为数据跳过索引,它使用布隆过滤器并跳过读取保证不匹配的重要数据块。

ABR

我们在 requests_error 日志上构建了多个仪表板。加载这些仪表板通常会达到 ClickHouse 中为单个查询/用户设置的内存限制。

基于这些日志构建的仪表板主要用于识别异常情况。为了直观地识别指标中的异常情况,不需要确切的数字,但可以提供近似的数字。例如,要了解数据中心中错误的增加,我们不需要确切的错误数量。因此,我们决定使用围绕 ABR 概念构建的内部库和工具。

20231007180059

ABR 代表“自适应比特率” - 术语 ABR 主要用于视频流服务,其中服务器选择视频流的最佳分辨率以匹配客户端和网络连接。博客文章《解释 Cloudflare 的 ABR 分析》对此进行了详细描述。

换句话说,数据以多种分辨率或采样间隔存储,并为每个查询选择最佳解决方案。

ABR的工作方式是在向ClickHouse写入请求时,它将数据写入多个具有不同采样间隔的表中。例如table_1存储100%的数据,table_10存储10%的数据,table_100存储1%的数据,table_1000存储0.1%的数据等等。表之间的数据是重复的。 Table_10 将是 table_1 的子集。

Demo

在 Cloudflare 中,我们使用内部库和工具将数据插入 ClickHouse,但这可以通过使用开源工具 - vector.dev 来实现。如果您想测试 ClickHouse 的日志摄取是如何工作的,您可以参考或使用https://github.com/cloudflare/cloudflare-blog/tree/master/2022-08-log-analytics的演示。

确保您已安装 docker 并运行docker compose up即可开始。这将打开三个容器,Vector.dev 用于生成矢量演示日志,将其写入 ClickHouse,ClickHouse 容器用于存储日志,Grafana 实例用于可视化日志。当容器启动后,访问 http://localhost:3000/dashboards 来使用预构建的演示仪表板。

总结

20231007180833

日志本质上应该是不可变的,而 ClickHouse 最适合处理不可变的数据。我们能够将关键且重要的日志生成应用程序之一从 Elasticsearch 迁移到更小的 ClickHouse 集群。

inserter 端的 CPU 和内存消耗减少了八倍。每个使用 600 字节的 Elasticsearch 文档在 ClickHouse 中减少到每行 60 字节。这种存储增益使我们能够在较新的集群中存储 100% 的事件。在查询方面,99分位的查询延迟也显著改善。

Elasticsearch 非常适合全文搜索,ClickHouse 非常适合分析!



 

不管是日志分析还是指标体系,都少不了监控告警。很多公司都会同时使用多个监控系统(云上的、云下的),导致监控事件散落各处,人员维护多份,缺少了告警聚合降噪、排班协同的能力。我们团队做了9年开源监控系统,深知大家的痛点,特推出 FlashDuty 事件 OnCall 中心的产品,一站式解决告警难题。

 
  • 产品介绍地址:https://flashcat.cloud/product/flashduty/
  • 产品注册体验:https://console.flashcat.cloud/

20231007182006

🛎️ 中心化告警处理,在正确的时间通知正确的人

20231007182021

20231007182028

💸 每一分钟都很关键,降低故障时间,就是赚钱

20231007182044

20231007182055

20231007182103

🖇️ 您常用的监控系统,我们都可以集成

20231007182128

告警事件的及时处理,对于线上稳定性保障至关重要。一款中心式的告警事件 OnCall 中心,去除告警风暴,确保告警不遗漏,还能分析故障处理的MTTA、MTTR等效率指标,您的团队值得拥有,快来免费体验起来吧:FlashDuty - 一站式告警响应平台。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Spring Boot】如何运用Spring Cache并设置缓存失效时间

简单描述 Spring Cache是一个框架,实现了基于注解的缓存功能,只需要简单地加一个注解,就能实现缓存功能。Spring Cache提供了一层抽象,底层可以切换不同的cache实现。具体就是通过CacheManager接口来统一不同的缓存技术。CacheMan…

Arduino驱动Si7021温湿度传感器(温湿度传感器)

目录 1、传感器特性 2、控制器和传感器连线图 3、驱动程序 Si7021温湿度传感器,应用了专用的数字模块采集技术和温湿度传感技术,具有极高的可靠性与卓越的长期稳定性。同时其体积小巧、精度高,特别是拥有毫秒级测试转换时间(DHT系列需要约2s的转换时间),启动测量与读…

【LeetCode刷题】--12.整数转罗马数字

12.整数转罗马数字 方法:模拟 分析罗马数字的规则是:对于罗马数字从左到右的每一位,选择尽可能大的符号值 根据罗马数字的唯一表示法,为了表示一个给定的整数num,寻找不超过num的最大符号值,将num减去该符…

UEC++ day7

敌人NPC机制 敌人机制分析与需求 新建一个character类来作为敌人,直接建蓝图设置骨骼网格,因为敌人可能多种就不规定死,然后这个敌人肯定需要两个触发器,一个用于大范围巡逻,一个用于是否达到主角近点进行攻击 注意我…

thinkphp8 DB_PREFIX 属性

设计表的时候使用**_user, **就是前缀,DB_PREFIX就是默认把前缀给去掉 在config/database.php prefix,改成你的前缀,数据库的表重命名‘ltf_user’ 代码调用 $user Db::name("user")->select();return json($user);之前是使用…

java springboot在测试类中构建虚拟MVC环境并发送请求

好 上文java springboot在测试类中启动一个web环境我们在测试类中搭了一个web环境 那么 下面就要想办法弄一个接口的测试 这边 我们还是要在controller包下去创建一个 controller类 写一个访问接口 这里 我创建一个 TestWeb.java 这里 我们编写代码如下 package com.example.…

九韵和声 饕餮盛宴丨音乐和声与校友情谊的完美交融

“九韻和聲”音樂會於11月19日晚上在深圳大劇院盛大舉行。來自各高校深圳校友會的逾千名同學們歡聚一堂,共同慶祝自己的合唱音樂會。 首次舉辦合唱音樂會 “九韵和声”音乐会由深圳市西安交通大学校友会牵头发起、主办,与深圳市清华大学校友会、深圳市浙…

国内外传输大文件有哪些好用又便宜的文件传输工具?

在当今数字化时代,数据已经成为企业和个人的重要资产,而文件传输则是数据流动的主要方式。无论是工作还是生活,我们都会面临需要传输大文件的场景,如视频制作、数据分析、软件开发等。然而,传输大文件并不是一项轻松的…

C语言的基础概念

1、编译和链接 C语⾔是⼀⻔编译型计算机语⾔,C语⾔源代码都是⽂本⽂件,⽂本⽂件本⾝⽆法执⾏,必须通过编译器翻译和链接器的链接,⽣成⼆进制的可执⾏⽂件,可执⾏⽂件才能执⾏。 C语⾔代码是放在 .c 为后缀的⽂件中的…

如何有效的禁止Google Chrome自动更新?

禁止Chrome自动更新 1、背景2、操作步骤 1、背景 众所周知,当我们在使用Selenium进行Web自动化操作(如爬虫)时,一般会用到ChromeDriver。然而Driver的更新速度明显跟不上Chrome的自动更新。导致我们在使用Selenium进行一些操作时就…

高校档案室建设标准-高校数字档案室建设需考虑哪些因素

高校档案室是高等教育机构所建立的档案存放与管理的机构,主要负责高校行政、教学、科研、文化和保密等方面的档案的收集、整理、保存、利用和管理工作。高校档案室是高等教育机构的重要组成部分,旨在为高校的历史研究、管理和服务提供必要的档案资源。同…

实战 | SQL注入漏洞

在页面参数增加 and -1-1,页面回显正常 这里如果 and 11 会被拦截 然后尝试-1-2 页面报错,此处存在数字型sql注入漏洞 接下来就是查字段数 order by 1 页面依旧报错 如果大家在渗透的时候遇到这种情况 要考虑是不是某些参数被拦截等 换一种思路&#xf…

OpenCV快速入门:目标检测——轮廓检测、轮廓的距、点集拟合和二维码检测

文章目录 前言一、轮廓检测1.1 图像轮廓的概念1.2 轮廓检测算法简介1.3 轮廓检测基本步骤1.4 轮廓检测函数说明1.4.1 轮廓发现1.4.2 轮廓面积1.4.3 轮廓周长1.4.4 轮廓外接多边形1.4.5 点到轮廓距离1.4.6 凸包检测 1.5 轮廓检测代码实现 二、轮廓的距2.1 几何距2.2 中心距2.3 H…

算法通关村第十二关-青铜挑战字符串

大家好我是苏麟 , 今天带来字符串专题 . 转换成小写字母 描述 : 给你一个字符串 s ,将该字符串中的大写字母转换成相同的小写字母,返回新的字符串。 题目 : LeetCode 709.转换成小写字母 : 709. 转换成小写字母 分析 : 这个题可以先遍历整个字符串…

设计模式-访问者模式-笔记

Visitor模式 动机(Morivation) 在软件构建过程中,由于需求的变化,某些类层次结构中常常需要增加新的行为(方法),如果直接在基类中做这样的更改,将会给子类带来很繁重的变更负担&am…

多目标应用:基于多目标粒子群优化算法MOPSO求解微电网多目标优化调度(MATLAB代码)

一、微网系统运行优化模型 微电网优化模型介绍: 微电网多目标优化调度模型简介_IT猿手的博客-CSDN博客 二、多目标粒子群优化算法MOPSO 多目标粒子群优化算法MOPSO简介: 三、多目标粒子群优化算法MOPSO求解微电网多目标优化调度 (1&…

springcloud整合seata我踩过的坑

版本问题 seata 1.5和1.5之前的目录结构不同,使用docker修改的配置文件也不同 1.4的左右 1.5之后docker 挂载文件也不同 1.5之前是使用自己写的挂载registry docker run -d -p 8091:8091 -p 7091:7091 --network newlead --name seata-serve -e SEATA_IP192.168.249.132…

万宾科技智能井盖传感器的特性一览

在不断发展的智慧城市技术领域,科学技术的创新永无止境。智能井盖传感器是科学进步带来的高科技产品,为促进城市生命线并保障地上地下连接点安全提供保障。它就在我们脚下,正在悄然改变城市基础设施和公共服务。智能井盖传感器成为现代城市规…

python 实现蚁群算法(simpy带绘图)

这里使用了蚁群算法求解了旅行商问题,同时结合了simpy来绘图 选择下一个食物的函数为: probability[i] pheromone[self.now][self.not_to_foods[i]] ** pheromone_w (1 / distance[self.now][self.not_to_foods[i]]) ** distance_w 该条路概率权重该点…

解锁潜力:创建支持Actions接口调用的高级GPTs

如何创建带有Actions接口调用的GPTs 在本篇博客中,我们将介绍如何创建一个带有Actions接口调用的GPTs ,以及如何进行配置和使用。我们将以 https://chat.openai.com/g/g-GMrQhe7ka-gptssearch 为例,演示整个过程。 Ps: 数据来源&#xff1a…