使用 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 - 一站式告警响应平台。

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

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

相关文章

Nginx - 本机读取服务器图像、视频

目录 一.引言 二.安装 Nginx 1.安装 By apt 2.安装 By 官网 三.配置 Nginx 1.Linux 机器配置 2.重启 Nginx 服务 3.本机查看机器文件 四.总结 一.引言 前面介绍了 GFP-GAN、PNG2GIF、GIF2PNG 等操作,我们生成的 video、gif、png 等形式的文件都存储在 lin…

【FPGA】Verilog:升降计数器 | 波纹计数器 | 约翰逊计数器 | 实现 4-bit 升降计数器的 UP/DOWN

目录 Ⅰ. 理论部分 0x00 升降计数器(UP DOWN Counter) 0x01 波纹计数器(Ripple Counter) 0x02 约翰逊计数器(Johnson Counter) Ⅱ. 实践部分 0x00 实现:升降计数器(4-bit&…

Unity - 实现模型动态伸长缩短,贴图不变形(材质球参数篇)

思路为修改模型材质球的Tiling参数&#xff0c;根据与自身localScale的值得到合适的比例&#xff0c;再修改Tiling值 var mat target.transform.GetComponent<Renderer>().material; var oriValue mat.mainTextureScale;//沿着Y轴伸缩 oriValue.y 1 * target.transfo…

使用DHorse发布SpringBoot项目到K8S

前言 在介绍DHorse的操作之前&#xff0c;先来介绍一下使用k8s发布应用的步骤&#xff0c;以SpringBoot应用为例进行说明。 1.首先从代码仓库下载代码&#xff0c;比如GitLab&#xff1b; 2.接着进行构建&#xff0c;比如使用Maven&#xff1b; 3.如果要使用k8s作为编排&am…

MySQL - 4种基本索引、聚簇索引和非聚索引、索引失效情况

目录 一、索引 1.1、简单介绍 1.2、索引的分类 1.2.1、主键索引 1.2.2、单值索引&#xff08;单列索引、普通索引&#xff09; 1.2.3、唯一索引 1.2.4、复合索引 1.2.5、复合索引经典问题 1.3、索引原理 1.3.1、主键自动排序 1.3.2、索引的底层原理 1.3.3、B 树和 B…

海康威视监控相机的SDK与opencv调用(非工业相机)

1.研究内容 本篇主要对海康威视的监控相机的SDK回调进行研究&#xff0c;并于opencv结合&#xff0c;保存图像,以供后续其他处理&#xff0c;开发语言为C 2.步骤及方法 2.1 海康SDK介绍 海康SDK下载地址 根据自身编译环境&#xff0c;下载对应的SDK&#xff0c;需要注意的是…

wincc定时器功能介绍

1定时器功能介绍 WinCC中定时器的使用可以使WinCC按照指定的周期或者时间点去执行任务&#xff0c;比如周期执行变量归档、在指定的时间点执行全局脚本或条件满足时打印报表。WinCC已经提供了一些简单的定时器&#xff0c;可以满足大部分定时功能。但是在有些情况下&#xff0c…

SpringBoot:ch02 配置文件(日志)

前言 简单介绍 Spring Boot 中常见的配置文件类型&#xff0c;如 application.properties 和 application.yml 等&#xff0c;并说明它们各自的特点和用途。 一、前期准备 1、新建项目&#xff0c;结构如下 2、添加依赖 <?xml version"1.0" encoding"UTF…

OpenLayers入门,OpenLayers6的WebGLPointsLayer图层样式运算符详解

专栏目录: OpenLayers入门教程汇总目录 前言 本章讲解使用OpenLayers6的WebGL图层显示大量点情况下,列举出所有WebGLPointsLayer图层所支持的所有样式运算符大全。 二、基于的OpenLayers版本 "ol": "^6.15.1"使用npm安装依赖npm install ol@6.15.1使…

html页面直接使用elementui Plus时间线 + vue3

直接上效果图 案例源码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title><script src"../js/vue3.3.8/vue.global.js"></script><link rel"styles…

英语六级范文模板

目录 现象解释 观点选择 问题解决 六级只考议论文&#xff0c;我们将从现象解释&#xff0c;观点选择&#xff0c;问题解决三个角度给出范文&#xff1a; 多次使用的句子&#xff0c;就可以作为模板记下来~~ 现象解释 In the contemporary world, the ability to meet cha…

VPX 插座(VITA46)介绍及应用 (简单介绍)

1. VPX 插座的介绍 VPX是VITA(VME International Trade Association, VME国际贸易协会)组织于2007年在其VME总线基础上提出的新一代高速串行总线标准。VPX总线的基本规范、机械结构和总线信号等具体内容均在ANSI/VITA46系列技术规范中定义。VPX就是基于高速串行总线的新一代总线…

LeetCode977.有序数组的平方(双指针法、暴力法、列表推导式)

LeetCode977.有序数组的平方 1.问题描述2.解题思路3.代码4.知识点 1.问题描述 给你一个按 非递减顺序 排序的整数数组 nums&#xff0c;返回 每个数字的平方 组成的新数组&#xff0c;要求也按 非递减顺序 排序。 示例 1&#xff1a; 输入&#xff1a;nums [-4,-1,0,3,10] …

竞赛选题 行人重识别(person reid) - 机器视觉 深度学习 opencv python

文章目录 0 前言1 技术背景2 技术介绍3 重识别技术实现3.1 数据集3.2 Person REID3.2.1 算法原理3.2.2 算法流程图 4 实现效果5 部分代码6 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 深度学习行人重识别(person reid)系统 该项目…

虚拟机配置网络ip,主打一个详细

文章目录 一、前言二、安装vim编辑器三、检查联网状态1. 使用ping命令 四、查看ip五、ens33网卡六、开机启动ens33网卡七、获取子网地址和子网掩码八、配置网关与子网掩码1. 编辑虚拟网络信息2. 配置网关3. 配置ens33网卡信息 九、动态ip配置十、静态ip配置 一、前言 本文主要…

Linux ps -ef|grep去除 grep --color=auto信息

linux 监控 进程判断是否启动可通过该指令实现 ps -ef|grep java指令结果为 # -v 参数有过滤作用 ps -ef|grep java |grep -v grep

Redis事务+秒杀案例

Redis事务是一个单独的隔离操作&#xff0c;是指将多条命令放在一个命令队列当中&#xff0c;按顺序执行&#xff0c;保证多个命令在同一个事务中执行而不受其他客户端的影响。 通俗来说就是&#xff1a;串联多个命令防止别的命令插队。 1.Multi、Exec、discard 在输入Multi命…

nginx配置-超详细

背景 安装nginx之后&#xff0c;会自动生成很多的文件&#xff0c;但是nginx.conf这个文件是我们的核心&#xff0c;如何去正确的修改和优化它是nginx的核心。在配置之前&#xff0c;需要看懂它的配置。鉴于经常需要配置&#xff0c;再次记录一下 一、nginx的默认配置 #user …

【C++】类和对象(6)--运算符重载

目录 一 概念 二 运算符重载的实现 三 关于时间的所有运算符重载 四 默认赋值运算符 五 const取地址操作符重载 一 概念 C为了增强代码的可读性引入了运算符重载&#xff0c;运算符重载是具有特殊函数名的函数&#xff0c;也具有其返回值类型&#xff0c;函数名字以及参数…

【UE】线框材质

一、方式1 新建一个材质&#xff0c;混合模式设置为“已遮罩”&#xff0c;勾选“双面” 勾选“线框” 然后可以随便给一个自发光颜色&#xff0c;这样最基本的线框材质就完成了 二、方式2 新建一个材质&#xff0c;混合模式设置为“已遮罩”&#xff0c;勾选“双面”&#x…