Post-incidence เหตุการณ์ CU Get Reg ล่มเมื่อต้นเดือนมกราคม

Pipat Saengow
Thinc.
Published in
2 min readJan 30, 2023

หมายเหตุ: บทความนี้คัดลอกทั้งหมดมาจากเฟสบุ้คโพสต์นี้ เพื่อความง่ายในการเข้าถึงเท่านั้น ไม่มีเนื้อหาเพิ่มเติม

บทความนี้จะมาเล่าเกี่ยวกับเหตุการณ์ที่เว็บ cugetreg.com พังเมื่อสามอาทิตย์ที่แล้วครับ เนื่องจาก Bug นี้ค่อนข้างน่าสนใจและผู้ใช้หลายคนอาจสงสัยว่าปกติทำไมเว็บล่ม ซึ่ง cugetreg ไม่เขียนเรื่องพวกนี้

บทความนี้อาจจะออกแนว Technical นิดนึงทำให้อ่านยาก

Credit คนที่เจอและแก้ Bug: Nut Pinyo, paphonb, และ แสนยากร เสียงเสนาะ

เรื่องมีอยู่ว่า…

ก่อนอื่น cugetreg.com เป็นเว็บสำหรับช่วยจัดตารางเรียนในจุฬาแบบ unofficial มีคนใช้อยู่พอประมาณในช่วงลงทะเบียนเรียน (สูงสุดถึง 15,000 คนต่อ week) [1]

เว็บนี้นิสิตทำกันเองในเวลาว่าง เลยไม่ได้มีคนดูแลเว็บ 24/7 แต่ปกติเว็บก็อยู่ได้โดยไม่พัง เพราะ automate ไว้เยอะอยู่

เมื่อประมาณสามอาทิตย์ที่แล้ว (Jan 5) ตอนที่ทีมทำเว็บหลายคนไปเที่ยว ตจว. จู่ๆ เว็บก็ขึ้นหน้าเปล่าพังๆ โหลดข้อมูลไม่ขึ้น

ซึ่งแปลกมาก เพราะไม่ได้มีใครไปทำอะไรกับเว็บเลย แต่ตอนนั้นก็แก้อะไรไม่ได้เพราะกำลังเที่ยวอยู่

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

อย่างแรกที่เจอคือสำนักทะเบียน (Reg Chula) โพสต์ประกาศเปิดรอบลงทะเบียนพิเศษวันนั้นพอดี [2]

แต่เว็บนี้รอดการลงทะเบียนมาหลายรอบหลายเทอมแล้วจึงไม่น่าพังได้

มี change เดียวที่เกิดขึ้นระหว่างรอบลงทะเบียนก่อนหน้ากับรอบนี้คือ การ เปลี่ยนจาก Docker Compose เป็น Kubernetes ตอน Dec 2022 ซึ่งผู้ใช้ก็ใช้มาเป็นอาทิตย์แล้วโดยไม่พัง [3]

ก็เลยมาดู container log เจอว่า “UnhandledPromiseRejection” ตอนสร้างบัญชีผู้ใช้ [7]

แต่ที่น่าสนใจกว่านั้นคือ log ชี้ว่าปัญหาเกิดจาก code ที่ผมเองเขียนไว้เมื่อ 2 ปีที่แล้ว (Oct 2021) [4]

ถึงตอนนี้ก็ยิ่งงงหนักเข้าไปใหญ่คือถ้า bug นี้มีอยู่ตั้งแต่ปี 2021 จริงทำไมมันพึ่งมาทำเว็บล่มตอนปี 2023

ถึงตรงนี้ คงจะรู้กันแล้วว่า ต้องเกี่ยวกับเรื่องที่ NodeJS UnhandledPromiseRejection เปลี่ยนจาก warn เป็น throw ใน v15 [5]

เพราะ cugetreg เคยมีการ upgrade จาก v14 ข้ามไป v16 [6]

แต่ก็วนมาคำถามเดิมคือการ upgrade NodeJS เกิดขึ้นตอน Aug 2022 แล้วมาทำเว็บล่มตอน 2023 ได้ยังไง?

ข้อมูลที่ให้ไปน่าจะเพียงพอที่จะหาคำตอบได้แล้ว บรรทัดต่อไปคือเฉลย

คำตอบคือ…

ความจริงเว็บมันพังตั้งแต่ตอน Upgrade NodeJS ใน Aug 2022 แล้ว แค่สังเกตไม่ได้

Oct 2021: ผมเขียน code bug เข้าในระบบ แต่เพราะ error ถูก suppress ไว้เลยไม่พังและไม่มีใครเจอ

Aug 2022: มีการ upgrade NodeJS ไปใช้ version ใหม่ที่ไม่ suppress error ทำให้เว็บล่มตลอดเวลา แต่… เพราะเราตั้งให้ Docker Compose restart ระบบตลอดถ้าเกิดล่มไป ซึ่ง restart delay ของ docker คือ 100ms [8] ดังนั้นแม้เว็บจะล่มตลอดเวลาแต่ผู้ใช้แทบไม่มีทางสังเกตตอนเว็บล่มทันเลย

Dec 2022: เปลี่ยนมาใช้ Kubernetes ซึ่งทำให้เวลาระหว่างที่เว็บล่มกับเว็บกลับขึ้นมานานขึ้นเพราะ วิธีการ restart ของ Kubernetes คือถ้าระบบล่มก่อนอายุ 10 นาที ระบบจะ delay เป็นเวลา 10s, 20s, 40s, … ระหว่างการ restart ดังนั้นผู้ใช้จะเห็นเว็บล่มนานขึ้นเรื่อยๆแบบ Exponential [9]

Jan 2023: Reg Chula ประกาศวันลงทะเบียนรอบพิเศษ

- Code ส่วนที่ error จะทำงานก็ต่อเมื่อผู้ใช้สมัครบัญชีใหม่เท่านั้น เนื่องจากก่อนวันลงทะเบียน ผู้ใช้ส่วนใหญ่มักเป็นผู้ใช้เดิมที่เข้ามาดูตารางตัวเอง ไม่ได้มาสมัครใหม่ จึงไม่ทำให้เว็บล่มถี่และต่อเนื่องกันมากพอที่จะเกิด Exponential delay

- แต่พอถึงวันลงทะเบียน ผู้ใช้เข้ามาสมัครใหม่ถี่ขึ้น เว็บก็เลยล่มแบบสังเกตได้จาก exponential delay

สรุปคือ สาเหตุที่เว็บล่มแบบไม่คาดคิดแบบนี้เกิดจาก bug ที่แอบซ่อนอยู่, Trigger ภายนอกที่เหมาะพอดีที่จะทำให้ bug เปิดเผย และความเปลี่ยนแปลงภายในระบบที่ทำให้เกิด Side-Effect ในส่วนที่ดูไม่เกี่ยวข้อง

เมื่อทุกอย่างต่อไปนี้เกิดขึ้น:

1) มี bug ดังกล่าวใน code ที่ทำให้เกิด error

2) มีการ upgrade ชิ้นส่วนที่ทำให้ error กลายเป็น crash

3) policy ของชิ้นส่วนระบบ ที่ทำให้สังเกต crash ไม่ทัน

4) มีการ replace ชิ้นส่วนที่บังเอิญทำให้ policy เปลี่ยน ทำให้สังเกตการล่มได้

5) มีผู้ใช้ใหม่ถี่มากพอจากการลงทะเบียนรอบพิเศษ ที่ทำให้ code ที่ bug ทำงานและ interact กับ policy ใหม่

เว็บก็เลยล่มวันนั้นพอดี จาก bug เมื่อปี 2021

สุดท้ายแล้วทีมหาต้นตอเจอแล้วก็แก้ Bug นั้นไป [11]

ขายของ

แต่ยังไงก็คงมี Bug แบบข้อหนึ่งหลงเหลืออยู่อีกมาก ดังนั้นถ้าใครสนใจสามารถลองหา Bug ใน Source Code ได้เลยเพราะ cugetreg.com เป็น Open Source Project [10]

Project นี้มีขนาด ~21 KLOC มี contributor ~20 คน และมีชิ้นส่วนค่อนข้างเยอะตาม Diagram (แทรกเพื่อให้ Post ไม่ดูมีข้อความมากเกินไป) [12] ซึ่งน่าจะทำให้หา Bug ได้อย่างสนุกสนานเลย.

System Component Diagram

Footnotes

[1] เลขจาก Google Analytic

[2] โพสต์ประกาศ: https://www.facebook.com/ChulaRegNet/posts/pfbid02u2LwqihiXKPPdDqHbZaQc5HBTp8a6x1JZYtobMMhzXAzZ55hSxEX8d9PBUXS2u53l

[3] ไม่มีทีม QA แต่มีนิสิตผู้ใช้ทุกคนทำหน้าที่เป็น QA มีฟอร์มแจ้ง dev ที่มุมขวาบนเว็บ

[4] commit ที่ใส่ bug ลงไป: https://github.com/.../7de19c875120db0133e7c3abb57623e091...

[5] Changelog NodeJS v15: https://nodejs.org/en/blog/release/v15.0.0/...

[6] commit upgrade NodeJSv14->16: https://github.com/.../6c533d40593108277532f8c35e82b6f502...

[7] Parallel Save: https://github.com/Automattic/mongoose/issues/8132

[8] Docker Engine Restart Policy: https://docs.docker.com/engine/reference/run/...

[9] Kubernetes Restart Policy: https://kubernetes.io/.../workloads/pods/pod-lifecycle/...

[10] CUGetReg GitHub: https://github.com/thinc-org/cugetreg

[11] Bug Fix Commit: https://github.com/.../c1e1dc89b3d1f5e6351a1929919463e89a...

[12] ทุกอย่างใน diagram นี้รันบนคอมขนาดธรรมดาตัวนึงที่ทาง Reg Chula สนับสนุนมาให้ฟรี ซึ่งทีมงานก็ทีมออกแบบให้รับโหลดของนิสิตทั้งมหาลัยได้

--

--