写点什么

降低领英私有云的 MTTD 和 MTTR

2016 年 11 月 24 日

我们将领英内部的云管理门户称之为 Nuage(法语中的“云”)。领英的开发者可以借此快速在领英的数据中心内新建数据存储,例如 Kafka 话题 Voldemort 存储,以及 Espresso 数据库等。该产品包含一个供领英的开发者使用的 HTTP 前段,以及一个与 Kafka 等底层系统通信的 rest.li 后端服务。

与领英的底层存储和流系统类似,Nuage 本身也是一种分布式系统,包含分布在多个数据中心内的数个前端和后端。与其他任何分布式系统类似,这个系统的调试不仅困难而且需要耗费大量时间。对于某些事件,可能需要找到每个服务涉及到的所有相关计算机,从这些计算机中读取特定时段内的日志,然后进行汇总和分析。具体到 Nuage 则需要找到相关数据中心,确定该数据中心内有关的前端和后端计算机,然后提取特定时段内的日志。

为了简化 Nuage 系统的调试并降低平均恢复时间(MTTR),我们执行了日志汇总、请求标记,以及用户体验异常报表等工作。下文将介绍日志汇总的相关设置,但首先想谈谈请求标记和用户体验异常报表,因为这些是进行日志汇总的前提条件。

请求标记和异常报表

如上文所属,Nuage 包含运行在不同宿主机上的前端和后端服务。为了简化调试工作,我们希望能轻松地将前端和后端事件信息关联在一起。为此我们会在前端生成一个随机的请求 ID,将其作为 HTTP 标头传递给 Nuage 后端。前端会在日志中记录发送至后端的请求(包括请求 ID)以及所获得的响应。在收到传入的请求后,后端会检查 HTTP 标头中的请求 ID,并将该请求 ID 添加至所关联的每一条日志信息中。后一个操作是通过 log4j 的映射诊断上下文环境(Mapped Diagnostic Context,MDC)实现的。MDC 实际上是一种“每线程”的映射,可以在日志输出格式化程序(Formatter)中引用。这样我们就可以将请求 ID 包含在与该请求有关的每一条日志项中,借此可解决一系列问题:

  1. 当有多个线程同时写入日志时,可以更简单地判断每条日志项与哪个请求有关。
  2. 使用 Grep 命令在日志中查找请求 ID 可找到所有相关日志项。
  3. 可以更方便地分析请求 ID 并将其插入 Elasticsearch 中一个独立的列,具体做法请参阅下一节。

Webserver.java – 为请求对应的线程加入请求 ID。

复制代码
import org.apache.log4j.MDC;
public void onRequest(request) {
String requestId = request.get(“x-req-id”);
MDC.put(“requestId”, requestId);
}

Log4j.xml – 将请求 ID 写入每条日志项。

复制代码
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{yyyy/MM/dd HH:mm:ss.SSS} [req-id-%X{requestId}] ..." />
</layout>

日志范例

除了这些宝贵的信息外,我们还设置了在前端或后端遇到非预期异常后向我们发送邮件通知,并在通知中包含方便进行调查所需的细节信息。选择邮件作为通知方式是因为这些异常本身没必要让我们立刻着手处理,现有的其他警报机制即可应对各种紧急问题。从下文的邮件范例中可以看到,我们可以直观地看到前端和后端的堆栈跟踪情况。邮件中还包含了触发这一异常的请求所对应的请求 ID,这样就可以更容易地找到日志中的所有相关日志项。

用户遇到异常后发送给 Nuage 开发团队的邮件范例。

复制代码
Nuage 发现了非预期异常
收件人:nuage-debugging
请求 ID:123456
用户:lideveloper
前端信息
所发送请求:
Rest.li 端点:d2://nuage ...
后端信息
响应:创建 Voldemort 存储 XYZ 时出现异常
...
状态代码:500

这样的设置已被证明在降低我们的平均检测时间(MTTD)方面非常有用。我们不再依赖用户上报自己使用前端过程中遇到的问题,可以在问题发生后立刻开始进行调试。借助邮件中包含的信息,我们可以通过下文将要介绍的 Elasticsearch、Logstash 和 Kibana(ELK)快速着手深入分析。

使用 Elasticsearch、Logstash 和 Kibana(ELK)进行日志汇总

ELK 堆栈使得我们可以将来自多个产品和宿主机的日志汇总在一起并进行集中搜索,借此可实现很多用例,例如可以回答注入“错误 X 的发生频率和每次发生位置是什么”或“上周以来异常率有何变化”等问题。ELK 各种组件的用途如下:

  • Elasticsearch:底层数据库;
  • Logstash:将日志解析为结构化格式并将其放入 Elasticsearch;
  • Kibana:一种对 Elasticsearch 数据进行可视化的 Web UI。

Logstash 可以在应用程序服务器上运行,或读取其他来源的日志。我们在领英内部的用法通常是在运行应用程序的服务器上使用 Kafka 生成器(Producer)发送日志,随后由 Logstash 使用 Kafka 消耗器(Consumer)读取日志,并在解析后将其发送至 Elasticsearch 集群。由于日志可以在其它计算机上处理,这种做法可以降低对服务器的影响。下图展示了 Nuage 的 ELK 工作流。

(点击放大图像)

作为我们Logstash 配置的一部分,我们会通过解析日志找到请求ID 并将其以一个单独的字段发送至Elasticsearch 的日志行中。

Logstash – 解析日志行并将请求 ID 放入相应字段。

复制代码
# Add the request ID to a separate field if one is present.
grok {
match => ["message", "\[req[\-]id[\-]\]$"]
}

借助这样的设置,直接在 Kibana 仪表盘中输入类似“request_id: ”这样简单的查询即可从前端和后端计算机获得与该请求有关的所有相关日志,这一过程中甚至不需要知道这个请求是由哪台计算机处理的。由于不再需要确定运行请求的计算机,无需通过 Grep 命令查找特定计算机的日志,无需确定特定请求相关的其他日志行还有哪些,我们的调试过程得以大幅简化,进而显著缩短了我们的 MTTR。

Kibana – 从 Elasticsearch 中获得与前端和后端有关的所有相关日志行。

搜索:request_id: 123456

结果:

日期

服务

宿主机

请求 ID

消息

nuage-frontend

host1

123456

用户 lidev 正在创建 Espresso 数据库

nuage-backend

host2

123456

正在处理来自 nuage-frontend 的新请求

nuage-backend

host2

123456

用户 lidev 被授权创建数据库

nuage-backend

host2

123456

正在将数据库定义上传至 Espresso host3

nuage-backend

host2

123456

数据库创建失败:到 host3 的连接超时

未来扩展

目前我们只将请求 ID 与 Nuage 前端请求和 Nuage 后端的处理和响应关联在一起。考虑到这个产品的本质,Espresso 或 Voldemort 等底层系统经常会遇到各种异常,因此我们可以对其进行一个简单的改进,让 Nuage 后端对收到的请求 ID 进行转发并在底层系统之间进行传递。随后来自该系统的响应也可以附加至调试邮件中,并可以使用 ELK,这样我们就可以在前端、后端,以及底层系统中查找与该请求 ID 有关的所有日志,在调试过程中针对日志信息获得更完整的视图。这就要求所有这些系统的日志必须全部发送至同一个 Elasticsearch 集群,或能够通过一个 Tribe 节点与多个 Elasticsearch 集群通信,这样即可在一个位置查看所有系统的日志。

结论

通过这样的 ELK 设置和请求标记,我们可以针对遇到的问题轻松查看所有相关日志。通过将这样的能力与包含触发用户体验异常的请求 ID 的邮件提醒配合使用,我们的私有云管理系统 Nuage 的 MTTD 和 MTTR 均有显著改善。如果你想进一步了解 Nuage 及其目标,建议阅读 Alex Vauthey 有关“隐形”基础架构的文章

作者: Gustaf Helgesson 阅读英文原文: Reducing the MTTD and MTTR of LinkedIn’s Private Cloud


感谢陈兴璐对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ @丁晓昀),微信(微信号: InfoQChina )关注我们。

2016 年 11 月 24 日 16:161149

评论

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

架构师训练营第二周

小树林

ARTS打卡Week 04

teoking

ios LeetCode ARTS 打卡计划

架构师训练营第二章课后作业

叮叮董董

基本的面向对象原则(Basic OO principles)

旭东(Frank)

编程思维 极客大学架构师训练营

一个包子铺看懂 I/O 模型演变

小眼睛聊技术

Java 程序员 架构 后端 nio

第二周作业

武鹏

架构师训练营 - 第二周 - 作业

韩挺

这也太拧巴了吧?结局意想不到

非著名程序员

程序员 程序人生 提升认知

架构师训练营二期作业

老姜

618你的系统顶住了么?系统发生重大灾难难道只能“删库跑路”?

夜来妖

架构师训练营 - 第二周架构师实现自己架构的主要手段

zcj

极客大学架构师训练营

什么是依赖倒置原则,为什么有时候依赖倒置原则又被称为好莱坞原则?

朱月俊

用接口隔离原则优化 Cache 类的设计

朱月俊

给行动找个理由

Neco.W

行动派 决策

第二次作业

朱月俊

第二次作业总结

朱月俊

小师妹学JVM之:GC的垃圾回收算法

程序那些事

JVM 「Java 25周年」 小师妹 JIT GC

数据库周刊28│开发者最喜爱的数据库是什么?阿里云脱口秀聊程序员转型;MySQL update误操作;PG流复制踩坑;PG异机归档;MySQL架构选型;Oracle技能表;Oracle文件损坏处理……

墨天轮

数据库

Week 02 学习总结

卧石漾溪

极客大学架构师训练营

架构师训练营第二章总结

叮叮董董

老大吩咐的可重入分布式锁,终于完美的实现了!!!

楼下小黑哥

Java redis 分布式锁

品软件架构原则模式之美

老姜

架构师训练营-第二章-依赖倒置原则&接口隔离原则

而立

极客大学架构师训练营

为什么坐车会晕车呢

石云升

生活,随想 日常思考 晕车

产品视角看推荐算法

峰池

人工智能 算法 产品经理 推荐算法

哪些框架是遵循依赖倒置原则的?

朱月俊

做一个有原则的码农可好?

Dawn

极客大学架构师训练营

千万不能让程序员给娃娃取名字

码农神说

程序员

第二周学习总结

武鹏

依赖倒置和案例

王锟

架构师训练营 - 第二周 - 学习总结

韩挺

InfoQ 极客传媒开发者生态共创计划线上发布会

InfoQ 极客传媒开发者生态共创计划线上发布会

降低领英私有云的MTTD和MTTR-InfoQ