1 คะแนน โดย GN⁺ 2023-09-11 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • Knight Capital Group ซึ่งเคยเป็นหนึ่งในเสาหลักของการซื้อขายหุ้นสหรัฐฯ สูญเสียเงิน 460 ล้านดอลลาร์ภายใน 45 นาทีจาก ความล้มเหลวในการ deploy SMARS เมื่อวันที่ 1 สิงหาคม 2012 จนเกือบล้มละลาย
  • จุดเริ่มต้นของเหตุการณ์คือระหว่างการรองรับ Retail Liquidity Program ของ NYSE บริษัทนำ flag ของโค้ด Power Peg ที่ไม่ได้ใช้มานาน 8 ปี กลับมาใช้ซ้ำกับฟีเจอร์ใหม่
  • โค้ดใหม่ถูก deploy ไปยังเซิร์ฟเวอร์เพียง 7 เครื่องจากทั้งหมด 8 เครื่อง และเมื่อเซิร์ฟเวอร์ที่เหลืออีกหนึ่งเครื่องได้รับคำสั่ง RLP ใหม่ ฟีเจอร์ Power Peg ที่เคยปิดตายไว้ก็กลับมาทำงานอีกครั้ง
  • Power Peg routing คำสั่งลูกต่อไปเรื่อย ๆ โดยไม่ติดตามปริมาณการจับคู่ของคำสั่งแม่ และ Knight ต้องค้นหาสาเหตุใน production โดยไม่มี kill switch หรือขั้นตอนรับมือที่จัดทำเป็นเอกสารไว้
  • การ deploy สำคัญพอ ๆ กับการเขียนโค้ดและการทดสอบ และการ deploy ที่พึ่งพาขั้นตอนแบบ manual จะกลายเป็นความเสี่ยงด้าน operations ที่ร้ายแรง หากไม่มี automation, repeatability และ verification

บริษัท high-frequency trading ที่ล้มลงใน 45 นาที

  • Knight Capital Group เป็นบริษัทบริการทางการเงินของสหรัฐฯ ที่ทำ market making, electronic execution, การขายและ trading สำหรับสถาบัน
  • ในปี 2012 Knight เป็นผู้ซื้อขายรายใหญ่ที่สุดในตลาดหุ้นสหรัฐฯ โดยมี ส่วนแบ่งตลาดประมาณ 17% ทั้งใน NYSE และ NASDAQ
  • Electronic Trading Group (ETG) ของ Knight จัดการปริมาณการซื้อขายเฉลี่ยมากกว่า 3.3 พันล้านรายการต่อวัน และซื้อขายมูลค่ามากกว่า 21 พันล้านดอลลาร์ต่อวัน
  • ณ วันที่ 31 กรกฎาคม 2012 Knight มีเงินสดและสินทรัพย์เทียบเท่าเงินสดประมาณ 365 ล้านดอลลาร์

การอัปเดต SMARS เพื่อรองรับ RLP

  • NYSE มีกำหนดเริ่ม Retail Liquidity Program ในวันที่ 1 สิงหาคม 2012
  • Knight จึงอัปเดต SMARS ซึ่งเป็น router อัลกอริทึมความเร็วสูงแบบอัตโนมัติสำหรับส่งคำสั่งเข้าสู่ตลาด
  • SMARS เป็นระบบที่รับ “คำสั่งแม่” จากแพลตฟอร์มซื้อขาย แล้วแบ่งออกเป็น “คำสั่งลูก” หนึ่งรายการหรือมากกว่าเพื่อดำเนินการ
    • ยิ่งคำสั่งแม่มีขนาดใหญ่ ก็ยิ่งสร้างคำสั่งลูกมากขึ้น
  • การอัปเดตครั้งนี้เป็นงานเพื่อแทนที่โค้ด Power Peg ที่ไม่ได้ใช้งานมา 8 ปี
  • โค้ดใหม่นำ flag เดิมที่เคยใช้เปิดใช้งาน Power Peg กลับมาใช้กับฟีเจอร์ใหม่
  • ตัวโค้ดเองถูกทดสอบอย่างเพียงพอ และยืนยันแล้วว่าทำงานได้ตามปกติ

เซิร์ฟเวอร์หนึ่งเครื่องที่ตกหล่นจากการ deploy แบบ manual

  • ตั้งแต่วันที่ 27 กรกฎาคมถึง 31 กรกฎาคม 2012 Knight deploy แบบ manual ซอฟต์แวร์ใหม่ไปยังเซิร์ฟเวอร์จำนวนจำกัดต่อวัน โดยมีเป้าหมายทั้งหมด 8 เครื่อง
  • ตามเอกสารของ SEC มีช่างเทคนิคคนหนึ่งไม่ได้คัดลอกโค้ดใหม่ไปยังหนึ่งในเซิร์ฟเวอร์ SMARS ทั้ง 8 เครื่อง
  • ไม่มีขั้นตอนให้ช่างเทคนิคคนที่สองตรวจทานการ deploy นี้ และไม่มี ขั้นตอนที่จัดทำเป็นเอกสาร ซึ่งกำหนดให้ต้องตรวจทานเช่นนั้น
  • ผลคือเซิร์ฟเวอร์เครื่องที่ 8 ไม่ได้ถูกลบโค้ด Power Peg ออก และไม่ได้เพิ่มโค้ด RLP ใหม่เข้าไป

โค้ดที่ตายไปแล้วกลับมามีชีวิตได้อย่างไร

  • เมื่อเวลา 9:30 น. ตามเวลาฝั่งตะวันออกของสหรัฐฯ วันที่ 1 สิงหาคม 2012 ตลาดเปิดทำการ Knight เริ่มประมวลผลคำสั่งของลูกค้า broker-dealer สำหรับ Retail Liquidity Program
  • เซิร์ฟเวอร์ 7 เครื่องที่ deploy ถูกต้องประมวลผลคำสั่งได้ตามปกติ
  • คำสั่งที่ถูกส่งไปยังเซิร์ฟเวอร์เครื่องที่ 8 ทำให้โค้ด Power Peg เดิมกลับมาทำงานอีกครั้งผ่าน flag ที่ถูกนำกลับมาใช้ซ้ำ
  • เดิมที Power Peg เป็นฟีเจอร์ที่นับจำนวนหุ้นที่ซื้อหรือขายไปเมื่อคำสั่งลูกถูก executed เทียบกับคำสั่งแม่ และหยุด routing คำสั่งลูกเมื่อคำสั่งแม่ถูกเติมเต็มแล้ว
  • ในปี 2005 Knight ได้ย้ายฟังก์ชันติดตามยอดสะสมไปไว้ในขั้นตอนก่อนหน้าของการรันโค้ด และการติดตามผลรวมภายใน Power Peg ถูกลบออกไปแล้ว
  • เมื่อ flag ของ Power Peg ถูกเปิดใช้งานบนเซิร์ฟเวอร์เครื่องที่ 8 Power Peg จึง routing คำสั่งลูกไปยังตลาด execution แต่ไม่ได้ติดตามจำนวนหุ้นเทียบกับคำสั่งแม่ ทำให้ในทางปฏิบัติมันทำงานเหมือน ลูปไม่รู้จบ

สัญญาณก่อนเปิดตลาดและการพุ่งควบคุมไม่ได้หลัง 9:30

  • ระบบของ Knight เริ่มส่งอีเมลอัตโนมัติตั้งแต่เวลา 8:01 น. ในเช้าวันนั้น
    • เกิดขึ้นเมื่อ SMARS ประมวลผลคำสั่งที่เป็นเป้าหมายของการซื้อขายก่อนเปิดตลาด
    • อีเมลกล่าวถึง SMARS และระบุข้อผิดพลาดว่า “Power Peg disabled”
    • ตั้งแต่ 8:01 ถึง 9:30 น. มีการส่งอีเมลลักษณะนี้ถึงพนักงานของ Knight 97 ฉบับ
  • อีเมลเหล่านี้ไม่ได้ถูกออกแบบให้เป็นระบบแจ้งเตือน จึงไม่ได้ถูกตรวจสอบทันที
  • ทันทีหลังตลาดเปิดเวลา 9:30 น. ผู้คนหลายคนใน Wall Street ก็สังเกตเห็นความผิดปกติ
  • เวลา 9:31 น. เห็นได้ชัดว่ามีเหตุการณ์ร้ายแรงกำลังเกิดขึ้น และเวลา 9:32 น. ความสงสัยว่าทำไมมันไม่หยุดก็ยิ่งเพิ่มขึ้น
  • ในช่วง 45 นาทีแรก การ execute ของ Knight คิดเป็น มากกว่า 50% ของปริมาณซื้อขายในบางหุ้น และดันราคาหุ้นบางตัวขึ้นมากกว่า 10%
  • หุ้นอื่น ๆ มีมูลค่าลดลงจากการตอบสนองต่อการซื้อขายที่ผิดพลาด

การไม่มี kill switch และการรับมือที่ผิดพลาด

  • Knight ไม่มี kill switch สำหรับหยุดระบบที่มีปัญหาได้ทันที
  • และไม่มีขั้นตอนรับมือที่จัดทำเป็นเอกสารไว้ จึงต้องวิเคราะห์หาสาเหตุใน production ที่มีการซื้อขาย 8 ล้านหุ้นต่อนาที
  • เมื่อหาสาเหตุไม่พบ Knight จึงลบโค้ดใหม่ออกจากเซิร์ฟเวอร์ที่ deploy ถูกต้อง
  • การกระทำนี้กลายเป็นการลบโค้ดที่ทำงานได้ออกไป และปล่อยโค้ดที่มีปัญหาไว้
  • หลังจากนั้น คำสั่งแม่เพิ่มเติมเปิดใช้งานโค้ด Power Peg บนเซิร์ฟเวอร์ทุกเครื่อง ไม่ใช่แค่เครื่องเดียว ทำให้ปัญหาขยายใหญ่ขึ้น
  • Knight จึงหยุดระบบได้ก็ต่อเมื่อผ่านไปแล้ว 45 นาที

ขนาดความเสียหายและจุดจบของบริษัท

  • ในช่วง 45 นาทีแรกหลังตลาดเปิด โค้ด Power Peg รับและประมวลผล คำสั่งแม่ 212 รายการ
  • SMARS ส่งคำสั่งลูกหลายล้านรายการเข้าสู่ตลาด ส่งผลให้เกิดการซื้อขาย 4 ล้านรายการในหุ้น 154 ตัว และมีปริมาณซื้อขายมากกว่า 397 ล้านหุ้น
  • Knight ต้องแบกรับ สถานะซื้อสุทธิประมาณ 3.5 พันล้านดอลลาร์ ในหุ้น 80 ตัว และ สถานะขายสุทธิประมาณ 3.15 พันล้านดอลลาร์ ในหุ้น 74 ตัว
  • Knight Capital Group รับรู้ ขาดทุน 460 ล้านดอลลาร์ ภายใน 45 นาที
  • เนื่องจากขณะนั้นมีเงินสดและสินทรัพย์เทียบเท่าเงินสด 365 ล้านดอลลาร์ Knight จึงร่วงจากการเป็นผู้ซื้อขายหุ้นสหรัฐฯ รายใหญ่ที่สุดและ market maker รายสำคัญ ไปสู่ภาวะล้มละลาย
  • เพื่ออุดความเสียหาย Knight ต้องระดมทุนภายใน 48 ชั่วโมง และสามารถรับ เงินลงทุน 400 ล้านดอลลาร์ จากนักลงทุนประมาณ 6 ราย
  • ต่อมา Knight Capital Group ถูก Getco LLC เข้าซื้อในเดือนธันวาคม 2012 และบริษัทที่ควบรวมกันกลายเป็น KCG Holdings

บทเรียนสำหรับ DevOps และ Continuous Delivery

  • การสร้างซอฟต์แวร์ที่ดีและการทดสอบเพียงอย่างเดียวยังไม่พอ
  • หากต้องการส่งมอบคุณค่าให้ลูกค้า ซอฟต์แวร์ต้องถูก deploy อย่างถูกต้อง สู่ตลาด
  • สาเหตุของเหตุการณ์ไม่ได้อยู่ที่วิศวกรเพียงคนเดียวที่ deploy SMARS แต่อยู่ที่กระบวนการของ Knight ซึ่งไม่สามารถรับมือกับความเสี่ยงที่เผยออกมาได้
  • การ deploy ที่พึ่งพาวิธีให้คนอ่านและทำตามคู่มือย่อมมีโอกาสผิดพลาด
    • ความผิดพลาดอาจเกิดได้จากตัวคู่มือเอง การตีความคู่มือ หรือระหว่างการปฏิบัติตามคู่มือ
  • การ deploy ควรถูกทำให้เป็น automation และทำซ้ำได้ให้มากที่สุดเท่าที่เป็นไปได้ เพื่อลดโอกาสความผิดพลาดของมนุษย์
  • หากระบบ deploy อัตโนมัติรวมถึงการทำ automation ด้าน configuration, deployment และ testing ก็น่าจะหลีกเลี่ยงข้อผิดพลาดที่ก่อให้เกิด Knightmare ได้
  • ในบรรดาหลักการของ Continuous Delivery มีสองข้อที่ใช้ได้กับกรณีนี้
    • การ release ซอฟต์แวร์ต้องเป็น กระบวนการที่ทำซ้ำได้และเชื่อถือได้
    • ควรทำ automation ให้มากที่สุดเท่าที่เป็นไปได้ภายในขอบเขตที่สมเหตุสมผล

1 ความคิดเห็น

 
GN⁺ 2023-09-11
ความคิดเห็นบน Hacker News
  • ไม่ค่อยแน่ใจว่า automated deployment จะแก้ปัญหานี้ได้อย่างไร กลับกัน มันอาจยิ่งทำให้ ผลกระทบและผลพวง ของปัญหาใหญ่ขึ้นด้วยซ้ำ
    ต่อให้เปลี่ยนจาก “นักพัฒนาลืมอัปโหลดโค้ดไปยังเซิร์ฟเวอร์เครื่องหนึ่ง” เป็น “deployment agent เกิดข้อผิดพลาดขณะดาวน์โหลดไบนารี/โค้ดใหม่ลงเซิร์ฟเวอร์ และบั๊กของ agent ทำให้ข้อผิดพลาดนั้นไม่ถูกเปิดเผย” ก็ยังเป็น failure mode แบบเดียวกัน ผลกระทบคงแพร่กระจายเร็วขึ้น
    ความรับผิดชอบในกรณีนี้อยู่ที่นักพัฒนา เพราะเขียนโค้ดในลักษณะที่ ไม่ backward compatible

    • ความรับผิดชอบอยู่ที่ ทีมบริหารความเสี่ยง ทั้งหมด
      ทั้งตลาดและ Knight ต่างรู้ว่ามีปัญหาร้ายแรง แต่ก็ลอง hotfix หลายครั้งตลอด 45 นาทีก่อนจะหยุดการเทรด เป็นไปได้ว่าไม่มี kill switch หรือไม่มีใครมีอำนาจกด เพราะถ้ากดผิดจังหวะจะมี opportunity cost ราว 500,000 ดอลลาร์
      ตอนนั้นผมทำงานอยู่กับคู่แข่งของ Knight และเราก็ deploy บั๊กเลวร้ายขึ้น production บ่อยเหมือนกัน แต่ตอนทำ postmortem ก็ยังนึกภาพได้ยากว่าเหตุการณ์เดียวกันจะเกิดกับเราได้ เรามีระบบอัตโนมัติหลายตัวที่คอยบล็อกคำสั่งซื้อขายรายรายการ และ senior trader หรือคนดูแล operations สามารถสั่งให้ดึง kill switch ได้ด้วยการคุยกันแค่ 60 วินาที โดยไม่ต้องกลัวผลพวงหลังจากนั้น
      จริง ๆ แล้วเราอาจทำเงินจากการขาดทุน 400 ล้านดอลลาร์ของ Knight ได้มากกว่านี้ แต่ระบบความเสี่ยงของเราตัดสินว่า “ดีเกินกว่าจะเชื่อได้” แล้วปิดกลยุทธ์ทิ้งไปเรื่อย ๆ ทำให้กำไรลดลง
    • ถ้าเป็น CI/CD ปัญหานี้จะแก้ได้ 100%
      ต้องกลับไปดูส่วนที่ว่า “วิศวกรของ Knight คนหนึ่งไม่ได้คัดลอกโค้ดใหม่ไปยังหนึ่งในเซิร์ฟเวอร์ SMARS 8 เครื่อง” แน่นอนว่า pipeline ของ CI/CD ก็อาจล้มเหลวกลางทางและ deploy ไปได้แค่บางเซิร์ฟเวอร์ แต่ผมคิดว่าโอกาสต่ำ
      ต่อให้เป็นแบบนั้น หากเป็น Ansible Playbook มันก็คงหยุดทันทีเมื่อการส่งไฟล์ล้มเหลว และ Playbook ทั้งชุดจะ fail โดยไม่ไปถึงขั้นตอนสุดท้ายอย่างการ restart service
      นี่คือ human error และนั่นแหละคือเหตุผลที่ automation มีอยู่
      อีกทั้งส่วนที่ว่า “วิศวกรคนที่สองไม่ได้ review การ deploy และไม่มีใครรู้ว่าโค้ด Power Peg ไม่ได้ถูกลบออกจากเซิร์ฟเวอร์เครื่องที่ 8 และโค้ด RLP ใหม่ก็ไม่ได้ถูกเพิ่มเข้าไป” CI/CD ก็ป้องกันได้เช่นกัน “Pull Request” ไปยัง repository ของโค้ด Ansible จะกันไม่ให้วิศวกรคนแรก merge เข้า master/main โดยไม่มีการ review เพราะ master/main ควรถูกตั้งให้ protected อยู่แล้ว
      ผมมั่นใจว่า DevOps ที่อิง CI/CD จะแก้ปัญหานี้ได้ 100%
    • คนที่ตัดสินใจนำ flag เดิมกลับมาใช้ซ้ำอาจเป็นผู้รับผิดชอบ คนที่เคยพัฒนาซอฟต์แวร์ย่อมรู้ว่า การตัดสินใจแบบนั้นไม่จำเป็นต้องเป็นการตัดสินใจของ นักพัฒนา เสมอไป หรือโดยทั่วไปก็ไม่ใช่
    • ผมมองว่านี่เป็นปัญหาเรื่อง การลงทุนในกระบวนการ deploy ไม่เพียงพอ อนึ่ง ผมหาเลี้ยงชีพด้วยการ maintain เครื่องมือ deploy แบบ open source
      Charity Majors เคยพูดเรื่องนี้ไว้เยอะที่ Euruko เครื่องมือ deploy ไม่ควรเป็นแค่สคริปต์ bash ที่เอาโค้ตมาคลุมไว้ แต่ควรมีคนและการทดสอบเพียงพอ และทำ automation ให้ได้สุดทางเท่าที่เป็นไปได้
      หากมีกระบวนการ deploy ที่ใกล้เคียง immutable architecture, เครื่องมือที่เฝ้าดู rollout ที่ล้มเหลว/หยุดค้าง/ไม่เสร็จสมบูรณ์ และความสามารถในการย้อนกลับไปยังสถานะปกติก่อนหน้าได้อย่างรวดเร็ว ก็จะมีชั้นป้องกันเพิ่มขึ้น และทำให้เส้นทางการรับมือเมื่อเกิดเรื่องผิดพลาดง่ายขึ้น ปัญหานี้คงไม่ได้เป็นไปไม่ได้ที่จะเกิด แต่จะเกิดได้ยากขึ้น
    • เป้าหมายของ automation คือการลด edge case ที่ยังไม่ได้ระบุชัด ลงเมื่อเวลาผ่านไป
      runbook แบบทำมือจะกลายเป็นเกมเดาไปทุกครั้งที่ทำงานบนเซิร์ฟเวอร์ว่า “ทำขั้นตอนที่ 12 แล้ว และคิดว่าขั้นตอนที่ 13 ก็น่าจะทำแล้ว ดังนั้นต่อไปคือขั้นตอนที่ 14” สมองมนุษย์มักแยกไม่ค่อยออกอย่างน่าเชื่อถือ ระหว่างการรันครั้งนี้กับความทรงจำปลอมที่มาจากความจำของครั้งก่อน เมื่อมีงานที่ทำมาเป็นล้านครั้งถูกขัดจังหวะกลางคัน
      ถ้าไม่มี interlock ที่บังคับไม่ให้ข้ามขั้นตอน ทุกครั้งก็คือการพนัน และความพยายามในการสร้าง interlock นั้นก็คิดเป็นส่วนสำคัญของต้นทุน automation อยู่แล้ว
  • มีคนบอกว่า “การที่โค้ดที่ตายไปแล้ว 8 ปียังเหลืออยู่ใน codebase นั้นเป็นเรื่องลึกลับ แต่ไม่ใช่ประเด็นสำคัญ” แต่ผมว่าตรงนี้แหละคือประเด็นพอดี
    ดูเหมือนว่าพวกเขาปล่อยโค้ดที่ไม่ได้ใช้ไว้เฉย ๆ นาน 8 ปี แล้วเพิ่งพยายามจะลบมันก็ตอนจะนำ flag กลับมาใช้ซ้ำ ถ้าจัดการให้ถูกต้องตั้งแต่ 8 ปีก่อนและลบโค้ดที่ไม่ได้ใช้ออก เรื่องราวคงเปลี่ยนไปโดยสิ้นเชิง routine เก่าคงไม่ถูกปลุกขึ้นมาอีก และคงไม่มีเซิร์ฟเวอร์ที่ทำงานผิดแผนเอง
    เป็นไปได้ว่า Knight Capital ไม่ได้ใช้ version control เลยเก็บโค้ดไว้ “เผื่อไว้ก่อน” แต่แม้ใน repository ที่ควบคุมเวอร์ชันครบถ้วน ผมก็เคยเห็นนักพัฒนาที่ไม่อยากลบโค้ด ซึ่งน่าทึ่งจริง ๆ ถ้าต้องใช้อีกก็เอากลับมาจาก version control ได้ ถ้าต้องใช้อีกแต่ลืมไปว่ามันอยู่ตรงนั้น ก็คงหา code path ที่ตายแล้วไม่เจอเหมือนกัน การปล่อยมันไว้ใน source tree คือ หนี้ ล้วน ๆ
    Kevlin Henney เคยมีทอล์กยอดเยี่ยมที่ GOTO เรื่องความน่าเชื่อถือของซอฟต์แวร์ และยก Knight Capital เป็นตัวอย่างพร้อมพูดถึงประเด็นนี้ จริง ๆ แล้วเขายังอ้างถึงบทความบล็อกนี้ด้วย https://youtu.be/IiGXq3yY70o?si=hZ9HB2dlfj0vHvNK&t=463
    “ไม่มีโค้ดที่ตายแล้วจริง ๆ หรอก แค่สมมติฐานเล็ก ๆ หนึ่งข้อ หรือการเปลี่ยนแปลงของสมมติฐานหนึ่งครั้ง จู่ ๆ มันก็ไม่ใช่โค้ดตายแล้ว แต่กลายเป็นโค้ดซอมบี้ การคืนชีพของซอมบี้ apocalypse มีต้นทุน”

    • ดูเหมือนว่านักพัฒนาจำนวนมากจะรู้จัก git แค่พื้นฐาน คือ commit การเปลี่ยนแปลง ดู history ด้วย git log และอาจใช้ git blame เป็นบ้าง
      หลายคนไม่รู้วิธี filter ประวัติของ git ไม่รู้จัก git pickaxe หรือ exclude pattern และไม่เคยแม้แต่คิดว่าจะค้นหา foo ใน git log โดยยกเว้น directory บางตัวได้ เช่น git log -G'int.*foo\(' -- ':(exclude)directory'
      แต่พวกเขารู้วิธี grep ใน code tree ปัจจุบัน ดังนั้นจึงคิดว่าถ้าไม่ลบออก ก็จะหาเจออีกครั้งด้วย grep ที่เหมาะสม ถ้าลบไปแล้ว พวกเขาอาจไม่รู้วิธีหาในประวัติ git
      ในระดับหนึ่งก็พอเข้าใจได้ โค้ดใน git log มองไม่เห็นในเครื่องมือจำนวนมาก เช่น editor จะไม่เสนอใน autocomplete และมันก็ไม่ปรากฏในเอกสาร library
      ถ้าเชื่อจริง ๆ ว่าโค้ดนั้นจะถูกใช้ซ้ำ การปล่อยให้อยู่ใน tree เพื่อให้ตาม refactoring ไปด้วยและถูกค้นพบเมื่อจำเป็น ก็พอปกป้องได้บ้าง แต่ในกรณีที่ชัดเจนว่าไม่มีทางได้ใช้อีกอย่าง Knight Capital นั้นปกป้องได้ยาก
    • ได้ยินคำว่า “ถ้ามันยังทำงานได้ ก็อย่าไปแตะ” บ่อยมาก โดยเฉพาะจากผู้จัดการที่ไม่รู้ว่าตัวเองพูดอะไรอยู่
      แม้แต่การอัปเดตที่แค่ “ลบโค้ดเก่า” ก็อาจรู้สึกยากสำหรับคนที่มองว่าการเปลี่ยนแปลงใด ๆ ล้วนสร้างความเสี่ยงให้พัง พูดอย่างเป็นธรรม ทุกการเปลี่ยนแปลงมีความเสี่ยง แต่การปล่อยโค้ดเก่าไว้ก็มีความเสี่ยงเช่นกัน
      อย่างน้อยตอนนี้เราก็สามารถชี้ไปที่กรณีนี้เป็นตัวอย่างความเสี่ยงที่ชัดเจนได้
    • การปล่อยโค้ดตายไว้ไม่ใช่เรื่องน่าประหลาดใจเท่าไร แทบทุกบริษัทที่ผมเคยทำงานด้วยมีเรื่องแบบนั้น
      สิ่งที่ผมไม่เข้าใจจริง ๆ ทุกครั้งที่เห็นเรื่องนี้คือ การที่พวกเขา นำ flag เดิมกลับมาใช้ซ้ำ แทนที่จะสร้าง flag ใหม่ ทำไมถึงทำแบบนั้นกัน
    • version control ก็ไม่ได้สมบูรณ์แบบไร้ที่ติ ประวัติโค้ดทั้งหมดอาจหายไปตลอดกาลได้ด้วย git rebase ครั้งเดียว
      หวังว่าองค์กรส่วนใหญ่จะมีกระบวนการป้องกันไม่ให้เรื่องแบบนั้นเกิดรอบ main branch แต่ผมเองก็เคยทำตารางฐานข้อมูล production พังโดยไม่ตั้งใจในองค์กรเล็ก ๆ ดังนั้น git rebase โดยไม่ตั้งใจก็ไม่ใช่เรื่องที่เป็นไปไม่ได้
    • ผมเคยเขียนประสบการณ์ตอนทำงานที่ Knight หลังเหตุขัดข้องไว้ใน thread พี่น้องอีกอันหนึ่ง
      ยังมีปัญหาอีกอย่างคือพวกเขาใช้ database ที่มีได้แค่ 256 columns เวลาต้องการ column ใหม่ ก็มักจะเอา column เก่าที่ “ตอนนั้นไม่ได้ใช้” กลับมาใช้ซ้ำ
      ถ้าจำไม่ผิด ภายในเองก็ยอมรับกันโดยทั่วไปว่านี่เป็น “ความคิดที่แย่” แต่ไม่มีใครจัดให้การเก็บกวาดโค้ดเก่าหรือการสร้าง best practice ที่ดีกว่าเป็นเรื่องสำคัญ
  • ระบบ continuous deployment ใด ๆ ที่ผมเคยเจอคงไม่สามารถป้องกันบั๊กเฉพาะตัวนี้ได้
    มันเป็นสถานการณ์ rollout แบบค่อยเป็นค่อยไป แต่ในโค้ดมีบั๊กเชิงตรรกะที่ทำให้ถ้า installation หนึ่งตัวล้มเหลวในขั้นตอน rollout แบบค่อยเป็นค่อยไปนั้น บริษัทก็ล้มละลายได้
    ถ้าจะป้องกันสิ่งนี้ คงต้องตรวจตอน runtime ว่าเวอร์ชันซอฟต์แวร์ เช่น git SHA ตรงกันหรือไม่ และเพิ่ม fault injection เข้าไปใน test ที่เรียกใช้ infrastructure สำหรับ rollout ซอฟต์แวร์ด้วย

    • ระบบ continuous deployment ที่ดีจริงไม่ควรยอมให้ configuration กับ code คลาดกัน เดิมเคยมีการเปิด Power Peg แต่ตอนนี้มีการเปลี่ยน configuration สำหรับ flag ที่ใช้เปิดอย่างอื่น และก็มีการเปลี่ยน code ที่ตีความ flag นั้นต่างออกไปด้วย
  • มันเป็นยุค Wild West อย่างแท้จริง สิ่งสำคัญอีกอย่างคือหลังจากนั้น ระบบเทรด เปลี่ยนไปมาก
    ตอนผมเริ่มทำงานในสายนี้เมื่อปี 2009 ธนาคาร broker และตลาดหลักทรัพย์ต่างก็มีความน่าเชื่อถือของระบบค่อนข้างแย่ บ่อยครั้งต้องโทรไปยืนยันว่าปริมาณที่ execute จริงคือเท่าไร
    ผมจำได้ตอนตลาดหลักทรัพย์อิตาลีกำลัง rollout ระบบ ช่วงหนึ่งพวกเขา “ทดสอบ” ในสภาพแวดล้อมที่ production กับ UAT ปนกัน และถ้าจำไม่ผิด ก็แค่เปลี่ยน IP สำหรับ connection ส่งคำสั่งซื้อขายหลังตลาดปิดเพื่อทดสอบ release ถัดไป สภาพแวดล้อม UAT มีบั๊กเยอะเกินไปและส่วนใหญ่ก็แทบจะตายครึ่งหนึ่ง จึงทดสอบที่นั่นไม่ได้
    อย่าให้เริ่มพูดถึง spreadsheet Excel ที่มีโค้ด VBA ระดับที่ ChatGPT ยังด่า ซึ่งใช้ตั้งราคาผลิตภัณฑ์ที่มี volume เป็นเลขศูนย์ยาว ๆ เลย
    ทุกวันนี้ต่างไปมาก ส่วนหนึ่งก็เพราะเหตุการณ์เหล่านี้ ส่วนใหญ่ถูก automate แล้ว และท่าทีแบบคาวบอยก็ลดลงมาก
    มี kill switch ที่บังคับใช้ มีการเฝ้าระวังความเสี่ยง/กิจกรรมเทรดหลายชั้น มีการเฝ้าระวังฝั่งตลาดหลักทรัพย์ และบทเรียนที่ได้มาอย่างเจ็บปวดจำนวนมากถูกสะท้อนเข้าไปในระบบจริง ๆ นี่จึงเป็นเหตุผลที่ผู้คนมักมองความยากของการสร้างระบบเทรดที่ดีแบบไร้เดียงสา กลยุทธ์ฉลาดขึ้นก็จริง แต่แก่นสำคัญมักเป็นวิธีไม่ให้ตายเพราะสิ่งที่อยู่นอกเงื่อนไขปกติ

  • คนในวงการ quantitative finance ทุกคนรู้จัก Knight Capital แบบไม่ต้องอธิบาย มีสำนวนว่า “pulling a knight capital” ด้วย หมายถึงการเลือกใช้ทางลัดแม้แต่ในระบบ mission critical ที่สามารถทำให้บริษัทล้มละลายได้ในพริบตา แล้วต้องชดใช้ราคาของมัน

    • จริง ๆ แล้วมันยังถูกใช้ในเอกสาร onboarding ของบริษัทเราด้วย
  • ระบบของทีมเรามีบทบาทสำคัญต่อรายได้วันละหลายร้อยล้านดอลลาร์ ถ้าระบบล่มนานพอ รายได้นั้นก็จะหายไป ในที่นี้ “นานพอ” คืออย่างน้อยหลายชั่วโมง และโดยทั่วไปภายในช่วงเวลานั้นเรามักจะทำให้กลับสู่สภาพปกติได้โดยไม่ให้ผลกระทบภายนอกใหญ่เกินไป
    เราก็มีกระบวนการแบบแมนนวลเหมือนกัน แต่ไม่ว่าจะเป็นกระบวนการแมนนวลแบบไหน ก่อนเริ่มเราจะจัดทำเอกสาร ขั้นตอนการ rollback และเฝ้าติดตามการ deploy นอกจากนี้ยังแยกการ deploy โค้ดออกจากการ deploy ฟีเจอร์ และ deploy ฟีเจอร์แบบค่อยเป็นค่อยไปหลัง feature flag
    ฟีเจอร์ใหม่หรือการเปลี่ยนแปลงโค้ดจะต้องมี feature flag ใหม่ มันเจ็บปวดและช้า แต่ช่วยให้หลีกเลี่ยงสถานการณ์เสี่ยงกับความตื่นตระหนกได้ และยังลดภาระงาน operations กับ on-call ลงได้มาก
    ถ้าจะพังอย่างร้ายแรงจริง ๆ จะต้องผ่าน “ตัวกรองข้อบกพร่อง” หลายชั้น เช่น code review พลาดการเปลี่ยนพฤติกรรมที่ไม่มี feature flag, การทดสอบแบบแมนนวล/ในสภาพแวดล้อมพัฒนาก็พลาด, การ deploy ล้มเหลว, rollback ล้มเหลวหรือทำผิด, ไม่มีการเฝ้าติดตามที่จะส่งแจ้งเตือนว่าปัญหายังไม่ถูกแก้, ไม่สามารถ escalate ไปยังระดับบนได้ทันเวลา และเวลาผ่านไปมากพอจนสูญเสียความสามารถในการทำตาม SLA
    สำหรับการเปลี่ยนแปลงแบบแมนนวลที่เสี่ยงกว่า อาจให้สองคนช่วยกันทำการเปลี่ยนแปลงได้ คนหนึ่งชี้ผ่านวิดีโอคอลว่ากำลังเปลี่ยนอะไร อีกคนตรวจสอบยืนยัน
    ถ้าคุณกำลังดูแลระบบที่ SLA เป็นระดับนาทีและการเปลี่ยนแปลงย้อนกลับไม่ได้ คุณต้องรู้วิธีที่ใช้ได้จริงในการเฝ้าติดตามและ rollback ภายในไม่กี่นาที ถ้าเป็นงานใหม่และเป็นงานแมนนวล ก็ควรตรวจทานสี่รอบ และให้คนอื่นนั่งดูอยู่ข้าง ๆ ไม่อย่างนั้นก็เป็นเพียงเรื่องของเวลา ก่อนที่ปัญหาหลายอย่างจะซ้อนกันต่อเนื่องจนถึงจุดที่แก้ไม่ได้ ต่อให้เก่งและฉลาดแค่ไหน หากมนุษย์ต้องเปลี่ยนแปลงหรือเริ่มการเปลี่ยนแปลงด้วยมือ ความผิดพลาดก็เกิดขึ้นได้เสมอ และความน่าจะเป็นของความผิดพลาดนั้นต้องถูกฝังอยู่ใน กระบวนการจัดการการเปลี่ยนแปลง

    • รายได้นั้นจะหายไปจริง ๆ หรือ? หรือแค่เกิดขึ้นภายหลังเท่านั้น?
      ในการค้าทั่วไปหรือ B2B หลายกรณีลูกค้าสามารถลองซื้อแบบเดิมอีกครั้งในอีกไม่นานได้ ไม่ใช่ “ถ้าไม่ใช่ตอนนี้ก็ไม่มีวันได้”
      ผมเองก็เคยลองซื้อของที่อยากได้อีกครั้ง ตอนที่ผู้ขายล่ม, เซิร์ฟเวอร์แตกเพราะประกาศใหม่กับดีมานด์มหาศาล, หรือมีปัญหาการปิดปรับปรุงของธนาคาร
  • บทความที่เกี่ยวข้อง:
    Knightmare: A DevOps Cautionary Tale (2014) - https://news.ycombinator.com/item?id=22250847 - กุมภาพันธ์ 2020, 33 ความคิดเห็น
    Knightmare: A DevOps Cautionary Tale (2014) - https://news.ycombinator.com/item?id=8994701 - กุมภาพันธ์ 2015, 85 ความคิดเห็น
    Knightmare: A DevOps Cautionary Tale - https://news.ycombinator.com/item?id=7652036 - เมษายน 2014, 60 ความคิดเห็น
    เพิ่มเติม:
    The $440M software error at Knight Capital (2019) - https://news.ycombinator.com/item?id=31239033 - พฤษภาคม 2022, 172 ความคิดเห็น
    Bugs in trading software cost Knight Capital $440M - https://news.ycombinator.com/item?id=4329495 - สิงหาคม 2012, 1 ความคิดเห็น
    Knight Capital Says Trading Glitch Cost It $440 Million - https://news.ycombinator.com/item?id=4329101 - สิงหาคม 2012, 90 ความคิดเห็น
    มีอย่างอื่นอีกไหม?

    • เคยมีทฤษฎีเบื้องต้นเกี่ยวกับสาเหตุ แต่สุดท้ายก็ผิด
      Nanex ~ 03-Aug-2012 ~ The Knightmare Explaned - https://news.ycombinator.com/item?id=4337359 - ไม่มีความคิดเห็น
  • ปัญหาที่แท้จริง ถ้าจะยอมใช้สำนวนแบบ “ชาวสกอตแท้” ก็คือการใช้ ชุดค่าผสมของ config ที่ไม่ได้ทดสอบกับ binary release
    config กับ binary สามารถ rollout ให้สอดคล้องกันพร้อมกันได้ และถ้าทำเช่นนั้นก็จะป้องกันปัญหาประเภทนี้ได้ แน่นอนว่ายังมีข้อผิดพลาดอื่น ๆ ด้วย แต่ถ้าไม่มีเงื่อนไขนี้ ปัญหานี้ก็เกิดขึ้นไม่ได้

  • ส่วนที่ว่า “ทำไมโค้ดที่ตายไปแล้ว 8 ปีถึงยังอยู่ใน codebase เป็นเรื่องลึกลับ แต่นั่นไม่ใช่ประเด็นหลัก” อาจไม่ใช่ความผิดพลาดที่เลวร้ายที่สุดในเรื่องนี้ แต่ก็พูดไม่ได้ว่าไม่ใช่ประเด็นหลัก
    ถ้าตัดฟีเจอร์ที่ตายแล้วออกเชิงรุก ซอฟต์แวร์ก็จะเรียบง่ายกว่าและเข้าใจได้ดีกว่า และโอกาสที่จะหลุดควบคุมก็จะน้อยลง การเดินหน้าอย่างเดียวไม่หยุดโดยไม่มีการบำรุงรักษาแบบนี้ ไม่ว่าจะคำนวณไว้แล้วหรือไม่ก็ตาม คือ ความเสี่ยง

  • ดีใจจริง ๆ ที่ไม่ได้เขียนโค้ดที่ route เงินหลายล้านดอลลาร์โดยอัตโนมัติโดยไม่มีมนุษย์เข้ามาเกี่ยวข้อง
    มันเหมือนเขียนโค้ดที่ใช้บินเครื่องบินเจ็ตลำใหญ่ ใครจะอยากรับผิดชอบแบบนั้นกัน

    • ความรับผิดชอบแบบนั้นเองยังพอรับได้ แต่ต้องเป็น ความรับผิดชอบของผม จริง ๆ กล่าวคือ ถึงหัวหน้าจะอยาก release พรุ่งนี้ ผมก็ต้องมีอำนาจที่จะพูดว่า “จะไม่ release จนกว่า XYZ จะถูกแก้” แม้การสร้าง XYZ จะใช้เวลาเพิ่มอีก 2 ปีก็ตาม
    • ถ้าทำให้ถูกต้อง มันก็ไม่น่ากลัว และงานที่ทำให้ถูกต้องอาจดูเหมือนงานที่น่าเบื่ออย่างสุด ๆ
      ผมมองว่าเป็นงานที่เหมาะกับคนบางประเภทที่รัก process, testing, simulator และ redundancy ตัวโค้ดที่ใช้บินเครื่องบินเองเป็นเพียง 1% ของวิศวกรรมในที่แบบนั้น
    • ตอนแรกมันกระตุ้นความกังวล แต่ถ้ามีการควบคุมและการเฝ้าติดตามที่ดี มันก็จะกลายเป็นเรื่องประจำวัน
      แค่แก้ความกังวลที่ผุดขึ้นมาเองทีละอย่างก็พอ และยิ่งกังวลอย่างมีเหตุผลมากเท่าไร ก็ยิ่งดีต่อธุรกิจ จากประสบการณ์ในวงการการเงิน ผมคิดว่าปัญหาของ Knight เป็นปัญหาเทคนิค 10% และเป็นปัญหาที่คนระดับคล้าย CTO เข้าใจผิดว่าตัวเองกล้าได้กล้าเสีย 90% ไม่ใช่แค่วันนั้นหรือสัปดาห์นั้น แต่เป็นภาพรวม
    • ไม่รู้ว่าทุกบริษัทเป็นแบบนั้นไหม แต่โดยปกติเมื่อซอฟต์แวร์ส่งคำสั่งซื้อขายเข้า exchange จะมีคนจำนวนมาก เฝ้าติดตามอย่างใกล้ชิด ว่าเกิดอะไรขึ้น
      เหตุการณ์นี้น่าจะมีส่วนอยู่บ้างเหมือนกัน
    • ดีใจจริง ๆ ที่ไม่ได้เสียชีวิตไปกับการทำงานในวงการการเงิน