บันทึกทั้งหมด วิศวกรรม

ทำไม Rust ทำให้บิล AWS ของเราน่าเบื่อ (ในทางที่ดี)

บิล AWS ที่น่าเบื่อคือความหรูหราที่ถูกมองข้าม นี่คือวิธีที่การเลือกใช้ Rust ในส่วนที่ทำงานหนัก เปลี่ยนค่าโครงสร้างพื้นฐานจากเซอร์ไพรส์รายเดือน ให้กลายเป็นเส้นตรงที่คุณเลิกกังวล

คำชมที่ดีที่สุดเรื่องโครงสร้างพื้นฐานไม่ใช่คำว่า “เร็ว” หรือ “สวยงาม” แต่คือ “ความเงียบ” ลูกค้าเปิดหน้า AWS console สามเดือนหลังเปิดตัว เห็นตัวเลขที่แทบจะเหมือนเดือนก่อน แล้วก็ปิดแท็บไป ไม่มีอะไรต้องตรวจสอบ ความน่าเบื่อนั้นแหละคือผลงานของเรา

ความสงบนั้นส่วนใหญ่มาจากการตัดสินใจที่เราทำตั้งแต่ต้นและตั้งใจทำ นั่นคือการเขียนส่วนที่ทำงานหนัก (hot path) ด้วย Rust

เงินหายไปไหนจริง ๆ

บนบิลคลาวด์ส่วนใหญ่ ต้นทุนไม่ได้แปรผันตามฟีเจอร์ — แต่แปรผันตาม ความสูญเปล่า ทั้ง CPU ที่เสียไปกับ garbage collection หน่วยความจำที่จองไว้เผื่อ runtime แทนที่จะเผื่อข้อมูลของคุณ เครื่องที่เปิดอุ่นไว้ตลอดเพราะกลัว cold start คำขอที่ควรใช้ 8ms กลับใช้ 80ms คูณด้วยทุกคำขอ ทุกวัน

สิ่งเหล่านี้ไม่ปรากฏตอนเดโม แต่ปรากฏบนใบแจ้งหนี้

Rust จัดการความสูญเปล่าโดยตรง ไม่มี garbage collector หมายถึงไม่มี GC pause และไม่ต้องจองหน่วยความจำมาเลี้ยงมัน การใช้หน่วยความจำที่ต่ำและคาดเดาได้ ทำให้เราอัดงานลงในเครื่องที่เล็กลงได้ หรือใส่ลงใน Lambda ระดับหน่วยความจำต่ำได้สบาย และ latency ที่เร็วและสม่ำเสมอ หมายถึงใช้เครื่องน้อยลงเพื่อรักษาเป้า p99 เท่าเดิม

ตัวอย่างจริง

เราย้าย pipeline ประมวลผลรูปภาพของลูกค้ารายหนึ่งจากเซอร์วิส Node ไปเป็น Rust worker ตัวเล็ก ตัวงานไม่เปลี่ยน — ย่อขนาด เข้ารหัสใหม่ เขียนลง S3 แต่เวอร์ชัน Node ต้องใช้หน่วยความจำ 1GB ถึงจะอยู่สบาย และยังพุ่งตอนโหลดหนัก ส่วนเวอร์ชัน Rust ทำงานเดียวกันได้ใน 128MB ด้วย latency ที่แทบไม่ขยับ ไม่ว่าจะประมวลผลรูปเดียวหรือสองร้อยรูป

บิลไม่ได้ลดแค่ 10% แต่ลดราว 70% สำหรับงานนั้น และที่สำคัญกว่าคือ มันหยุดขยับ ทีมเลิกถูกปลุกเรื่องหน่วยความจำ autoscaler เลิกกระตุก เส้นกราฟต้นทุนกลายเป็นเส้นตรง

เส้นต้นทุนที่แบนราบไม่ได้แค่ถูกลง แต่มันคาดเดาได้ และความคาดเดาได้คือสิ่งที่ทำให้คุณวางแผนได้

”แต่ Rust เขียนช้า”

นี่คือข้อโต้แย้งตัวจริง และมันก็มีเหตุผล Rust เรียกร้องจากคุณมากกว่าตั้งแต่แรก — borrow checker คือผู้รีวิวที่เข้มงวดและไม่เคยมีวันอารมณ์ดี ถ้าเราเขียน ทุกอย่าง ด้วย Rust เราจะช้าลงและคุณต้องจ่ายค่าชั่วโมงนั้น

เราจึงไม่ทำแบบนั้น เราเลือกอย่างจงใจ ส่วน CRUD หน้าแอดมิน โค้ดเชื่อมต่อ — อยู่ในภาษาที่ส่งงานได้เร็วที่สุด ซึ่งมักเป็น TypeScript ส่วน Rust สงวนไว้สำหรับส่วนที่ทำงานหนักและทำงานตลอด: เส้นทางคำขอที่ยิงล้านครั้งต่อวัน worker ที่ย่อยคิวไม่หยุด เซอร์วิสที่ latency เป็นตัวกำหนด p99 ของคุณ

นั่นคือราว 15% ของโค้ดที่แบกต้นทุนรันไทม์ไว้ 80% การลงแรงวิศวกรรมเพิ่ม ตรงนั้น คืนทุนทุกเดือนที่ระบบยังมีชีวิตอยู่ ส่วนการลงแรงกับหน้าตั้งค่า ไม่คืนทุน

ส่วนที่ทบต้น

นี่คือจุดที่มักมองข้ามในใบเสนอราคา บิลรายเดือนที่ถูกลงไม่ใช่การประหยัดครั้งเดียว แต่ทบต้นตลอดอายุของผลิตภัณฑ์ งานที่รันด้วยต้นทุน 60% ไม่ได้ประหยัด 40% ครั้งเดียว แต่ประหยัด 40% ทุกเดือน เป็นปี ๆ พอผลิตภัณฑ์อายุครบสามปี ส่วนต่างของค่ารันสะสมมักจะแซงส่วนต่างของค่าพัฒนาไปไกล

นั่นคือการแลกที่เราทำแทนคุณ: ความเข้มงวดทางวิศวกรรมเพิ่มอีกนิดในไม่กี่จุดที่สำคัญ แลกกับบิลที่น่าเบื่อจนคุณลืมเปิดดู เราคิดว่ามันคุ้ม และฝ่ายการเงินของคุณคิดแบบนั้นแน่นอน

พร้อมเมื่อคุณพร้อม

อยากได้วิธีคิดแบบนี้ในงานของคุณไหม?

ดูราคาใน 2 นาที