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