云服务器价格_云数据库_云主机【优惠】最新活动-搜集站云资讯

天翼云_美剧乔伊百度云_返现

小七 141 0

Cloudflare每秒如何分析1M DNS查询

上周五,我们宣布了针对所有Cloudflare客户的DNS分析。由于我们的规模-当您读完本文时,Cloudflare DNS将处理数百万个DNS查询-我们必须在实现中创新。在这篇文章中,我们将描述组成DNS分析的系统,这些分析帮助我们每月梳理数万亿个这样的日志。原木是怎么从边缘进来的Cloudflare已经有一个用于HTTP日志的数据管道。我们想利用这个系统来进行新的DNS分析。每次我们的边缘服务收到HTTP请求时,它都会生成Cap'n Proto格式的结构化日志消息并将其发送到本地多路复用器服务。考虑到数据量,我们选择不记录完整的DNS消息有效载荷,只记录我们感兴趣的遥测数据,如响应代码、大小或查询名称,这使得我们平均每个消息只保留约150字节。然后将其与处理元数据(如时间信息和查询处理期间触发的异常)融合在一起。在边缘融合数据和元数据的好处是,我们可以将计算成本分散到数千台边缘服务器上,并且只记录我们绝对需要的内容。多路复用器服务(称为"日志转发器")运行在每个边缘节点上,将来自多个服务的日志消息集合起来,并将它们传输到我们的仓库,以便通过TLS安全通道进行处理。在仓库中运行的对应服务接收日志并将其分解为几个apachekafka集群。多年来,Apache-Kafka已经被证明是一种宝贵的服务,可以在生产者和下游消费者之间进行缓冲,防止消费者故障转移或需要维护时丢失数据。从0.10版开始,Kafka允许对副本进行支持机架的分配,这提高了对机架或站点故障的恢复能力,为我们提供了未处理消息的容错存储。有一个带有结构化日志的队列使我们可以回顾性地调查问题,而不需要访问生产节点,但事实证明有时这是相当困难的。在项目的早期,我们会浏览队列以找到所需的粗略时间间隔的偏移量,然后将数据以拼花格式提取到HDFS中进行离线分析。关于聚合HTTP分析服务是围绕生成聚合的流处理器构建的,因此我们计划利用apachespark将日志自动流式传输到HDFS。由于Parquet本机不支持索引或以避免全表扫描的方式排列数据,因此在API上进行在线分析或提供报表是不切实际的。有一些扩展,比如parquet index,可以在数据上创建索引,但不是动态的。鉴于此,最初的计划是只向客户显示聚合报告,并保留原始数据以供内部故障排除。聚合摘要的问题是,它们只适用于基数较低的列(一些唯一值)。使用聚合,给定时间范围内的每一列都会分解为与唯一条目数相等的行数,因此可以对响应代码(例如,只有12个可能值,但没有查询名称)进行聚合。域名受欢迎程度的影响,因此,例如,如果一个受欢迎的域名每分钟被请求1000次,那么每分钟聚合的行数可以减少1000倍,但实际上并非如此。由于DNS缓存的工作方式,解析程序将在TTL期间从缓存中回答相同的查询,而不必去权威服务器。TTL往往长于一分钟。因此,虽然权威服务器多次看到同一请求,但我们的数据倾向于不可缓存的查询,例如打字错误或随机前缀子域攻击。实际上,当按查询名称聚合时,我们可以看到0到60倍的行缩减,因此以多个分辨率存储聚合几乎会否定行缩减。聚合也是通过多个分辨率和键组合完成的,所以在高基数列上聚合甚至可以产生比原始列更多的行。由于这些原因,我们开始时只在区域级别聚合日志,这对于趋势来说足够有用,但是对于根本原因分析来说太粗糙了。例如,在一个案例中,我们正在调查我们的一个数据中心中短暂的不可用突发事件。拥有未聚合的数据允许我们将问题缩小到遇到延迟峰值的特定DNS查询,然后将查询与配置错误的防火墙规则关联起来。像这样的情况如果只使用聚合的数据就更难调查了,因为它只影响了聚合中丢失的请求的一小部分。所以我们开始研究几个联机分析处理系统。我们研究的第一个系统是德鲁伊。我们对这些功能以及前端(Pivot和以前的Caravel)如何对数据进行切片和分块,从而能够生成任意维度的报告,给我们留下了深刻的印象。Druid已经部署在类似的环境中,每天的事件数超过100B,因此我们确信它可以工作,但是在对采样数据进行测试之后,我们无法证明数百个节点的硬件成本是合理的。大约在同一时间,Yandex公开了他们的OLAP系统ClickHouse。然后它咔嚓一声ClickHouse的系统设计要简单得多——集群中的所有节点都具有相同的功能,并且只使用ZooKeeper进行协调。我们构建了一个由多个节点组成的小集群来启动测试,发现其性能相当令人印象深刻,并且与分析型数据库管理系统的性能比较结果相符,因此我们继续构建概念证明。第一个障碍是缺乏工具和社区规模小,因此我们深入研究了ClickHouse设计,以了解它是如何工作的。ClickHouse不支持直接从Kafka摄取,因为它只是一个数据库,所以我们在Go中编写了一个适配器服务。它从Kafka读取Cap'n Proto编码的消息,将它们转换成TSV,然后通过HTTP接口批量插入ClickHouse。稍后,我们重写了该服务,使用本地ClickHouse界面使用Go库来提高性能。从那时起,我们已经为项目贡献了一些性能改进。我们在摄取性能评估期间了解到的一件事是,ClickHouse摄取性能在很大程度上取决于批处理大小-一次插入的行数。为了理解原因,我们进一步研究了ClickHouse是如何存储数据的。ClickHouse用于存储的最常见的表引擎是MergeTree家族。它在概念上类似于Google的BigTable或apachecassandra中使用的LSM算法,但是它避免使用中间内存表,而是直接写入磁盘。这给它提供了极好的写吞吐量,因为每个插入的批处理都只按"主键"排序、压缩并写入磁盘以形成一个段。没有内存表或任何数据"新鲜度"的概念也意味着它只是附加的,不支持数据修改或删除。目前删除数据的唯一方法是按日历月份删除数据,因为数据段不会与月份边界重叠。ClickHouse团队正在积极努力使其可配置。另一方面,这使得写入和段合并没有冲突,因此摄取吞吐量与并行插入的数量成线性关系,直到I/O或核心饱和。然而,这也意味着它不适合小批量,这就是为什么我们依赖Kafka和inserter服务进行缓冲。ClickHouse会不断地在后台合并段,因此许多小部件将被合并并写入更多次(从而增加写入放大率),太多未合并的部分将触发严重的插入限制,直到合并进行为止。我们发现,在实时摄取和摄取性能之间进行折衷时,每表每秒进行几次插入的效果最好。表读取性能的关键是索引和磁盘上数据的排列。无论处理速度有多快,当引擎需要从磁盘扫描TB级的数据并只使用其中的一小部分时,都需要时间。ClickHouse是一个列存储,因此每个段为每一列包含一个文件,每一行都有排序的值。这种方法可以跳过查询中不存在的整列,然后可以并行处理多个单元格和矢量化执行。为了避免完全扫描,每个段也有一个稀疏索引文件。假设所有列都是按"主键"排序的,索引文件只包含第n行的标记(捕获的行),以便即使对于非常大的表,也能够将其保存在内存中。例如,默认设置是标记每8192行。这样,只需要122070个标记就可以稀疏地索引包含1万亿行的表,这很容易放入内存中。请参阅ClickHouse中的主键,以深入了解其工作原理。当使用主键列查询表时,索引返回考虑的行的大致范围。理想情况下,范围应该是宽而连续的。例如,当典型的用法是为单个区域生成报告时,将区域放在主键的第一个位置将导致每列中按区域排序的行,使单个区域的磁盘读取连续,而主要按时间戳排序则不会。行只能以一种方式排序,因此必须根据典型的查询负载仔细选择主键。在我们的例子中,我们优化了各个区域的读取查询,并为探索性查询提供了一个单独的表,其中包含采样数据。从中得到的教训是,我们没有试图为所有目的优化索引并分割差异,而是创建了多个表。一个这样的专业化是在不同区域上聚集的表格。由于没有机会从扫描中排除数据,所以跨所有行的查询成本要高得多。这使得分析师不太现实地进行比较