Skip to content
This repository has been archived by the owner on Mar 14, 2019. It is now read-only.
zhongl edited this page Aug 3, 2012 · 2 revisions

HouseMD的诞生并非一次艳遇的产物, 而是一个酝酿了两年的结晶.

日期: 2010-04-06 关键字: TimeTunnel2

2010年我开始参与TimeTunnel2的开发, 目标是为全网日志提供可靠的收集分发渠道, 其架构与消息中间件非常类似.

TimeTunnel是原阿里妈妈用于日志收集的系统, 2010年TimeTunnel团队加入到我所在团队后, TimeTunnel开始了2.0的开发, 简称TimeTunnel2. 同年底, TimeTunnel2淘蝌蚪上发布开源.

当时我在网络服务器开发上经验尚浅, 加上单元测试不太能覆盖持续高负载下暴露的诡异问题, 一旦问题出现了, 还是要依赖打印的日志来可视化服务器的行为和状态, 再进一步分析原因, 找解决办法.

为什么不用断点调试? 确实, 在自己的开发环境中, 系统与外部的交互是自己可控的, 断点调试是首选. 但在交互变得频繁, 复杂, 不可控, 又是多线程并发的情况下, 断点调试不是那么容易. 最关键的问题还是, 断点意味着线程阻塞, 有些问题是在高负载的情况才会出现的, 用了断点问题就无法重现了.

我很反感在代码充斥着各种DEBUG日志, 它们会使得代码看上去不是那么干净, 干扰关键逻辑的阅读. 可是问题来的时候, 没有它们又没有其他更好的办法, 为此我每次都要纠结于要不要在这里或那里写上一段打印调试的语句.

为了不让自己再纠结下去, 一定要有个一劳永逸的办法, 我想到了AOP.

大部分关于AOP的资料中都会以日志作为其典型应用场景, 显然实现它是不难的. 综合考虑后, 我在TimeTunnel2 中使用Google-Guice实现对所有被管理对象的所有方法切面增强(即方法进入和退出进行"日志埋点"), 并提供一个配置接口, 以限定需要输出调用调试日志的方法范围.

这样做了之后, 代码清爽了不少. 在开发环境调试的过程中, 也很方便的通过修改配置, 来实现按需输出方法调用日志. 后来, 为了方便生产环境中快速调试, 借助JMX实现动态修改配置的接口, 不错很先进.

爽了没多久, 便发现一些问题:

  • 日志埋点的对象太多, 一些对象频繁创建会带来性能上的损耗
  • 输出的内容(如参数值, 返回值)的范围和格式不能灵活调整, 还是得修改代码, 重新编译
  • 能够显示的信息还是太有限了

日期: 2010-11-11 关键字: BTrace, TimeTunnel2, Hadoop

同年11月, 我看到公司牛P毕玄写的一篇博客, 是介绍了BTrace的, 看后惊呼"神器出现"! 因为它改变我以往调试程序的思维方式, 强大的脚本定制特性, 驱使我欣喜若狂地研究它所有的范例, 心想着TimeTunnel2线上诊断调优就全靠它了.

毕玄(花名), 真名林昊, 网络ID是bluedavy. 他是国内OSGI第一人, 加入淘宝后 成为淘宝3.0架构的核心人物之一, 公司内外技术影响力强大. 他是将BTrace引入淘宝的人, 此后还写两篇博客分享了使用BTrace解决问题的案例.

不负众望, 在BTrace帮助下我解决不少实际问题, 为此我还将BTrace和常用脚本作为TimeTunnel2发布包的一部分, 这样部署到生产环境后, 用起来就很方便了.

这里不得不提一下BTrace的一个更有分量的成功案例. 当时, 淘宝Hadoop平台的应用已经上了规模, Hive的引入大大提升了离线数据分析作业的开发效率, 每日剧增的作业量和数据量, 使得本身已是集群性能瓶颈的NameNode每况愈下. 我们的Hadoop技术专家周忱想到了BTrace, 编写了一段脚本在作业高峰期的时候收集NameNode内部调用的性能数据, 这些数据指导了后续优化方向, 并且收效喜人.

周忱(花名), 真名周敏, 网络ID是coderplay. 2009年当时还是实习生的他, 就已经成为淘宝第一个Hadoop平台的核心人物, 在构建基于Hive的数据仓库平台上, 他的贡献也是至关重要的.

日期: 2011-08-15 关键字: BTrace, Hadoop, ADFS

2011年, 我的工作从TimeTunnel2转移到了TBFS的开发上. 历时大半年的开发, 为了确保平滑上线, 我们基于社区的测试用例做了很多功课. 但直觉告诉我, 一旦上线肯定还会有我们没有预想到的问题. 产品永远不可能完美, 即使如此也不能放任问题不管. 试想, 要是我们能缩短发现问题到解决问题的周期, 降低问题影响面, 这也是相当值得做的一件事情.

TBFS 是淘宝自主研发的NameNodeHA方案, 现已经更名为ADFS (Ali Distributed File System), 现在也已开源在Github.

我最先想到的还是BTrace, 它的强大已无需再多言, 可是用过的人, 应该都会有这样一些经历:

  • 修改脚本时拼写错误导致代码校验失败, 只得改好再来;
  • 修改的正则表达式匹配的范围过大(或小), 得调整调整再来;
  • 打印输出的信息不够, 改吧;
  • ......

每多一次反复, 可能十多秒或半分钟就过去了, 不知不觉就错过了发现问题的最好时机. 编辑器一开一关, 一天就过去了.

当然, 如果是经验足够, 事先准备好一些常用脚本模版, 配合动态语言, 倒是可以加快一点速度. 呵呵, 要想把BTrace玩得出神入化, 还是有些门槛的.

另外, BTrace有个让我不能接受的问题, 就是每次退出后, 它所增强过的字节码是不会被还原的, 这意味一旦某些消耗性能的脚本被应用后, 除非目标进程重启, 不然它们依然还在那儿起作用.

直到写本文为止, BTrace的最新版也未解决这个的问题, 不过最近的源码显示他们有解决的办法啦, 敬请期待吧.

不过, 还是有个奇淫技巧可以实现不用重启进程也可以让上一次的增强失效的办法, 就是准备一个脚本里面只有一个空方法, 但一定要保证脚本被应用的范围要覆盖上一次的, 然后用这个脚本Attach目标进程, 成功后立即结束, 就达成了. 原理这儿就不细说了, 这不是技术贴.

下一步, 就是怎么改进BTrace了. 本以为动手写个Patch就可以搞定的, 但一番研究后, 发现这其实是脚本灵活机制的代价. 看来我得依着它这个葫芦画个小瓢出来啊.

两周后, 我写了一个Demo验证了自己动手的可能性, 这为后来的HouseMD打下关键的基础.

这个Demo我放到了Github上, 非常适合对其中原理感兴趣的人研究一下.

日期: 2012-06-13 关键字: HouseMD, Notify

令人遗憾的是Demo写好之后, 我并未一蹴而就的完成一个实用的版本, 因为一些事情就搁置了.

一晃10个月过去了, 我的工作一如既往的又转移了, 现在是加入到Notify的团队.

Notify是淘宝2009年自主研发的消息中间件, 一直沿用至今, 其地位比肩各大核心业务系统.

Notify是连接各大核心业务系统的信息管道, 由于其系统环境的复杂性, 加上消息异步传输的特点, 使得业务系统在开发中诊断调试问题的难度较高. BTrace仍旧在其中扮演重要角色, 正如前文所述, 改进BTrace是非常值得做的一件事情. 于是, 这驱使我两个月前开始继续之前未完成的任务.

4月30日, HouseMD内部仓促发布第一个版本0.1.0, 由于并没有解决BTrace最痛的问题, 而且在复杂的容器环境中还会导致目标进程运行异常, 我保持低调立即投入0.2.0的开发.

一个月后, 我重写了大部分的代码, 加强了测试, 引入了可交互的特性以加快诊断问题的迭代过程(改变了BTrace的诊断模式), 还在易用性上花费了些心思, 0.2.0发布了!

乘热打铁, 我鼓足勇气在微博上@了一群公司的牛P们帮我推一把(这里真心的感谢他们), 反响远远超出了我的预期. 当天, HouseMD就跻身Github上Scala这个语种下当日被Watch和被Fork的双料榜首. 这让我动力百倍, 面对网上随之而来疑问和建议, 迅速在接下来的两周, 依次发布了0.2.10.2.2.

HouseMD现在被Watch的人数已经过百, 但我依然感觉有遗憾. 开发HouseMD的初衷仅仅只是为了方便自己, 但过程中意识到它应该能帮助到更多苦逼在一线的程序员, 可惜我一个人的力量是有限.

我一个人无法让HouseMDJava一样跨平台!

我一个人无法让HouseMD在每种特定应用场景下都能用着很方便!

我一个人无法让HouseMD没有任何Bug!

我一个人无法让HouseMD......

我希望HouseMD不是我一个人的HouseMD, 而是所有工作在Java平台上的工程师们的HouseMD!

Clone this wiki locally