首页 文章详情

Knightmare,DevOps警告故事 - 4亿资产的骑士资本如何在45分钟内因部署失败而破产 | IDCF

DevOps | 1087 2020-08-21 05:56 0 0 0
UniSMS (合一短信)

本文主要译自两份材料:“https://dougseven.com/2014/04/17/knightmare-a-devops-cautionary-tale/”以及“DevOps in Finance”,并经过译者整理和分析总结。

译者:冬哥


前言



这是一家拥有近4亿美元资产的公司如何在45分钟内因部署失败而破产的故事,本文从DevOps的视角复盘骑士资本集团Knight Capital Group的破产案例。
2012年8月1日,因为一个 Bug 被部署到生产环境,45分钟内环环相扣的错误,让骑士资本在交易中损失了 4.65 亿美金,进而导致破产。
这个故事涉及的代码库,是一个巨大的、无人维护、散发着“坏味道”的代码库,而肇事代码本身将近 9 年没有被用过,却依然留存在代码库中。真是集合了所有典型技术债务的一次惨案。
分析案例的同时,我们也希望借用这个真实的故事,来讨论让部署完全自动化和可重复的重要性,这也是DevOps /持续交付的核心部分。


背景



骑士资本集团Knight Capital Group是一家位于美国的全球金融服务公司,主要的业务涉及三大块,做市商业务、电子交易执行服务业务、以及机构销售和交易业务。
截止2012年,骑士资本是美国股票市场最大的交易商,交易份额占到纽约证券交易所交易总量的17.3%,纳斯达克证券市场(NasdaqStock Market)的16.9%。骑士资本平均每天管理超过33亿笔交易,每天交易超过210亿美元,日交易总量达到全美金融证券市场的10%。
截止2012年7月31日,骑士资本拥有约3.65亿美元的现金和等价物。
纽约证券交易所计划于2012年8月1日推出新的零售流动性计划RLP(该计划旨在通过类似骑士资本这样的经济商向普通投资者提供更优惠的股票交易价格)。为此,骑士资本准备更新其自动化算法程序SMARS,SMARS是骑士资本自主开发的一款智能型的高频交易软件系统。
SMARS的核心功能之一是从骑士资本交易平台的其他组件接收订单(“父”订单),然后拆分并发送一个或多个“子”订单以执行。换句话说,SMARS将从交易平台接收大笔订单,然后将其分解成多个小笔订单,以找到与股票数量匹配的买家/卖家。父订单越大,就将生成越多的子订单。
SMARS的本次更新主要是为了把过时或没用的功能替换掉,比如说“Power Peg”。自2003年之后PowerPeg模块就已经被弃用,2005年其中的检验功能被软件开发人员从PowerPeg模块中删除,移植到其他的模块中继续使用(分单功能依然在,却没了检验功能)。这个功能已经 8 年没有用到过了( 8 年都没用到的功能代码仍然存在,这的确很稀奇,但这不是重点)。更新后的代码对以前用来激活 Power Peg 功能的Flag进行了更改。这次更新经全面测试后证明安全可靠,那么问题出在哪?


可能出错的地方就一定会出错?的确!



从 2012 年 7 月 27 日至 31 日,骑士资本把软件手动部署到公司为数不多的服务器上——总共就 8 台。以下是美国证交会关于这次人工部署过程的档案描述(顺便一提,如果你的操作被记录到证交会档案里可就大事不妙了)。
“在部署过程中,相关技术人员忘记把新代码拷贝到这八台服务器其中的一台上。骑士资本也没有安排另外的技术人员对部署过程进行复查,所以没有人意识到第八台机器上的 Power Peg 代码并没有被删除,新的 RLP 代码也没有被添加。对于复查,骑士资本并没有相关的书面流程。 
—— 美国证监会SEC文件 | 发布编号 70694 | 2013-10-16”
美国东部时间 2012 年 8 月 1 日早上 9:30 ,股市开盘,骑士资本开始处理来自 RLP 新项目的交易商的订单。其中七台正确部署的服务器开始正确地处理订单。但是发向第八台服务器的订单触发了被更改的标识符,并从死角处恢复了旧的Power Peg代码。


来自「僵尸」代码的攻击



我们得弄清楚这段「僵尸」代码是用来干什么的。这个功能以前是用来对比买/卖股票的父订单和子订单的数额的。父订单数额一旦达标,Power Peg 就会向系统反馈停止订单拆分。总的来说,Power Peg 功能会跟踪子订单并在父订单完成后停止它们。然而 在2005 年,骑士资本把将这一跟踪检查功能挪走了(因此 Power Peg 不再具备跟踪计数功能了)。
当第八台服务器上的 Power Peg 功能被激活后,Power Peg功能开始拆分并执行子订单,但是由于它无法跟踪对比父订单的股票数,所以子订单被不断的产生并执行,这就成了无法终止的死循环。


45分钟的地狱



想象一下,当一个失去追踪计数功能的“智能型”高频交易软件系统,疯狂的、高速地、毫无限制的向市场发出订单,是什么情况?!

  • 9:30,市场开放,立即有人意识到出了问题。
  • 9:31,一分钟后,华尔街大部分人都感觉到大事不妙了,股票市场中某些个股涌现出大量不符合常规交易量的订单。
  • 9:32,又过了一分钟,人们发现交易仍然没有停止——就高速交易系统而言,交易根本停不下来。为什么没人尝试停止出问题的系统呢?事后发现,这个系统根本没有切断开关kill-switch。
  • 在 45 分钟之内,骑士资本执行了超过日均交易额 50% 的订单,导致部分股票市值上升超过 10%,带来的连锁反应是其他股票价格暴跌。

更糟的是,早在上午的 8:01(这时 SMARS 在进行开市前交易),骑士资本的系统就自动发送了有关问题的邮件。这些标记为 SMARS 的邮件提及 Power Peg 功能出现了问题。从 8:01 到 9:30,共有97 个骑士资本人员的邮箱收到了这封邮件。然而,这些电子邮件并没有设计为系统警报,因此没有人立即查看它们。天呐。

在这灾难性的 45 分钟里,骑士资本尝试了几种对策来终止错误的交易。由于这个系统没有切断开关(也没有相关情况的文档说明),因此他们只能在每分钟交易 800 万股的线上环境中诊断问题。然而他们无法确定是什么原因导致了错误的订单,因此他们做出的反应是卸载掉已经部署到几台服务器上的新代码。

换句话说,他们删除了工作代码并留下了损坏的代码。这导致情况进一步恶化,除了第八台未被正确部署的服务器,另外七台服务器中的父订单也触发了 Power Peg 功能。最后,他们终于想办法终止了交易系统,然而已经过去了 45 分钟。

在开市后的 45 分钟内,骑士资本接收并处理了 212 个父订单,SMARS 发出了数百万个子订单,累计对 154 支股票进行了 400 万次交易,交易量超过3.97亿股。

在内行人看来,骑士资本建立了 80 支个股 35 亿美元的净多头仓位和 74 支个股 31 亿 5000 万美元的净空头仓位。用非专业人士的话来解释,骑士资本在 45 分钟内亏损了4.6亿美元。

请记住,骑士资本仅有3.65亿美元。仅仅 45 分钟内,骑士资本从美国股市最大的交易商和纽交所以及纳斯达克的大庄家变得一文不值。破产后,骑士资本有 48 小时的时间筹集资金弥补损失(他们设法从大约六名投资者那里获得了4亿美元的投资)。

骑士资本Knight Capital Group最终于2012年12月被Getco LLC收购,合并后的公司现在称为KCG Holdings。


从DevOps的角度复盘骑士资本事件



骑士资本的事故,体现出DevOps领域一些关键的典型控制故障。让我们通过DevOps的视角,再次看看这里面存在的问题:
  • 手动部署多台生产系统服务器
  • 没有对部署过程进行复查的机制
  • 非工作代码长期遗留在系统中
  • 缺乏对代码Flag标签的管理
  • 系统没有设置切断开关kill-switch
  • 标记为 SMARS 的邮件并没有设计为系统警报,因此没有人立即查看它们。
  • 没有机制来确定是什么原因导致了错误的订单。
1)自动化发布/部署 
  • 运维工程师遵循手工流程来部署更改,但是错过了在其中的一台服务器上部署程序,不幸的是也没有人注意到该错误。
  • 这一问题正是自动化配置管理以及自动化部署旨在防止的问题。经过审核的、自动化的,并且经过良好测试的部署流水线,通过发布后检查和冒烟测试(包括在所有服务器上查找版本不匹配)来检查部署是否成功,可以避免此问题。 
  • 软件发布过程应该是可靠且可重复的,部署应该是自动化且可重复的,这个过程应该尽量排除人为因素的干扰。假如骑士资本采用的是自动部署系统——配置、部署和测试完全自动化,这场Knightmare(骑士悲剧)可能就不会发生了。
2)代码中的暗启动和分支
  • 将代码更改风险最小化的一种方法是将变更保护在功能开关后面,以便运维人员可以通过打开或关闭标志来在运行时控制系统的行为。
  • 骑士资本在修改SMARS的过程中重新加进了一个Flag,这个Flag与之前使用PowerPeg的Flag完全相同。如果该Flag在运行新的SMARS软件系统的过程中被设置成“是”,则执行与RLP相关的新软件模块。
  • 新代码是基于每个订单消息中的Flag而不是运行时开关值执行的,这意味着运维人员没有简单的方法可以立即停止代码。
  • 这也凸显了使用条件开关和代码分支来控制系统运行时行为的风险。对于新功能,骑士资本的开发人员选择重新设置一个标记,然而该标记在旧版本的代码中具有完全不同的含义。并且由于上述部署错误,这些旧代码仍在其中一台服务器上运行,这意味着它被意外触发了,其结果是无法预测且令人困惑。
  • 使用条件逻辑来“分支代码”可以在运行时控制系统的不同行为,但这也使代码更难理解,更难更改和更难测试。代码中保留的逻辑条件和功能开关的时间越长,随着时间的推移添加的开关越多,这种问题就越严重。过不了多久,就没人会知道打开某些Flag或Flag的组合会发生什么,这就是骑士资本发生的事情。
  • 代码中的功能开关和分支是一种危险的技术债务,团队需要纪律严明的管理代码,确保一旦条件逻辑和Flag不再需要时就将其删除。
  • 对于代码也是一样,需要定期的对代码进行清理和审视。9年未使用的代码依然存留,这就像你家里的清洁死角一样。
3)可视性和监视/反馈循环 
  • 高频交易系统曾自动向公司内部共计97名员工发送了包含“(PowerPeg disabled)”信息的电子邮件,却没有引起任何收到信息人员的警惕。
  • DevOps中的另一个重要实践是确保开发人员随时待命,并随时可以帮助他们进行任何更改。如果开发人员在清晨看到“ Power Peg”警报,他们应该认识到出了问题,并能够在股市开放前阻止事态的发生。 
4)应对失败 
  • 始终为故障做好准备并拥有成熟的事件响应能力极为重要。包括知道何时回滚代码,并且知道代码是否起作用,定义明确的问题升级机制以便于在问题失控之前迅速关闭设备。
  • “无法确定是什么原因导致了错误的订单,因此他们做出的反应是卸载掉已经部署到几台服务器上的新代码。换句话说,他们删除了工作代码并留下了损坏的代码。这导致情况进一步恶化,除了第八台未被正确部署的服务器,另外七台服务器中的父订单也触发了 Power Peg 功能。”
  • 骑士资本的团队花了过长时间来做出关键的(错误)决定,到系统真正关闭时,公司实际上也已经倒闭了。 
在这个事件中,我们不应该把矛头全部对准部署 SMARS 的技术人员,骑士资本的业务流程根本不足以应付他们所面对的问题。此外,这种流程(或缺陷)本来就很容易出错。是人都会犯错,不论何时,只要你的部署过程依赖于人工指令操作,就有可能出现问题。隐患可能存在于指令本身、对指令的解读以及指令的执行过程中。
所有的开发与运维团队都应该从骑士资本惨案中吸取教训。仅仅开发出好的软件(骑士资本距离好的软件差的好远)并对其进行测试还不够,还需要把软件正确地被交付给市场,这样客户才能获得正确的结果 (以免您的公司破产)。


八月伊始,乘风破浪。IDCF【冬哥有话说】8月特别邀请到四位美女,带来四个主题分享,分别从组织建设、绩效考核、品牌营销,以及技术卓越等不同角度,围绕“数字化”展开,这也体现了IDCF一直秉承的理念“培养端到端的人才”,我们希望可以通过本系列的分享,给你不同的视角去看待一个企业,从单纯的技术视角跳出来,去尽可能的看到一个更加完整的全貌。
本周四晚8点,天泽智云市场营销副总裁夏鑫琪分享《VUCA时代的B2B市场营销体系与品牌价值构建》,识别下图二维码,回复“乘风破浪”即可获取直播地址。


good-icon 0
favorite-icon 0
收藏
回复数量: 0
    暂无评论~~
    Ctrl+Enter