从指标中获得更多价值的简单方法

2020-05-30 21:43:48

当我刚开始在Twitter工作时,我花了一天的时间构建了一个系统,它立即找到了7位数的优化(最终交付了),这是一个从指标中获得更多价值的简单方法。在第一年,我们每年的发货量达到8位数,因此节省了成本。该系统引入的关键功能是能够查询所有主机和所有服务以及任何时间段(自创建以来)的指标数据,因此我们在内部将其称为LongTermMetrics(LTM),因为我喜欢枯燥、描述性的名称。

这是在我寻找一个入门项目时开始的,这个项目既能帮助我理解Twitter基础架构,又能有一些容易量化的价值。Andy Wilcox建议查看一些大型服务的JVM残存空间利用率。如果您不熟悉生存空间是什么,您可以将其视为JVM中的一个可配置的固定大小的缓冲区(至少如果您使用Twitter默认的GC算法)。当时,如果您查看随机的大型服务,您通常会发现以下两种情况之一:

缓冲区太小,导致性能较差,有时在高负载下会出现灾难性的性能下降。

但是,我们没有考虑随机服务,而是没有根本的理由不能查询所有服务,并获得哪些服务的配置有改进空间的列表(按性能降低或成本节约排序)。如果我们编写针对JVM幸存空间的查询,这也适用于其他配置参数(例如,其他JVM参数、CPU配额、内存配额等)。由于数据一致性和性能问题的结合,编写适用于所有服务的查询结果比我希望的要困难一些。数据一致性问题包括以下问题:

任何给定的指标都可以有大约100个名称,例如,我为JVM幸存者空间找到了94个不同的名称,我怀疑还有更多,这些只是我可以通过简单搜索找到的名称。

即使集群管理器启动了碎片的新实例,僵尸碎片仍可以继续操作和报告指标,从而导致特定碎片名称的指标重复且不一致。

我们的指标数据库MetricsDB专门处理监控和仪表盘,不支持一般查询。这是完全合理的,因为在马斯洛的可观察性需求层次结构中,监控和仪表板的级别低于一般指标分析,但这意味着我们不能对MetricsDB中的指标运行任意SQL查询。

查询数据的另一种方式是使用以Parquet格式写入HDFS的副本,这允许人们运行任意SQL查询(以及使用数据的写入烫伤(MapReduce)作业)。

不幸的是,由于指标名称的数量,HDFS上的数据不能以每个名称一列的列格式存储--如果您提供给它太多的列,而我们有足够多的不同指标,那么Presto就会不高兴,以至于我们远远超出了这个限制。如果您不使用列格式(并且不应用任何其他技巧),您最终将读取任何重要查询的所有数据。其结果是,您无法在不超时的情况下跨所有服务或所有主机运行任何不重要的查询(甚至许多不重要的查询)。我们没有类似的烫伤超时,但烫伤性能要差得多,根据集群负载,针对一天的指标进行简单的烫伤查询通常需要3到20个小时,这使得使用烫伤进行任何类型的探索性数据分析都是不合理的。

考虑到已经存在的数据基础架构,解决这两个问题的简单方法是编写一个快速作业来存储我们关心的与性能或容量相关的查询所需的0.1%到0.01%的指标数据,然后将其重写为列格式。这样做的一个令人高兴的副作用是,由于数据中只有一小部分是相关的,因此无限期存储它是便宜的。标准指标数据转储在几周后被删除,因为它足够大,无限期存储它的成本高得令人望而却步;较长的指标内存对于容量规划或其他更喜欢使用历史数据的分析非常有用。

我们重新保存的0.01%到0.1%的数据包括(但不限于)每个服务的每个实例的以下内容:

虽然这个项目的动机是找出哪些服务是为JVM幸存者空间配置的低于或超过配置,但它从GC和容器指标开始,因为这些都是非常明显的东西,从那时起,我们一直在递增地添加其他指标。(##39;{##**$$}。如果您稍微了解一下SQL,为了了解我们可以查询的内容种类以及查询有多简单,下面是一些示例:

这是查找供应不足/供应过剩服务的原始目标的一部分。任何具有非常高的p90JVM残存空间利用率的服务都可能在残存空间上配置不足。类似地,高峰负载下具有非常低的p99或p999 JVM残存空间利用率的任何东西都可能被过度配置(这里没有显示查询,但我们可以将查询的范围限定在高负载的时间)。

如果结果为(SELECT servicename,Approx_DISTINCT(SOURCE,0.1)作为近似源,--服务的实例数--REAL QUERY使用[合并和nullif](https://prestodb.io/docs/current/functions/conditional.html)来处理边缘情况,为简明起见省略了近似_PERCENTIAL(jvmSurvivorUsed/jvmSurvivorMax,0.9))作为p90_Used,Approx_Percententile(jvmSurvivorUsed/jvmSurvivorMax,0.9)AS p50_Used。=';2020-02-28';GROUP BY SERVICE NAME)SELECT*FROM RESULTS WHERE Approx_Sources>;100 ORDER BY P90_USED Desc。

我们不需要查看一大堆仪表板,只需获得一个列表,然后将包含配置更改的差异发送给适当的团队,或者编写一个脚本来获取查询的输出并自动编写差异。上面的查询提供了任何基本利用率数字或比率的模式;您可以使用类似的查询查看内存使用情况、新的或旧的Gen GC频率等。在一个案例中,我们发现一项服务浪费了足够的RAM来支付我十年的工资。

我已经不再使用针对简单百分位数的阈值来查找问题,就像在这个查询中一样,但我之所以提出这个查询,是因为这是人们通常想做的事情,这很有用,相反,我更喜欢做的事情超出了本文的讨论范围,可能应该有自己的帖子。

上面的查询涉及所有服务,但我们也可以跨主机进行查询。此外,我们还可以执行针对主机属性、功能标志等的连接查询。

使用一组查询,我们能够确定,即使主机级别的网络利用率很低,也有大量服务超出了网络限制。然后,计算平台团队逐步推出了对网络上限的更改,我们使用类似下面的查询进行了监控,以确定我们没有发现任何性能下降(理论上,如果增加网络上限会导致主机或交换机达到网络限制)。

随着网络的变化,我们能够观察到更小的队列深度、更小的队列大小(以字节为单位)、更少的数据包丢弃等等。

为简洁起见,下面的查询仅显示了队列深度;添加提到的所有数量只需键入更多名称即可。

我们可以做的一般事情是,对于平台或服务级别功能的任何特定推出,我们都可以看到对实际服务的影响。

WITH ROLLED AS(SELECT--ROLLUT在时间段内为所有主机固定,可以从时间段ARBULTY(element_at(misc,';egress_rate_Limit_increase';))中选择任意元素作为ROLLUP,HOSTID FROM LTM_DEPLIES WHERE DS=';2019-10-10';和zone=';foo';group by ipAddress),host_info as(选择ARBitrary(NicSpeed)作为nicSpeed,hostSpeed。和zone=';foo';GROUP BY ipAddress),HOST_ROLLED AS(SELECT ROLLUT,nicSpeed,Rolled.hostID FROM ROLLED JOIN HOST_INFO on Rolled.ipAddress=host_info.ipAddress),CONTAINER_METRICS AS(SELECT SERVICE,netTxQlen,hostID from LTM_CONTAINER WHERE DS&>39;2019-10-10&39;和DS<;=';2019-10-10-。)SELECT SERVICE,NICSPEED,Approx_Percententile(netTxQlen,1,0.999,0.0001)as P999_qlen,Approx_Percentle(netTxQlen,1,0.99,0.001)AS p99_qlen,Approx_Percententile(netTxQlen,0.9)AS p90_qlen,Approx_Percententile(netTxQlen,0.68)AS p68_qlen,Rollout,Count(*)AS cnt from CONTAINER_。

哪些主机在控制负载后,其上的每项服务的服务级别性能都异常差?

除了对主机级负载的一般影响之外,哪些服务不能很好地与其他服务配合使用?

故障切换或其他高负载事件对延迟有什么影响?考虑到未来的高负荷事件加上当前的增长,我们应该预计未来的负荷水平是多少?

哪些服务在故障转移期间会看到更多负载,哪些服务会看到不变的负载,哪些服务介于两者之间?

我们可以对任何固定大小的缓冲区或分配进行哪些配置更改,以便在不增加成本或降低成本的情况下提高性能而不降低性能?

等等,如果您可以针对历史指标数据编写任意查询,那么很多问题都会变得很容易回答。

LTM是一个尽可能枯燥乏味的系统。每一个设计决策都离不开走阻力最小的道路。

为什么要用烫伤呢?这是Twitter的标准,它的集成让一切都变得微不足道。我试过Spark,它有一些优点。然而,在那个时候,我必须做手工集成工作,这是我通过烫伤免费获得的。

为什么系统不是实时的(延迟至少一个小时)?Twitter的批处理作业流水线很容易构建,所有需要做的就是阅读一些关于它如何工作的教程,然后编写一些相似但业务逻辑不同的东西。

在我加入Twitter的几年前,有一份写得很好的提案,要为我撰写的指标数据建立一个实时分析渠道,但这个提议从未实现,因为(我估计)制作一个MVP需要一到四个季度的工作,而且不清楚哪个团队有合适的授权来做这件事,而且还有四分之四的员工可用。但是添加批处理作业需要一天的时间,您不需要为一天的工作制定路线图和计划会议,您只需这样做,然后逐步进行后续工作即可。

为什么要使用Presto,而不是像Druid这样允许实时切片和骰子查询的工具?丽贝卡·艾萨克斯(Rebecca Isaacs)和乔纳森·西姆斯(Jonathan Simms)正在做跟踪方面的相关工作,我们知道我们会想要跨LTM和他们创建的任何东西进行连接。这对Presto来说是微不足道的,但至少在当时,需要更多的规划和与德鲁伊这样的东西合作。

为什么不用Postgres或类似的东西呢?我们要存储的数据量使得这在没有大量工作的情况下是不可行的;即使数据存储的成本相当低,它仍然是一个大数据问题。

我认为写这样的系统,只是无聊的工作,真的是被低估了。我读到的不成比例的帖子和演讲都是关于使用热门技术的系统。我并不反对热门的新技术,但是很多有用的工作都来自于将枯燥乏味的技术组合在一起,并做一些显而易见的事情。由于关于枯燥工作的帖子和讨论相对较少,我认为写这样的东西比它有任何权利更有用。

例如,几年前,在马特·辛格(Matt Singer)为我们这个规模的公司组织的一次本地会议上(基本上就是比FB/亚马逊/谷歌(Google)规模更小的公司),我问道,是否有人在做与我们刚刚做过的事情类似的事情。没有人在场(或者不会承认这一点),来自两家不同公司的工程师对我们能够存储如此多的数据表示震惊。这项工作太直接、太明显,不可能是新奇的,我敢肯定人们在很多地方都建立了类似的系统。它实际上只是将指标数据无限期地存储在HDFS上(或者,如果您更喜欢使用更一般的术语,则称为数据湖),其格式允许交互查询。

如果您在我们规模级别的公司中为这样的项目计算指标数据存储成本,那么存储成本基本上是一个舍入误差。几十年来,我们已经发运了单独的差异化产品,可以轻松支付存储成本。我认为,当人们部署成本高得多的分析和可观察性工具时,存储几年甚至十年的指标应该是令人震惊的,这是没有任何理由的。但事实证明,这是令人惊讶的,部分原因是人们不会写出如此无聊的工作。

一个不相关的例子是,不久前,我在一家类似规模的公司遇到了一个人,他想从他们的指标数据中获得类似的见解。他们不是从像这个项目这样需要一天时间的事情开始,而是从深度学习开始。虽然我认为将ML和/或统计数据应用于基础指标是有价值的,但他们将一个可以在几个人天后为公司带来显著价值的项目变成了一个耗时数人年的项目。如果你只打算在有基础经验和简单统计模型的人的指导下应用简单的启发式方法,或者天真地应用深度学习,我认为前者实际上会给你带来更好的结果。同时应用复杂的STATS/ML和从业者指导的启发式方法比单独应用两者都能获得更好的结果,但我认为从一个简单的项目开始,这个项目需要一天的时间来构建,可能需要一两天才能开始应用,而不是从一个需要几个月或几年的项目开始构建并开始应用,这要有意义得多。但人们对做更大的项目有很多偏见:它能做更好的简历项目(深度学习!),在很多地方,它能做更好的宣传案例,人们更有可能就使用深度学习的酷系统发表演讲或撰写博客文章。

上面讨论了为什么写作工作对整个行业都很有价值。我们在上一篇帖子中谈到了为什么写工作对公司写工作是有价值的,所以我不打算在这里重复这一点。

我认为这是不幸的,你不能听到系统的缺点,没有反向渠道闲聊,所以现在回想起来,我所做的事情都是非常明显的错误。回想起来,当其他事情变得显而易见时,我会补充这一点。

理想世界中的几乎所有东西都不是双精度的,有些东西不是双精度的,但我们的指标堆栈中的所有东西都会经历一个阶段,在这个阶段,基本上每个指标都会转换为双精度。

我将大多数应该是整型的东西都存储为整型,但是从长整型转换到双精度长整型只可能引入比仅仅从长整型双精度转换更多的舍入误差。

我将一些不应该是整数类型的内容存储为整数类型,这会导致小值不必要地丢失精度幸运的是,这并没有对我所做的任何可操作分析造成严重错误,但有些分析可能会导致问题。

在代码中,长期与长期的对比当我第一次写这篇文章的时候,我不确定这应该以哪种方式大写,当我做出决定时,我没有对所有以错误方式编写的东西进行grep,并将其压碎,所以现在这种毫无意义的不一致存在于不同的地方。

这两种情况都是当你想得太快,想得不够透彻的时候,你会想到的。后者很容易修复,也不是什么大问题,因为在Twitter无处不在地使用IDE意味着,基本上任何受影响的人都会让他们的IDE为他们提供正确的大写字母。

前者更有问题,因为它实际上可能导致不正确的分析,而且修复它将需要迁移我们拥有的所有数据。我的猜测是,在这一点上,这将是半周到一周的工作,我可以通过多花30秒思考我正在做的事情来很容易地避免这一点。

这一周的大部分时间都花在了Twitter堆栈的各个部分,我估计对于一个已经熟练掌握Scala、滚烫和我们的指标堆栈的人来说,这将是一天的工作。

一天也只是对初始数据集的工作量的估计。从那时起,我可能又做了几周的工作,韦斯利·阿普特卡尔-卡塞尔和库纳尔·特里维迪也投入了大量时间,我估计到目前为止总共花了大约1-2个人月的时间。

我也没有计算使用数据集或调试问题所花费的时间,其中包括我只能粗略猜测的大量时间,例如,当计算平台团队由于一些数据分析花费了大约一个小时而更改了网络出口限制时,暴露了一个潜在的Mesos错误,这可能花费了伊利亚·普罗宁(Ilya Pronin)一天的时间。大卫·麦基(David Mackey)花了相当多的时间追踪奇怪的问题,这些问题的数据显示发生了一些奇怪的事情,但我们没有。我怀疑,如果您想要完全考虑对本文中讨论的数据集进行数据分析后花费在工作上的时间,再加上我们的JVM、OS和HW团队等平台级团队之间的时间,我们大概只有1个人一年的时间。

[返回]