走在程序员的路上,久了总会碰到一些系统崩溃的事件。
在 2011 年 8 月份某个阴雨连绵的周一,北弗吉尼亚一个 1000 万瓦特的变压器发生爆炸,在整个电网中带来了庞大的突增瞬间电压,对亚马逊位于弗吉尼亚州阿什伯恩(Ashburn)的一个数据中心造成了重创,导致这个数据中心的主电源关闭。亚马逊的杰出工程师詹姆斯·汉密尔顿(James Hamilton)当时正巧开车驶入该数据中心停车场,对于阿什伯恩数据中心来说,汉密尔顿在那个时刻到来是一个意外的惊喜,正当他们遭遇重创时有「大圣」经过帮助处理这些棘手的问题,真是再好不过了。
初入猿道的第一次系统崩溃
当我还是一个稚嫩的小猿时,刚拿到公司 offer,还没毕业就去将来公司实习没多久就碰到了一次系统崩溃事件。一个稳定运行了十多年的老程序,从某一天开始就突然崩溃。一开始团队里经验老到的高工认为也许只是一个意外事件,先把程序重启起来让业务恢复。第一次崩溃重启后程序又恢复了平稳运行,安稳的一天就这么过去了。可从第二天开始,程序又莫名的崩溃了,然后我们又重启了,但没多久后再次崩溃了。《星际穿越》这部电影给大众普及的一个定律:墨菲定律,适时的生效了。
如果你担心某种情况发生,那么它就有可能发生。会出错的事,总会出错。
之后每一天这个程序崩溃的次数变得越来越频繁,团队里的人一时都反应不过来发生了什么。一个稳定运行了十多年的系统,怎么突然就这样了。而开发这个系统的程序员和公司早已不知所踪,我们公司只不过接手维护而已。费了老大劲终于从归档源码光盘中找回了当初这个系统的源代码,项目经理安排了几个高工展开了攻关,而我这个初来乍到实习生就负责盯着程序运行,发现进程意外退出就立刻重启。
两天后,高工们找到了原因并顺利修复了问题。触发的根源在于系统的交易量突然产生剧烈变化,而且这种变化是逐日大幅递增,第一次瞬时交易量突破临界点时,程序处理不当导致指针异常直接退出。而这个程序正是处理银行和证券公司之间资金进出的,当时正是 2006 年,中国 A 股悄然引来一场有史以来最大的牛市。
经历了这次事件,初入猿道的我开始明白系统崩溃这样的事件在我之后的道路上还将反复出现。
接踵而至的第二次系统崩溃
如我所料,第二次系统崩溃很快接踵而至。在我正式毕业入职公司后不到三个月,进入了当初实习的项目组。在组里我成了唯一一名 Java 程序员,因为当时银行的大部分核心交易类系统都是 C 写的,所以整个项目组有经验的高工基本是 C 程序员。后来 Java 企业应用兴起,一些管理类应用,银行也开始用 Java 来开发,所以一些老的 Java Web 维护项目也开始落在我们团队来维护,实际也就是我一人来维护了。
这次崩溃也来的突然,早上银行结售汇的业务负责人打来电话说系统出错了,总行今日下发的外汇牌价导入出错。外汇牌价导入不了,意味着整个今天的结售汇业务无法开展,分行相应窗口全部都得停业。项目经理立刻让我查看怎么回事,我尝试将数据文件导入,观察后台日志,果然报错。但这也是我刚接手的一个维护系统,代码还没来得及看两行呢,后端都是 Java 写的,所以团队里一堆 C 的高工此时也帮不上太多忙。但看那错误来自一个解析 Excel 的第三方开源库的错误堆栈,一时看不出个所以然,只是奇怪为啥昨天都可以,今天就不行了。
初步判断可能是数据文件格式变化了,拿出总行下发的过去几天的牌价文件人工比对。但肉眼逐行检查怎么也看不出区别,时间一分一秒的过去,一小时后故障升级到银行分行副行长那里,副行长也坐不住跑到信息部和信息部科长一起来过问到底发生了什么。我们的项目经理陪着说正在排查,估计副行长一看就我一个毛头小伙在处理这个问题,很不满的对项目经理说为啥不多安排几个资深工程师来看,项目经理石破天惊的来一句,说对这个问题我就是最资深的了。我回头瞥了一眼,银行信息部科长不置可否的对着项目经理讪笑一下,他是最了解我们这个外包维护团队成员构成的了。
副行长一行人站我背后看了有半小时,可能觉着短期内也解决不了,立刻电话通知业务部门公告系统维护升级,下周一才可办理结售汇业务,幸好当时是周五为我们争取了周末两天时间。当然最后我也查出了问题并顺利修复,确实是数据文件格式发生了变化,这种变化从界面上看不出,解析程序却能感知到并很不友好的直接抛错了。
第一次系统崩溃,我站在边缘处。这次崩溃,我则站在了爆炸的中心。经历这次崩溃事件,我开始领悟到那些「大圣」不仅有火眼金睛能发现 bug,还能看清能处理状况的人,身心皆如玄铁方能在爆炸的中心站的住。我只是幸运的站在「大圣」身边方能在爆炸中心安然无恙。
求助你的人让你成为了「大圣」
一年后,我离开了第一家公司,从银行转到了电信行业,适逢电信收购联通 CDMA 准备大力发展自己的移动业务时。公司定义了一套以配置适配不同省电信公司特定情况的产品,开发了快一年后,在当年底准备拿人口最少的电信省份海南做试点。我作为产品的主力开发人员自然被派到海南省支持现场实施,几个月后,处理了各种现场的意外情况后系统顺利上线,我也疲惫的回到广州。
在广州一个周末的晚上,我正在电影院看电影,海南现场维护的一个同事的电话响起,我犹豫着要不要接,在海南几个月几乎没有周末好不容易回了广州休整下又接到电话,正在犹豫中,电话响了几声后停了,我想如果紧急的话会再打的,但电影期间没再打过来。回到住处也没有电话再响起,我想可能也不是什么大问题已经处理好了就睡去了。半夜三点电话终于又再次响起,还是来自海南现场的同事,我挣扎起来接听了电话才知道出了大问题了,墨菲定律又生效了。
海南现场的同事先向我抱歉,他们本不想在我刚离开又在周末晚打电话过来,但确实他们出了状况已经搞不定了。我冲了把冷水脸清醒下,当时远程连不上海南局方的内网,只好通过同事 QQ 远程协助。因为适逢月底,一批计费结算的一大批量单突然下发,系统就陷入了崩溃边缘,磁阵 IO 跑满,而积压的工单按现场同事估算按这速度跑一天也跑不完,那到了白天开业新来的工单怎么办,所以没办法只好电话求助了。就这样从 3 点忙乎到早上 8 点,改了好几版程序优化 SQL,合并数据压缩等等,才终于把 IO 降下来,并顺利跑完昨天晚上的批量单。
这次事件后我反思,如果我若没能把这个突发状况搞定会怎么办?海南现场维护的同事还能向我求助,我当时还能向谁求助么?当时已没有比我更熟悉这个系统的人,原来求助我的人,已将我当成最后能降妖除魔的「大圣」。
在崩与不崩之间
之后,电信全集团发力推 3G 后,我们的产品卖了很多省,第一次试点在人最少的海南省出了一次大问题。后来又在人最多的浙江省出了另一次问题。本来浙江的单子是竞争对手用免费占坑策略拿下的,但用免费策略占了很多坑人却不够,所以浙江这边对手公司一直只有一个现场售前的人。浙江电信已经提前放了电视广告出去确定要在指定日期准时放号推广营业,但他们系统其实还没开始实施。临近 deadline 对方还没派人,局方毛了就拉了我们公司进场一起做,谁先做出来用谁了,而且不免费承诺了几千万的后续合同。
就这样我们的产品因为已经顺利实施了其他多个省份,所以进展很快,一个月左右现场对接实施基本全部完毕。到了电视广告的放号日,早上 8 点公司领导和局方领导全员到场,局方还请了埃森哲做咨询协调各厂方工作,埃森哲弄了个大屏幕监控各厂方系统上线业务情况和系统运行指标。然后就在 9 点一开门营业后不久,从最前端 CRM 和 BSS 系统来的大量工单就蜂涌而至(看来那次电视广告营销效果很不错)然后我们的系统就看着 CPU 不停的攀升,很快就变成了两条直线,两台 IBM 顶配的 128 U 小型机 CPU 全部跑满 100%,然后进入压单阶段。
压单是个什么体验呢,就是你跑去营业厅开了个新手机号,交了钱两小时还不能打电话,这比双十一买个东西晚一周送到要难受点吧。当时公司所有领域最好的技术人员全到齐了,有专门优化 Weblogic 的,有搞 Oracle 的,有厂商磁阵的专业支持,我和另外个同事负责应用性能,同样在现场看代码还能怎么优化。其实那个年代的瓶颈大部分都出在数据库上,应用都是围绕数据库为中心构建的,如今互联网公司这套分布式架构还闻所未闻。
只是奇怪瓶颈一般在数据库,怎么 CPU 那么高。后来通过分析发现是因为浙江电信有些特殊逻辑很大一部分是通过动态脚本由现场实施人员编写的(产品框架支持),这部分特别消耗 CPU,工单量一冲过来 CPU 立刻就飙升。我和另一个同事就在现场不停的把脚本的逻辑改成原生代码的实现,并立刻上线观察效果,改了几个比较重的脚本后,CPU 立刻就下来了。期间我们一直担心硬件先烧坏了,还好 IBM 的小型机质量还是过硬的,100% 跑了大半天。
其实这次系统再次走在崩溃边缘,但我并没有比以前更大的压力。我知道不管这次问题出在哪,会有相应领域的「大圣」能处理好。
走在程序员的路上,久了总会碰到一些系统崩溃的事件,很多时候并没有「大圣」踩着七色云彩来救你。系统崩溃就像老君的炼丹炉,「大圣」于其中练就火眼金睛,玄铁肉身,丹炉不崩溃,「大圣」何归来?
在程序猿们成长的路上,每一次系统崩溃事件都是一个不幸的开始,但未必会有一个不幸的结局。