程序員的一次失誤,在45分鐘里搞垮了一家上市公司
如果有人告訴你,45 分鐘就能搞垮一家大公司,你可能會覺得有點(diǎn)荒謬。但工程師 Doug Seven 卻真的親歷過這樣的事情。
8 年前,因?yàn)橐淮问〉牟渴?,Knight Capital Group 在僅僅 45 分鐘內(nèi)就造成了 4.6 億美元的虧損。
這是一個(gè)真實(shí)的故事。
盡管 Doug Seven 并不是事件的參與者,但他在后來的會議中不斷提及 DevOps、代碼配置和持續(xù)交付的主題,希望讓開發(fā)人員意識到部署的重要性。
究竟是怎么回事?Doug Seven 在博客中分享了這個(gè)故事。
故事背景
這個(gè)故事的主角是一家名為 Knight Capital Group 的美國全球金融服務(wù)公司,它從事做市、電子執(zhí)行、機(jī)構(gòu)銷售和交易。
2012 年,Knight 是美國最大的股票交易商,在紐約證交所和納斯達(dá)克的市場份額約為 17%。Knight 電子交易集團(tuán)(ETG)平均每日交易量超過 33 億筆,每日交易額超過 210 億美元。
種種數(shù)據(jù)表明,當(dāng)時(shí)公司的運(yùn)營和財(cái)務(wù)狀況非常優(yōu)秀。
2012 年 7 月 31 日,Knight 擁有約 3.65 億美元的資產(chǎn)。
當(dāng)時(shí),紐約證交所正計(jì)劃于 2012 年 8 月 1 日推出一項(xiàng)新的零售流動(dòng)性計(jì)劃。
為了準(zhǔn)備這次活動(dòng),Knight 更新了他們的路由器 SMARS。這個(gè)路由器負(fù)責(zé)將訂單發(fā)送到市場上執(zhí)行。SMARS 的核心功能之一是接收 Knight 交易平臺其他組件的訂單(父訂單),然后發(fā)送一個(gè)或多個(gè)子訂單執(zhí)行。換言之,SMARS 將從交易平臺收到大量訂單,并將它們分成多個(gè)較小的訂單,以便找到股票數(shù)量相匹配的買家或者賣家。父訂單越大,生成的子訂單越多。
在 SMARS 中,有一段老舊的代碼,名為「Power Peg」,它已經(jīng) 8 年沒被用到過了,而此次更新的目的正是要換掉這段代碼。更新的代碼重新調(diào)整了用于激活 Power Peg 功能的舊標(biāo)志的功能。
代碼經(jīng)過了徹底的測試,并且還進(jìn)行了一系列的驗(yàn)證。所有的一切都看起來很完美,找不到出錯(cuò)的理由。
死灰復(fù)燃的舊代碼
2012 年 7 月 27 日至 2012 年 7 月 31 日期間,Knight 的開發(fā)人員每天手動(dòng)將新的軟件部署到公司的 8 臺服務(wù)器上。這就是 SEC 文件中關(guān)于手動(dòng)部署過程的內(nèi)容。如果 SEC 文件中有關(guān)于部署的內(nèi)容,那么就可能出現(xiàn)了嚴(yán)重的錯(cuò)誤。
然而,在新代碼的部署過程中,Knight 的一名技術(shù)人員忘記將新代碼復(fù)制到所有 8 臺 SMARS 計(jì)算機(jī)服務(wù)器中——他漏掉了其中一臺服務(wù)器。
沒有第二個(gè)技術(shù)人員來審查這個(gè)部署。
Knight 的所有人都沒有意識到,Power Peg 代碼并沒有從第 8 個(gè)服務(wù)器上刪除,也沒有添加新的 RLP 代碼。Knight 沒有書面流程要求這樣的審查。
2012 年 8 月 1 日,在美國東部時(shí)間上午 9:30,市場開盤。Knight 開始代表客戶處理訂單。
具有正確 SMARS 部署的 7 臺服務(wù)器開始正確處理這些訂單。然而,發(fā)送到第 8 臺服務(wù)器的命令觸發(fā)了可支持的重新利用標(biāo)志,并從死地中恢復(fù)了舊的 Power Peg 代碼。
殺手代碼如僵尸般的攻擊
Power Peg 代碼用于在執(zhí)行子訂單時(shí),根據(jù)父訂單計(jì)算購買或者出售的股份。Power Peg 將指示系統(tǒng)在完成父訂單后停止傳送子訂單。
也就是說,Power Peg 會跟蹤子訂單,并在父訂單完成后停止它們。
2005 年,Knight 將這種累計(jì)跟蹤功能移到了代碼執(zhí)行的早期階段,從而從 Power Peg 中刪除了計(jì)數(shù)跟蹤。
當(dāng)激活第 8 臺服務(wù)器上的 Power Peg 標(biāo)志時(shí),Power Peg 功能開始路由子訂單以供執(zhí)行。但由于沒有根據(jù)父訂單跟蹤共享量,造成了一個(gè)永無止境的循環(huán)。
地獄 45 分鐘
想象一下,如果你有一個(gè)系統(tǒng),它能夠向市場發(fā)送自動(dòng)化的、高速的訂單,且沒有任何跟蹤程序來檢查是否執(zhí)行了足夠的訂單,會發(fā)生什么?沒有比這更糟糕的事了。
上午 9:30 開市時(shí),人們很快就知道出了問題。到上午 9 點(diǎn) 31 分,華爾街的許多人都清楚發(fā)生了一些嚴(yán)重的事情。市場上充斥著非正常交易量的股票訂單。
到上午 9 點(diǎn) 32 分,華爾街的人們都在想,為什么訂單還沒有停下來,為什么沒有人按下任何系統(tǒng)的關(guān)閉開關(guān)?結(jié)果他們發(fā)現(xiàn),并沒有關(guān)閉開關(guān)。在交易的前 45 分鐘里,Knight 的交易量占了總交易量的 50% 以上,這使得某些股票的市值上漲了 10% 以上。因此,其他股票因錯(cuò)誤的交易而貶值。
更糟糕的是,Knight 的系統(tǒng)在當(dāng)天早些時(shí)候開始自動(dòng)發(fā)送電子郵件。早在上午 8:01,SMAR 已經(jīng)處理了符合上市前交易條件的訂單。郵件消息引用 SMARS,并將錯(cuò)誤識別為「Power Peg disabled」。
在上午 8:01 到 9:30 之間,Knight 工作人員也收到了 97 封郵件??上У氖?,這些電子郵件不是作為系統(tǒng)警報(bào)設(shè)計(jì)的,因此沒有人立即查看它們。
在 Knight 經(jīng)歷的 45 分鐘內(nèi),他們嘗試了幾種反制措施,試圖阻止錯(cuò)誤的交易。由于沒有終止開關(guān),所以他們只能在實(shí)時(shí)交易環(huán)境中嘗試診斷問題。
每分鐘,系統(tǒng)上約有 800 萬股股票被交易。他們無法確定是什么導(dǎo)致了錯(cuò)誤的命令,所以他們從正確部署的服務(wù)器上卸載了新代碼。
換句話說,他們刪除了工作代碼,留下了損壞的代碼。
這更加放大了問題。最開始,僅在部署不正確的服務(wù)器上,額外的父命令激活了 Power Peg 代碼?,F(xiàn)在,問題蔓延到了所有服務(wù)器上。最后,他們終于停止了系統(tǒng),但此時(shí)已經(jīng)進(jìn)行了 45 分鐘的交易。
在開盤的前 45 分鐘,市場收到并處理了 212 份父訂單。因此,SMARS 向市場發(fā)送了數(shù)以百萬計(jì)的子訂單,產(chǎn)生了 400 萬筆交易,而其中 154 只股票的交易量超過了 3.97 億股。這意味著,Knight 資本集團(tuán)在 45 分鐘內(nèi)造成了 4.6 億美元的虧損。
然而,Knight 只有 3.65 億美元的資產(chǎn)。
45 分鐘后,美國股市最大的交易商、紐約證交所和納斯達(dá)克的主要做市商 Knight 破產(chǎn),4 個(gè)月后被 Getco LLC 收購。
軟件發(fā)布必須可重復(fù)、可靠
所有開發(fā)和運(yùn)營團(tuán)隊(duì)都應(yīng)該從這次事件中吸取教訓(xùn)。僅僅構(gòu)建優(yōu)秀的軟件并對其進(jìn)行測試是不夠的,你還必須確保它被正確地交付給市場,這樣你的客戶才能獲得你所交付的價(jià)值。
部署 SMARS 的工程師并不是此事唯一的責(zé)任人,Knight 設(shè)置的流程和他們所面臨的風(fēng)險(xiǎn)并不匹配。此外,他們的流程天生就容易出錯(cuò)。任何時(shí)候,如果你的部署過程依賴于人主動(dòng)閱讀和遵循說明,那么都將面臨風(fēng)險(xiǎn)。人是會犯錯(cuò)的。錯(cuò)誤可能出現(xiàn)在指令中,也可能出現(xiàn)在指令的解釋中,或出現(xiàn)在指令的執(zhí)行中。
部署需要自動(dòng)化,并且可重復(fù),盡可能避免潛在的人為錯(cuò)誤。如果 Knight 實(shí)現(xiàn)了自動(dòng)化部署系統(tǒng),將配置、部署和測試全部自動(dòng)化,那么這次錯(cuò)誤本可以避免。
即使沒有實(shí)施完整的連續(xù)交付過程,你仍然需要遵守的幾個(gè)連續(xù)交付原則:
-
軟件發(fā)布應(yīng)該是一個(gè)可重復(fù)、可靠的過程。
-
盡可能地自動(dòng)化。