Knight Capital: Jak se probudí kód, který devět let nikdo nevolal?

1. srpna 2012 začal jeden z osmi serverů Knight Capital posílat do trhu miliony pokynů a za zhruba 45 minut bylo hotovo. Ztráta přes 460 milionů dolarů. Nový kód se nasadil na sedm serverů z osmi, na tom osmém zůstal kód vyřazený v roce 2003, a příznak, který ho zapínal, se mezitím recykloval. A když se to snažili opravit rollbackem, rozšířili to na všech osm serverů.

// obsah 11
  1. 01 Proč mě to zaujalo?
  2. 02 Co se vlastně stalo?
  3. 03 Co byl Power Peg?
  4. 04 Sedm z osmi
  5. 05 Devadesát sedm e-mailů
  6. 06 A pak to opravili
  7. 07 Proč to nic nezastavilo?
  8. 08 Kolik to stálo?
  9. 09 Co si z toho beru
  10. 10 Co bych z toho vytáhl, kdybych měl jednu větu
  11. 11 Zdroje

Tenhle případ je krátký a je ze všech, co jsem tady rozebíral, nejvíc vývojářský.

Zadání ani politika tu tentokrát roli nehrají. Spadlo to na mrtvém kódu, který se nesmazal, na recyklovaném příznaku, na nasazení, které se provedlo, ale neověřilo, a na chybějícím vypínači (neměli žádný postup, jak vlastní systém zastavit). Aspoň tři z těch čtyř věcí najdete ve skoro každém starším produkčním systému, jen zatím nestály 460 milionů dolarů.

A když se to 1. srpna 2012 snažili opravit, udělali rollback nového kódu. Tím problém rozšířili z jednoho serveru na všech osm.

Pokud se vám líp kouká, než čte, je k článku i video. Má zhruba deset minut.

Proč mě to zaujalo?

Kvůli zdroji. Rozhodnutí SEC, kterým to komise v říjnu 2013 uzavřela, má osmnáct stran a je v něm celý mechanismus i časová osa. Zpráva o migraci TSB měla 262 stran, tohle přečtete za půl hodiny.

A pak kvůli tomu, komu se to stalo. Knight nebyl garážový startup. Jeho obchodování představovalo v letech 2011 a 2012 zhruba deset procent veškerého obchodování s kotovanými americkými akciemi a samotný směrovací systém SMARS asi procento nebo víc. Velká firma tu narazila na věci, které se junior naučí v prvním roce praxe.

Co se vlastně stalo?

Datum Co se dělo
2003 Knight přestává používat funkcionalitu Power Peg. Kód zůstává na serverech a dá se pořád zavolat
2005 Počítadlo, které Power Pegu říkalo „už je všechno zobchodované, přestaň“, se přesune jinam v kódu SMARS. Power Peg se po tom přesunu už nikdy netestuje
říjen 2011 Po víkendovém testu obnovy generuje jeden desk v pondělí kotace z testovacích dat. Ztráta téměř 7,5 mil. USD. Opraví se jen ten jeden systém
3. 7. 2012 SEC schvaluje Retail Liquidity Program (RLP) newyorské burzy, start má být 1. 8.
27. 7. 2012 Začíná nasazování nového kódu do SMARS, po částech, každý den na pár dalších serverů
do 31. 7. 2012 Jeden technik nezkopíruje nový kód na jeden z osmi serverů. Nikdo to po něm nekontroluje, žádný předpis to nevyžaduje
1. 8. 2012, ~8:01 Systém začíná generovat automatické e-maily s chybou „Power Peg disabled“. Do otevření trhu jich odejde 97
1. 8. 2012, 9:30 Otevření trhu. Sedm serverů zpracovává pokyny správně, osmý spouští Power Peg
~45 minut Z 212 původních pokynů vznikly miliony dílčích. Přes 4 miliony obchodů, 154 titulů, přes 397 milionů akcií
1. 8. 2012, v průběhu Tým odinstaluje nový kód ze sedmi správných serverů. Tím se Power Peg aktivuje i tam
6. 8. 2012 Knight hlásí realizovanou předdaňovou ztrátu cca 440 mil. USD (ve výroční zprávě pak 457,6 mil.). Týž den bere záchrannou investici 400 mil. USD
1. 7. 2013 Knight Capital Group se spojuje s GETCO do KCG Holdings
16. 10. 2013 SEC: pokuta 12 mil. USD, důtka a povinnost nechat si přezkoumat vývojový proces

Co byl Power Peg?

SMARS je směrovač pokynů. Dostane původní pokyn („kup mi tolik a tolik akcií“), rozseká ho na dílčí (v originále parent a child orders) a ty rozešle na burzy podle toho, kde je zrovna likvidita. Jak se dílčí pokyny zobchodují, systém ví, kolik už má, a přestane posílat další.

Ta podmínka ukončení byla u Power Pegu vevnitř. Rozhodnutí SEC to popisuje takhle:

When Knight used the Power Peg code previously, as child orders were executed, a cumulative quantity function counted the number of shares of the parent order that had been executed. This feature instructed the code to stop routing child orders after the parent order had been filled completely.

Power Peg se přestal používat v roce 2003 (tedy devět let před tou událostí). V roce 2005 pak v Knightu to počítadlo přesunuli na dřívější místo v kódu SMARS. A pak tohle:

Knight did not retest the Power Peg code after moving the cumulative quantity function to determine whether Power Peg would still function correctly if called.

Smyčka tam zůstala, jen podmínka jejího ukončení se přestěhovala jinam. Od roku 2005 byl ten kód rozbitý a sedm let se to nedalo poznat, protože ho prostě nikdo nevolal.

Dvě smyčky vedle sebe: do roku 2005 vede zpětná vazba od provedených obchodů přes počítadlo zpátky do Power Pegu a smyčka se zastaví; po roce 2005 je počítadlo přesunuté mimo smyčku, zpětná vazba je přerušená a Power Peg posílá dál

Zdroj: SEC, In the Matter of Knight Capital Americas LLC, Release No. 70694, 16. 10. 2013, odstavce 12 až 17.

Proč se ten kód v roce 2012 vůbec zavolal? Protože nový kód pro RLP (ten burzovní program, kvůli kterému se to celé nasazovalo) recykloval příznak, kterým se dřív Power Peg zapínal (a který chodil přímo s pokyny). Záměr byl na papíře rozumný: starý kód smazat a příznak použít znovu pro nové chování. Když je jedno i druhé hotové, funguje to. Spoléhali ale na to, že se starý kód smazal všude.

A ještě jeden detail. Informace o tom, že původní pokyny jsou celé zobchodované, v systému existovala:

Although one part of Knight’s order handling system recognized that the parent orders had been filled, this information was not communicated to SMARS.

Systém to věděl, jen ne v té části, která rozhodovala.

Sedm z osmi

Nasazení začalo 27. července a probíhalo po částech, každý den na pár dalších serverů. Na jeden z osmi se nový kód nedostal.

Knight did not have a second technician review this deployment and no one at Knight realized that the Power Peg code had not been removed from the eighth server, nor the new RLP code added. Knight had no written procedures that required such a review.

Bacha, podstatné je hlavně to, že na osmém serveru zůstal starý kód, který měl být smazaný. Kdyby tam nebyl ani nový, ani starý, pokyny by se nejspíš prostě odmítly. Starý kód je ale zpracoval, a to úplně jinak.

SEC k tomu pojmenovává pravidlo, které se v procesech moc nevidí:

Knight also did not have a written protocol concerning the accessing of unused code on its production servers, such as a protocol requiring the testing of any such code after it had been accessed to ensure that the code still functioned properly.

Tedy: pokud sáhnete na nepoužívaný kód, který leží na produkci, měli byste ho otestovat, jestli po tom sáhnutí ještě funguje. Zní to samozřejmě, dokud si nezkusíte vzpomenout, kdy jste to naposledy udělali.

Devadesát sedm e-mailů

Od zhruba 8:01 ráno, tedy hodinu a půl před otevřením trhu, začal interní systém generovat automatické e-maily, takzvané BNET rejects, s chybou popsanou jako „Power Peg disabled“. Do otevření trhu v 9:30 jich odešlo 97 skupině lidí v Knightu (a šlo přitom o jiné pokyny než těch 212, které pak způsobily ztrátu).

Rozhodnutí k tomu:

Knight did not design these types of messages to be system alerts, and Knight personnel generally did not review them when they were received.

Byly to provozní zprávy, které se běžně nečtou. A přesto v sobě měly přesné jméno funkce, která o hodinu a půl později začne dělat ztrátu skoro půl miliardy dolarů. Po otevření trhu se k nim navíc nikdo nevrátil ani při diagnostice.

Tohle znám. Skoro každý projekt, který už nějakou dobu běží, má v logu pár chyb, co se hlásí pořád dokola. Nikdo je neřeší a po čase je lidi přestanou vidět. Zajímavější ale je, jestli si někdo všimne, když se mezi nimi objeví nová.

A pak to opravili

Knight neměl žádný předpis, jak při incidentu postupovat. Tým se snažil problém najít v živém produkčním provozu, zatímco systém pořád posílal miliony pokynů. A pak udělal to, co bych nejspíš udělal taky:

In one of its attempts to address the problem, Knight uninstalled the new RLP code from the seven servers where it had been deployed correctly. This action worsened the problem, causing additional incoming parent orders to activate the Power Peg code that was present on those servers, similar to what had already occurred on the eighth server.

Logika je pochopitelná: začalo to po nasazení nového kódu, tak ho stáhneme a vrátíme se ke staré verzi.

Jenže rollback nevrátil systém do posledního funkčního stavu. Odinstaloval se jen nový kód v SMARS, pokyny s recyklovaným příznakem ale chodily dál. Na těch sedmi serverech je tak začal zpracovávat Power Peg, rozbitý od roku 2005, jen o tom nikdo nevěděl. Jestli tam ležel celou dobu pod novým kódem, nebo se vrátil se starou verzí, rozhodnutí neříká. Výsledek byl stejný.

Dvě řady po osmi serverech: před rollbackem má sedm serverů nový kód RLP a na osmém je aktivní Power Peg, po odinstalaci nového kódu ze sedmi serverů je Power Peg aktivní na všech osmi

Zdroj: SEC, Release No. 70694, odstavce 15, 16 a 27.

Rollback je taky změna, jen se po ní systém ocitne ve stavu, který skoro nikdy netestuju. Testuju starou a novou verzi, ale ne kombinaci, kdy běží stará verze a okolní systémy jí už posílají data podle nové. Přitom to je přesně ten stav, do kterého se dostanu, když je nejhůř.

Proč to nic nezastavilo?

Knight kontroly měl, jen ne tam, kde byly potřeba, a ne takové, které by to zastavily.

Před SMARS jich měl několik: klientské rozhraní, interní order management i systém, který klientské pokyny prováděl interně, obsahovaly kontroly proti chybným pokynům. V samotném SMARS ale podle SEC nestačily:

Knight did not have sufficient controls to monitor the output from SMARS, such as a control to compare orders leaving SMARS with those that entered it. Knight also did not have procedures in place to halt SMARS’s operations in response to its own aberrant activity.

Chybělo tedy porovnání vstupu a výstupu a chyběl vypínač. Dovnitř přitom přišlo 212 malých retailových pokynů a ven šly miliony dílčích, takový nepoměr by chytila i hodně jednoduchá kontrola zobchodovaného množství proti původnímu pokynu.

Zbytek kontrol vypadá při čtení naprosto rozumně a žádná z nich nezabrala:

  • Cenový strop omezoval limitní cenu na 9,5 % od nejlepší kotace (u prodejů pod nejlepší nákupní cenou, u nákupů nad nejlepší prodejní). Nepomůže, když se trh hne o míň, a hlavně se vůbec nevztahoval na pokyny přijaté před otevřením trhu. Což bylo přesně těch 212 pokynů.
  • Účet 33, kam padaly mimo jiné obchody, které systém neuměl spárovat, měl limit hrubé pozice 2 miliony dolarů. Ten limit ale nebyl napojený na nic, co by při překročení zastavilo posílání pokynů. A protože na tom účtu ležely pozice z víc zdrojů, lidé v Knightu ani nedokázali rychle zjistit, odkud se to bere.
  • PMON, hlavní nástroj na sledování rizika, byl poobchodní (měřil až to, co se stalo). Neuměl nic zastavit, negeneroval výstrahy, nezobrazoval limity (museli jste je znát z hlavy) a při velkém objemu se zpožďoval a vykazoval nepřesné údaje. Přesně v okamžiku, kdy ho potřebovali, byl nejmíň spolehlivý.

Cesta pokynu z 212 pokynů přes SMARS a burzy na účet 33 a poloha pěti kontrol vůči ní: cenový strop je brána s mezerou, kterou pokyny před otevřením trhu prošly, porovnání vstupu a výstupu SMARS a vypínač jsou jen čárkované obrysy, protože neexistovaly, limit hrubé pozice a PMON sedí za koncem cesty a zpátky do SMARS z nich nevede nic

Zdroj: SEC, Release No. 70694, odstavce 20 až 25.

Deset měsíců předtím měli přitom zkoušku nanečisto. V říjnu 2011 po víkendovém testu obnovy jeden desk v pondělí ráno dál generoval kotace z testovacích dat a stálo to skoro 7,5 milionu dolarů. Opravili jen ten jeden systém: omezili ho na obchodní hodiny, upravili mu kontrolu, aby po prvním obchodu přestal kotovat, a do checklistu obnovy přidali kontrolu testovacích dat. Obecná otázka, jestli firma vůbec umí zastavit chybné pokyny bez ohledu na to, který systém je poslal, se nepoložila.

Kolik to stálo?

Ztráta se uvádí ve třech číslech a rozdíl je hlavně v tom, kdy které vzniklo.

Knight ve vlastním 8-K ze 6. srpna 2012, tedy pět dní po události, hlásil realizovanou předdaňovou ztrátu zhruba 440 milionů. Ve čtvrtletní zprávě z listopadu a pak i ve výroční zprávě za rok 2012 už uvádí 457,6 milionu (tolik ho stálo, když všechny chybné pozice uzavřel) a i s navazujícími právními a poradenskými náklady 468,1 milionu. SEC v rozhodnutí z října 2013 píše, že Knight na těch nechtěných pozicích ztratil přes 460 milionů. Jak k tomu číslu došla, rozhodnutí neříká. Těch 440 milionů bylo tedy jen první číslo, které se později zpřesnilo.

Za těch 45 minut nabral Knight čistou dlouhou pozici asi 3,5 miliardy dolarů v 80 titulech a čistou krátkou asi 3,15 miliardy ve 74 titulech. U 75 titulů tvořily jeho obchody přes 20 % objemu a přispěly k pohybu ceny o víc než 5 %; u 37 z nich se cena pohnula o víc než 10 % a Knight dělal přes polovinu objemu.

Firma nezkrachovala, ale dosavadní akcionáři přišli o většinu firmy. Už 6. srpna prodala investorům prioritní akcie za 400 milionů dolarů, které po konverzi představovaly zhruba 73 % kmenových akcií. Na dosavadní akcionáře tak zbyla zhruba čtvrtina. Za necelý rok se Knight Capital Group spojil s GETCO do KCG Holdings.

Pokuta od SEC byla 12 milionů dolarů (vedle té ztráty skoro symbolická), k tomu důtka. Zajímavější než pokuta je ale to, co SEC uložila jako nápravu: najmout na vlastní náklady nezávislého konzultanta, který přezkoumá životní cyklus vývoje softwaru u všech klíčových systémů i systém kontrol, a jehož zpráva půjde současně firmě i regulátorovi.

Co si z toho beru

1. Nepoužívaný kód není zadarmo.

Power Peg devět let nic nedělal a nikomu nevadil. V procesoru ani v paměti skoro nic nestál. Platilo se za něj jinak: zůstal volatelný, ale nikdo ho už netestoval. Když se v roce 2005 přesunulo počítadlo, nikdo nepřetestoval, jestli ten nepoužívaný kód ještě funguje (proč taky, když ho nikdo nevolal). U nepoužívaného kódu je tak podstatné, jestli by se ještě dal zavolat. Pokud ano, buď ho smažu, nebo ho testuju.

2. Recyklovaný příznak znamená dvě věci najednou.

Použít starý příznak znovu pro nové chování je lákavý nápad a šetří práci (kdo to nikdy neudělal?). Má ale jednu vlastnost: dokud existují obě implementace, ten příznak znamená dvě různé věci podle toho, kde se čte. Nic vás na to neupozorní, protože typově je všechno v pořádku. Když dneska měním význam nějakého příznaku, radši ho přejmenuju celý, i když to znamená víc práce.

3. Nasazení, které se neověří, je jenom naděje.

Knight kód nasadil, ale neověřil, že je nasazený, a chyběl mu na to i předpis. Přitom na otázku „běží všude to samé?“ se dá odpovědět docela nudně, třeba tím, že každá instance umí říct svoji verzi a po nasazení se to porovná. Elegantní to není, ale je to rychlejší, než se to dozvědět z trhu. A ještě lepší je, když kód po serverech nekopíruje člověk, ale skript, který stejnou verzi dostane na všechny, nebo skončí chybou.

4. Rollback potřebuje stejnou pozornost jako release.

Tady byl rollback tím, co problém rozšířilo na všech osm serverů. U větších změn stojí za to si aspoň jednou nahlas říct, do čeho se to vlastně vrací a co do té staré verze bude dál chodit.

Co bych z toho vytáhl, kdybych měl jednu větu

Nepoužívaný kód je pořád součást systému, dokud ho nesmažete, a u Knightu stačil jeden recyklovaný příznak, aby se zase volal.

Zdroje

Michal Katuščák
Michal Katuščák

Navrhuji a vyvíjím aplikace nad Symfony, zajímám se o architekturu softwaru. Žiju v Českých Budějovicích.