写点什么

如何解决看起来不可能的工程问题?

  • 2015-08-07
  • 本文字数:2396 字

    阅读完需:约 8 分钟

Scalyr 是一个基于云的服务器日志监控工具。其官方博客曾发表过一篇文章,描述如何使用蛮力方法实现数十 GB 日志数据的秒级查询。在对所有日志进行实时探索性分析时,那是个行之有效的方法,但无法实现 Scalyr 某些功能(如仪表板、预警)所需要的、TB 级数据的秒级查询。近日,前谷歌员工、Scalyr 创建者 Steve Newman 撰文介绍了他们如何遵循如下两个原则解决该问题:

  • 常用的用户行为对应简单的服务器行为;不常用的用户行为则可以对应复杂的服务器行为
  • 寻找一种可以简化关键操作的数据结构

Steve 指出,重定义可以让一个看似不可能的挑战变得容易处理,而这两个原则有助于寻找一种合适的重定义方法。

“不可能”的问题

Scalyr 提供了许多服务器监控和分析工具。为了支撑这些工具,他们将每项功能都实现为一个通用数据集上的一组查询。有些功能需要多个查询。例如,仪表板可以包含任意数量的图表,每个图表又包含多条曲线,而每条曲线对应一个复杂的日志查询。假如一个自定义的仪表板容包含十二个图表,每个图表 4 条曲线,用户选择了一个时间跨度为一周的仪表板视图,而他们每天生成的日志量为 50GB,那么,就需要在 350GB 的数据上执行 48 个查询。没有哪个蛮力算法可以在零点几秒内提供查询结果。同样,预警功能也会产生大量的查询。Scalyr 的日志预警可以触发非常复杂的条件,比如,过去10 分钟内99% 的Web 前端响应时间超过800 毫秒。单个用户可能有成百上千的预警,它们每分钟就需要计算一次。而通常,预警查询对延迟很敏感,需要在几毫秒内响应。

重定义问题

综上所述,仪表板和预警都会产生大量的查询,但都不能接受太长的查询执行时间。所幸,它们有一个共同点:查询事先已知,查询很常用,而新查询很少。按照上文提出的原则,他们需要一种可以简化仪表板和预警查询的数据结构,哪怕创建查询变得复杂也可以接受。

Scalyr 支持多种输出结果,包括文本、数值、直方图和键 / 值数据。不过,仪表板和预警查询总是生成一个数组。每个查询定义了一个时间上的数值函数,可能是“每秒产生的错误信息”、“服务器 X 上的空闲磁盘空间”等。执行查询就意味着使用函数求值,计算结果为数值序列,每个数值对应一个特定的时间区间。

他们通过预计算来简化函数求值过程。他们采用的数据结构非常简单:每个查询对应一个数组。查询每隔 30 秒执行一次,并输出一个数值。他们将那个数组称为“时间序列(timeseries)”。例如,用户仪表板上有一张图表,上面显示了 Web 服务器池产生 5xx 错误的速率。为此,他们创建了一个时间序列,每 30 秒记录一个错误数:

这样,他们就可以快速生成任意时段的图表(为了生成更长时段的图表,他们还以逐步增大的时间间隔存储一些冗余数组)。

时间序列维护

当有日志消息到达时,他们需要对每个相关时间序列进行增量更新。例如,如果一个新的 Web 访问消息包含有介于 500-599 之间的状态码,那么他们就需要增加对应特定时间间隔的“5xx 错误”时间序列的计数器。这里有个问题,就是针对一个新消息,如何确定哪些时间序列需要更新。由于仪表板和预警查询通常使用相同的字段进行过滤,如主机名、指标名,所以他们使用这些字段构建了一棵决策树,通过它快速确定与日志消息匹配的候选时间序列列表。

Steve 举了一个例子。假如有十二个时间序列,遵循下面的消息选择标准:

复制代码
host="frontend1" && metric="memfree"
host="frontend1" && metric="diskfree"
host="frontend2" && metric="memfree"
host="frontend2" && metric=diskfree"
host="backend1" && metric=memfree"
host="backend1" && metric=diskfree"
host="backend2" && metric="memfree"
host="backend2" && metric="diskfree"
pool="webapp" && status >= 400 && status <= 499
pool="webapp" && status >= 500 && status <= 599
pool="api" && status >= 400 && status <= 499
pool="api" && status >= 500 && status <= 599

这些时间序列可以组织成下面这样一棵决策树:

如果收到了下面这样一条消息:

复制代码
host=frontend1
metric=memfree
value=194207

则该消息会从决策树的根节点开始匹配,首先会进入host=“frontend1”host=[any]节点。从host=“frontend1”向下,可以进入metric=“memfree”节点,并匹配到该节点下的时间序列(host="frontend1" && metric="memfree");从host=[any]节点向下,未能找到匹配的分支,不再向下匹配。就是说,在这种情况下,只需要检查时间序列host="frontend1" && metric="memfree"是否需要更新。而对于消息host=frontend1, metric=memfree, pool=webapp,则需要检查 3 个时间序列。

决策树生成算法

决策树生成采用了一个简单的贪婪算法:

  1. 找出所有用于==检验并在至少一个时间序列中出现的字段名(比如,上例子中的 _host_、metric_ 和 _pool)。
  2. 根据每个字段名划分时间序列。如果一个时间序列无法匹配该字段值域中的某个值,那么就将其划分到 [any] 组。计算每个组中时间序列的数量,并找出最大的组。在上例中,_host_ 字段产生了 4 个大小为 2 的组和一个大小为 4 的组([any] 组)。因此,最大组的大小为 4。
  3. 创建一棵树,其根字段要能够使最大组最小化。在上例中,如果以 _host_ 和 _metric_ 字段为根节点,则最大组的大小均为 4;如果以 _pool_ 字段为根节点,则最大组为 [any],大小为 8。因此,可以使用 _host_ 和 _metric_ 的其中一个作为根节点,而不使用 _pool_。
  4. 在每棵子树上递归执行步骤 3。

在 Steve 举的一个例子中,与蛮力算法相比,该算法带来了 33 倍的性能提升。在实际的生产环境中,它对性能的提升更明显。

另外,Steve 还列举了一些具体的实现细节,此处不再一一赘述。感兴趣的读者可以查看原文


感谢徐川对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ @丁晓昀),微信(微信号: InfoQChina )关注我们,并与我们的编辑和其他读者朋友交流(欢迎加入 InfoQ 读者交流群InfoQ 好读者)。

2015-08-07 08:002736
用户头像

发布了 1008 篇内容, 共 441.1 次阅读, 收获喜欢 346 次。

关注

评论

发布
暂无评论
发现更多内容

迎接物联网时代,区块链大有可为

CECBC

云计算 大数据 区块链技术

Docker 镜像构建之 Dockerfile

哈喽沃德先生

Docker 容器 微服务

科普小知识:区块链与分布式系统

CECBC

区块链 分布式

甲方日常2

句子

工作 随笔杂谈 日常

Redis系列(二):Redis的5种数据结构及其常用命令

简爱W

《搞定1》读书笔记

超超不会飞

聊聊微服务

炜娓道来程序人生

架构 微服务 SOA

Redis系列(一):Redis简介及环境安装

简爱W

性能相关,内存

Linuxer

性能

零代码简史

明道云

SaaS

面经手册 · 第7篇《ArrayList也这么多知识?一个指定位置插入就把谢飞机面晕了!》

小傅哥

Java 数据结构 面试 小傅哥 ArrayList

为什么中国出了这么多厉害的互联网公司,但没有自己设计过编程语言?

代码制造者

编程语言 低代码 企业信息化 零代码 编程开发

区块链是一个有去无返的奇幻旅程

CECBC

区块链

Apache Pulsar 2.6.1 版本正式发布:2.6.0 功能增强版,新增 OAuth2 支持

Apache Pulsar

消息队列 Apache Pulsar 消息系统 消息中间件

【Elasticsearch 技术分享】—— ES 查询检索数据的过程,是什么样子的?

程序员小航

Java elasticsearch 搜索 ES Lucene Elastic Search

使用 K8s 进行作业调度实战分享

后端进阶

学习 Kubernetes 容器 k8s 调度式分布

Luajit字节码分析之KSTR

whosemario

lua

解决数据指数级增长挑战,英特尔如何又快又好提供领导力产品?

最新动态

Android |《看完不忘系列》之dagger

哈利迪

android

难以遏制的人因差错-Go的日志工具之痛

田晓亮

微服务 Go 语言

CRM企业到底该不该做PaaS?

ToB行业头条

PaaS SaaS CRM

前端智能化的加速时刻:华为机器视觉的创新方程式

脑极体

月度工作汇报,为什么要全球直播?

赵新龙

TGO鲲鹏会 技术社区 开源社区

炒股不要看K线图(分享最近学习投资的一点心得)

Nick

投资 理财

Woman、man、camera、TV:如何做一个完整的深度学习应用

LeanCloud

学习 程序员 互联网 容器 LeanCloud

有选择才会有困惑

escray

学习 面试

第11周总结+作业

林毋梦

OPPO互联网DevSecOps实践

OPPO安全

DevOps 安全

面试官再问你Http请求过程,怼回去!

架构师修行之路

HTTP TCP/IP

Java | 你知道快速搭建一个spring boot项目该怎么做吗?

简爱W

Flink-键值分区状态-10

小知识点

scala 大数据 flink

如何解决看起来不可能的工程问题?_语言 & 开发_谢丽_InfoQ精选文章