Content Entry

动态追踪技术(上) - 漫谈 [章亦春]

  2016-05-09 01:19:06   Coding  

什么是动态追踪

我很高兴能在这里和大家分享动态追踪技术(Dynamic Tracing)这个主题,对我个人来说也是一个很激动人心的话题。那么,什么是动态追踪技术呢?

动态追踪技术其实是一种后现代的高级调试技术。它可以帮助软件工程师以非常低的成本,在非常短的时间内,回答一些很难的关于软件系统方面的问题,从而更快速地排查和解决问题。它兴起和繁荣的一个大背景是,我们正处在一个快速增长的互联网时代,作为工程师,面临着两大方面的挑战:一是规模,不管是用户规模还是机房的规模、机器的数量都处于快速增长的时代。第二方面的挑战就是复杂度。我们的业务逻辑越来越复杂,我们运行的软件系统也变得越来越复杂,我们知道它会分成很多很多层次,包括操作系统内核然后上面是各种系统软件,像数据库和 Web 服务器,再往上有脚本语言或者其他高级语言的虚拟机、解释器及即时(JIT)编译器,顶上则是应用层面的各种业务逻辑的抽象层次和很多复杂的代码逻辑。

这些巨大的挑战带来的最严重的后果就是,今天的软件工程师正在迅速地丧失对整个生产系统的洞察力和掌控力。在如此复杂和庞大的系统中,各种问题发生的概率大大提高了。有的问题可能是致命的,比如 500 错误页,还有内存泄漏,再比如说返回错误结果之类。而另一大类问题就是性能问题。我们可能会发现软件在某些时候运行的非常缓慢,或者在某些机器上运行得非常缓慢,但我们并不知道为什么。现在大家都在拥抱云计算和大数据,这种大规模的生产环境中的诡异问题只会越来越多,很容易占据工程师大部分的时间和精力。大部分问题其实是线上才有的问题,很难复现,或者几乎无法复现。而有些问题出现的比率又很小,只有百分之一、千分之一,甚至更低。我们最好能够不用摘机器下线,不用修改我们的代码或者配置,不用重启服务,在系统还在运行的时候,就把问题分析出来,定位出来,进而采取有针对性的解决办法。如果能做到这一点,那才是完美的,才能每晚都睡上一个好觉。

动态追踪技术实际就能帮助我们实现这种愿景,实现这种梦想,从而极大地解放我们工程师的生产力。我至今还记得当年在雅虎中国工作的时候,有时不得不半夜打车去公司处理线上问题。这显然是非常无奈和挫败的生活和工作方式。如今我工作在美国的一家 CDN 公司,我们的客户也会有自己的运维团队,他们没事就去翻 CDN 提供的原始日志。可能对我们来说是百分之一或者千分之一这样的问题,但是对他们来说就是比较重要的问题,就会报告上来,我们则就必须去排查,必须去找出真正的原因,反馈给他们。这些实际存在的大量的现实问题,激发着新技术的发明和产生。

我觉得动态追踪技术很了不起的一点就是,它是一种“活体分析”技术。就是说,我们的某个程序或者整个软件系统仍然在运行,仍然在线上服务,还在处理真实请求的时候,我们就可以去对它进行分析(不管它自己愿不愿意),就像查询一个数据库一样。这是非常有意思的。很多工程师容易忽略的一点是,正在运行的软件系统本身其实就包含了绝大部分的宝贵信息,就可以被直接当作是一个实时变化的数据库来进行“查询”。当然了,这种特殊的“数据库”须是只读的,否则我们的分析和调试工作就有可能会影响到系统本身的行为,就可能会危害到在线服务。我们可以在操作系统内核的帮助下,从外部发起一系列有针对性的查询,获取关于这个软件系统本身运行过程当中的许多第一手的宝贵的细节信息,从而指导我们的问题分析和性能分析等很多工作。

动态追踪技术通常是基于操作系统内核来实现的。操作系统内核其实可以控制整个软件世界,因为它其实是处于“造物主”这样的一个地位。它拥有绝对的权限,同时它可以确保我们针对软件系统发出的各种“查询”不会影响到软件系统本身的正常运行。换句话说,我们的这种查询必须是足够安全的,是可以在生产系统上大量使用的。把软件系统作为“数据库”进行查询就会涉及到一个查询方式的问题,显然我们并不是通过 SQL 这样的方式去查询这种特殊的“数据库”。

在动态追踪里面一般是通过探针这样的机制来发起查询。我们会在软件系统的某一个层次,或者某几个层次上面,安置一些探针,然后我们会自己定义这些探针所关联的处理程序。这有点像中医里面的针灸,就是说如果我们把软件系统看成是一个人,我们可以往他的一些穴位上扎一些“针”,那么这些针头上面通常会有我们自己定义的一些“传感器”,我们可以自由地采集所需要的那些穴位上的关键信息,然后把这些信息汇总起来,产生可靠的病因诊断和可行的治疗方案。这里的追踪通常涉及两个纬度。一个是时间纬度,因为这个软件还一直在运行,它便有一个在时间线上的连续的变化过程。另一个纬度则是空间纬度,因为可能它涉及到多个不同的进程,包含内核进程,而每个进程经常会有自己的内存空间、进程空间,那么在不同的层次之间,以及在同一层次的内存空间里面,我可以同时沿纵向和横向,获取很多在空间上的宝贵信息。这有点儿像蛛蛛在蛛网上搜索猎物。

蜘蛛在蛛网上搜索

PIC: 蜘蛛在蛛网上搜索

我们既可以在操作系统内核里面拿一些信息,也可以在用户态程序等较高的层面上采集一些信息。这些信息可以在时间线上面关联起来,构建出一幅完整的软件图景,从而有效地指导我们做一些很复杂的分析。这里非常关键的一点是,它是非侵入式的。如果把软件系统比作一个人,那我们显然不想把一个活人开膛破肚,却只是为了帮他诊断疾病。相反,我们会去给他拍一张 X 光,给他做一个核磁共振,给他号号脉,或者最简单的,用听诊器听一听,诸如此类。针对一个生产系统的诊断,其实也应如此。动态追踪技术允许我们使用非侵入式的方式,不用去修改我们的操作系统内核,不用去修改我们的应用程序,也不用去修改我们的业务代码或者任何配置,就可以快速高效地精确获取我们想要的信息,第一手的信息,从而帮助定位我们正在排查的各种问题。

我觉得大部分工程师可能特别熟悉软件构造的过程,这其实是咱的基本功了。我们通常会建立不同的抽象层次,一层一层的把软件构造起来,无论是自底向上,还是自顶向下。建立软件抽象层次的方式很多,比如通过面向对象里面的类和方法,或者直接通过函数和子例程等方式。而调试的过程,其实与软件构造的方式刚好相反,我们恰恰是要能够很轻易地“打破”原先建立起来的这些抽象层次,能够随心所欲的拿到任意一个或者任意几个抽象层次上的任何所需的信息,而不管什么封装设计,不管什么隔离设计,不管任何软件构造时人为建立的条条框框。这是因为调试的时候总是希望能拿到尽可能多的信息,毕竟问题可能发生在任何层面上。

正因为动态追踪技术一般是基于操作系统内核的,而内核是“造物主”,是绝对的权威,所以这种技术可以轻而易举地贯通各个软件层次的抽象和封装,因此软件构造时建立的抽象和封装层次其实并不会成为阻碍。相反,在软件构造时建立起来的设计良好的抽象与封装层次,其实反而有助于调试过程,关于这点,我们后面还会专门提到。我在自己的工作当中经常会发现,有的工程师在线上出问题的时候,非常慌乱,会去胡乱猜测可能的原因,但又缺乏任何证据去支持或者否证他的猜测与假设。他甚至会在线上反复地试错,反复地折腾,搞得一团乱麻,毫无头绪,让自己和身边的同事都很痛苦,白白浪费了宝贵的排错时间。当我们有了动态追踪技术之后,排查问题本身就可能会变成一个非常有趣的过程,让我们遇到线上的诡异问题就感到兴奋,就仿佛好不容易又逮着机会,可以去解一道迷人的谜题。当然了,这一切的前提是,我们具有趁手的强大的工具,帮助我们进行信息采集和推理,帮助我们快速证明或否证任何假设和推测。

动态追踪的优点

动态追踪技术一般是不需要目标应用来配合的。比如说,我们在给一个哥们做体检的时候,他还在操场上奔跑,我们就能在他还在运动的过程中,直接给他拍一张动态的 X 光,而且他自己还不知道。仔细想一下,这其实是一件很了不起的事情。各种基于动态追踪的分析工具的运行方式都是一种“热插拔”的方式,就是说,我们随时可以运行这个工具,随时进行采样,随时结束采样,而不用管目标系统的当前状态。很多统计和分析,其实都是目标系统上线之后才想到的,我们并不可能在上线前预测未来可能会遇到哪些问题,更不可能预测我们需要采集的所有信息,用以排查那些未知的问题。动态追踪的好处就是,可以实现“随时随地,按需采集”。另外还有一个优势是它自身的性能损耗极小。仔细写出的调试工具对系统的极限性能的影响,通常在百分之五,甚至更低的比例以下,所以它一般不会对我们的最终用户产生可以观察到的性能影响。另外,即使是这么小的性能损耗也只发生在我们实际采样的那几十秒或者几分钟以内。一旦我们的调试工具结束运行,在线系统又会自动恢复到原先百分之百的性能,继续向前狂奔。

被检查的小人在奔跑

PIC: 被检查的小人在奔跑

链接引用:

继续阅读: 动态追踪技术(中)

comments loading