2012年8月1日,Knight Capital向8台订单路由服务器中的7台部署了新代码。第8台上仍然运行着公司2003年就已停用的代码,而新代码复用了一个原本用来开启这段旧代码的功能开关。45分钟内,它执行了400万笔交易,给Knight留下超过4.6亿美元的亏损。关于这件事最权威的复盘出自监管机构之手,其中的每一条教训,对今天任何使用功能开关发布代码的人依然适用。
要点
![]()
Knight的路由器SMARS为纽约证券交易所一个8月1日启动的项目获得了新代码。一名技术人员手动把它复制到了8台服务器中的7台上,没有人复核。
新代码复用了原本用来开启Power Peg的开关。Power Peg是2003年就已停用、但从未删除的功能。在第8台服务器上,"是"仍然意味着Power Peg。
Power Peg的停止条件在2005年被移动过,此后从未重新测试,于是它无休止地发送订单:400万笔成交、3.97亿股、154只股票。
开盘前,97封写着"Power Peg已停用"的邮件已经到达。它们不是警报,所以没有人据此行动。而实盘中的修复动作——卸载新代码——让问题变得更糟。
SEC在其首例市场准入规则案件中對Knight处以1200万美元罚款。Knight需要4亿美元救助,并在数月内与GETCO合并。
2012年8月1日Knight Capital发生了什么
主要来源是SEC的行政令,编号34-70694,发布于2013年10月16日。它共十页,按段落编号,几乎不用形容词。下面的时间线来自这份文件和Knight自己提交给EDGAR的备案(均为美国东部时间)。
该行政令没有给出员工何时干预或订单何时停止的确切分钟,只说"大约45分钟"。最终确认的已实现亏损超过4.6亿美元,纽约时报将其折算为大约每分钟1000万美元。
SMARS是什么,Power Peg又是什么?
SMARS是Knight的订单路由器,SEC的描述是"一个自动化、高速、算法驱动的路由器,把订单送进市场"。它把客户的母订单拆成子订单,分发到各家交易所。仅SMARS一个系统,就处理了美国上市股票交易量的约1%。
2012年,纽约证券交易所准备在8月1日启动零售流动性项目(RLP),Knight为此写了新的SMARS代码。新代码替换掉的是一段未使用的功能:Power Peg,Knight在2003年就已停用,但按行政令的说法,它依然"存在且可被调用"。
SEC没有说明Power Peg原本是做什么的,只留下一个关键细节:它带有一个累计数量计数器,也就是那句"母订单已成交,停止发送子订单"的检查。2005年,Knight把这个计数器挪到了代码中更靠前的位置,并且没有对Power Peg重新测试(第14段)。没人需要测,它是一段死代码。此后七年,这个判断一直成立。
被复用的功能开关如何唤醒了死代码
整起事故的核心,是SEC行政令第13段的一句话:
新的RLP代码还复用了一个原本用来激活Power Peg代码的开关。
按计划,Power Peg已经不存在了,这个旧开关被设为"是",就会打开RLP。部署持续了几天,由一名技术人员完成,没有第二个人复核,也没有书面流程要求有人复核(第15段):
Knight的一名技术人员没有把新代码复制到8台SMARS计算机服务器中的一台。Knight没有安排第二名技术人员审查这次部署。
于是8月1日那天,同一个开关在两批服务器上代表了两件不同的事。基于行政令描述(而非Knight代码)的简化示意如下:
# 基于SEC第13-16段的示意草图,并非Knight源代码
if order.flag == "yes":
run_rlp(order) # 1到7号服务器:新代码
# run_power_peg(order) # 8号服务器:旧代码仍在这里,
# 而它的停止条件在2005年被移动过
在1到7号服务器上,RLP订单被正确处理。而到达8号服务器、且开关被设为"是"的订单,会启动Power Peg,它"连续地……以极快的顺序……完全不考虑已成交的股数"发送子订单(第16段)。212个母订单,变成了数百万个子订单和400万笔成交。
损失不只落在Knight头上。有75只股票,Knight的成交量占到当日交易量的20%以上,价格波动超过5%;其中37只,它的成交量超过一半,价格波动超过10%(第18段)。
为什么45分钟里没有人叫停?
这是事故第二天Hacker News上的第一个问题。salman89写道:"我搞不懂为什么45分钟里没有任何人工干预。他们连一个盯着交易的人都没有吗?"SEC的行政令从四个角度回答了这个问题。
第一,警告发进了一个收件箱。从早上8点01分起,一个内部系统开始发送关于SMARS的邮件,内容"描述了一个被称为'Power Peg已停用'的错误"。Knight的系统一共发出了97封这样的邮件(第19段)。它们被发给一组员工,但设计上不是警报,没有人据此采取行动。
第二,限额没有接到任何东西上。未匹配的成交堆积在一个叫"33号账户"的持仓账户里,这个账户有200万美元的总量限额。该限额没有与任何自动化控制相连(第23至25段)。人工盯着的风险监控系统PMON,既不显示这些限额,在高交易量下还会滞后。
第三,没有关闭开关。没有任何机制去比对从SMARS发出的订单和进入SMARS的订单,而且"Knight也没有针对自身异常活动叫停SMARS运行的流程"(第21段)。
第四,修复动作让事情变得更糟。没有书面的应急处置流程,团队在开市状态下做了一个听起来很合理的决定:回滚。
Knight把新的RLP代码从7台部署正确的服务器上卸载了。这一操作加剧了问题。
新代码一撤,那个开关在全部8台服务器上都会触发Power Peg(第27段)。回滚只有在旧版本本身安全时才安全,而这里的旧版本里就藏着那个bug。
根因:为Knight Capital做一次git blame
人们很容易把责任归到那名技术人员身上……
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.