มาประหยัดค่า AWS EC2 ด้วยการใช้ spot instance กัน
Cloud computing ดูจะเป็น norm ของการ host server ไปแล้วในทุกวันนี้ AWS ก็เป็นผู้นำตลาดเจ้าหนึ่ง สิ่งที่ทุกธุรกิจหนีไม่พ้นก็คงเป็นเรื่องการทำ cost optimization เพื่อให้ได้กำไรสูงสุด สิ่งหนึ่งเล็กๆน้อยที่เราสามารถลดค่า server ได้ง่ายๆเลยก็คือการเลือกใช้ spot instance แทนการใช้ on demand instance ปกติ
Spot instance คืออะไร?
ต้องเกริ่นก่อนว่า Data Center ระดับโลกอย่าง AWS มี High Availability ที่สูงมาก หาก server ล่มทีนึงจะก่อให้เกิดความเสียหายอย่างสูงทั้งต่อลูกค้าแล้วก็ชื่อเสียงของ AWS เอง ดันนั้น AWS เลยมี Server ที่เหมือนเป็น Server สำรองอยู่จำนวนหนึ่งที่พร้อมจะทำงานอยู่ตลอดเวลาเผื่อกรณีเกิดเหตุอะไรขึ้นมา ทีนี้การที่เรามี server รอไว้เฉยๆ (cold standby) มันก็จะเป็นค่าใช้จ่ายที่ไม่ทำให้เกิดรายได้แบบหนึ่ง AWS ก็เลยนำเครื่องเหล่านี้มาหารายได้เพิ่มด้วยโมเดล spot instance นี่เอง โดยให้ราคาที่ถูกลงสูงสุดถึง 90% แลกมากับการที่เครื่องของเราจะไม่ได้รับการการันตีเรื่อง availability และพร้อมที่จะถูก AWS ยึดคืน (terminate) ได้ทุกเวลา
ทำไมเราควรใช้ spot instance
แน่นอนครับ หลักๆเลยคือเรื่อง “ค่าใช้จ่าย” การใช้ spot instance ใน workload ที่เหมาะสมย่อมจะช่วยให้เราประหยัดค่าใช้จ่ายได้ส่วนนึง ผมมองว่าเป็นวิธีที่องค์กรสามารถนำมาใช้ในเรื่อง cost optimization ได้ง่ายๆ โดยที่ไม่ต้องลงแรงเยอะและเห็นผลได้ค่อนข้างเร็ว (low hanging fruit effort) อย่างไรก็ดี เราต้องทำความเข้าใจระบบและเงื่อนไขของ spot instance ให้ดีเสียก่อน ไม่เสียอย่างนั้น การใช้ spot instance อาจจะกระทบต่อ performance ของระบบ รวมถึงทำให้ระบบของเราล่มไปเลยได้ ถ้าเรา set up ไม่ถูกวิธี
workload แบบไหนที่ควรใช้ spot instance
จากประสบการณ์ของผม workload หลักๆที่เราสามารถนำ spot instance มาใช้ได้คือระบบที่เป็นเราต้องการทำงานในช่วงระยะเวลาหนึ่งสั้นๆ และ/หรือ ไม่ใช่ critical system หรือระบบจำพวก “ทัพเสริม” ตัวอย่างเช่น
- ระบบ CI/CD ที่เราสร้างเครื่องขึ้นมาเพื่อ run build pipeline ในช่วงเวลาสั้นๆ
- ระบบ cron job / scheduler ต่างๆที่ trigger ขึ้นมาทำงานหนึ่งสั้นๆ แล้วก็จบไป
- ระบบ auto scaling ที่ spin เครื่องขึ้นมารับ spike load ในช่วงเวลาหนึ่ง ทั้งนี้เราควรใช้เป็น mixed fleet ระหว่างเครื่องแบบปกติ on-demand/reserved instance ผสมรวมกับ spot instance เพื่อให้แน่ใจว่าระบบของเรายังมี availability ที่ดีพอ
- ระบบที่เป็น stateless เนื่องจาก spot instance พร้อมจะถูก terminate เครื่องได้ตลอดเวลา หากระบบเป็นแบบ stateful จำเป็นต้องทำให้มั่นใจว่าหากเครื่องถูก terminate ไปแล้ว state ของงานที่รันไว้จะถูกส่งต่อไปยัง worker node อื่นได้
- Non production cluster ที่เรายอมรับได้กรณีเกิด down time ขึ้น เช่น dev/test server หรือเรามี ops ที่คอยช่วยเหลือยามมีปัญหา โดยเฉพาะกรณีเจอ price surge ที่ทำให้เราไม่สามารถ bid เครื่องมาได้สำเร็จ
workload แบบไหนที่ไม่ควรใช้ spot instance
แน่นอนว่าไม่ใช่ทุกๆงานจะเหมาะกับการใช้งาน spot instance ระบบที่มีความ critical สูง เช่นระบบที่มี SLA availability 99.99% ไม่ควรใช้ spot instance หรือว่าถ้าใช้ก็ควรมีการ “ผสม”กับ instance ประเภทอื่นเพื่อให้แน่ใจว่าระบบเรายังสามารถทำงานได้ในระบบที่ “น่าพอใจ” ในยามที่เราไม่สามารถ spin spot instance ขึ้นมาได้ การทำ mixed fleet ของ auto-scaling group เป็น practice ที่แนะนำ
จากประสบการ์ของผมที่เคยใช้ spot instance กับ ECS cluster ที่ใช้ EC2 backed ด้วย spot instance 100% เปิด cluster ตลอด 24/7 ใน non prod environment พบว่า จะมี 1–2 ครั้งต่อปีที่จะเจอกับเหตุการณ์ price surge ที่ spot instance ไม่สามารถ provision ได้เลย (มีคนใช้เครื่องแบบเดียวกับเราเป็นจำนวนมากหรือว่า AWS มีความจำเป็นต้องใช้เครื่องเลยดึง resource กลับไปหมด) นอกจากนั้นระหว่างระยะเวลาเครื่องจะมีการถูก terminate และ provision ให้ใหม่เรื่อยๆครับ เพราะฉะนั้นควรจะทำให้มั่นใจด้วยว่า workload ของคุณเป็น stateless หรือมีการจัดการ storage หรือ state ที่แยกออกจากตัว ec2 instance เช่นการสร้าง ebs volume แยกเก็บข้อมูลต่างหาก ไม่เก็บ data ลงใน ebs ที่ provide มากับ instance
เราจะเริ่มใช้ spot instance ได้อย่างไร
การใช้ EC2 spot instance เริ่มจากการ config ก่อนเรา provision เครื่องให้ใช้ type เป็น spot instance ก่อน โดย config นี้จะอยู่ในที่ต่างๆที่เกี่ยวข้องกับการ provision ec2 เช่น
ใน Configure Instance ของ Launch Instance Wizard
ใน wizard ของการ launch instance เราสามารถกดเลือก Purchasing option เป็น spot instance ได้ เมื่อเราเลือก option นี้แล้ว จะมีตัวเลือกเพิ่มขึ้นมา พร้อมแสดงราคา spot instance price ของแต่ละ zone ใน region นั้นด้วย
Maximum Price เป็นการกำหนดราคาสูงสุดที่เรายอมจ่าย เนื่องจาก spot instance เป็นราคาแบบ “bidding” คือราคาจะมีการเปลี่ยนแปลงเรื่อยๆ เราสามารถควบคุมได้ว่าเราจะยอมจ่ายมากที่สุดเท่าไหร่ เช่นจากตัวอย่าง ราคา spot instance ของ t3.small ตอนนี้คือ $0.0062 เทียบกับ on-demand ที่ $0.0208 บางคนอาจจะยอมจ่ายไม่เกิน $0.01 ถ้าเกินจากนี้ขอไปใช้ on-demand ดีกว่าเพื่อลดความเสี่ยงเรื่อง availability เป็นต้น
Persistent request เป็นการระบุว่าหาก ec2 instance นี้ถูก interrupt/terminal ให้ทำการขอเครื่องใหม่ขึ้นมาทดแทนเลยหรือไม่ ทั้งนี้ข้อควรระวังคือหากเครื่องนี้ไม่ได้มีการผูก elastic ip ไว้ public ip จะเปลี่ยน หากเครื่องเป็น public internet facing ต้องระวังเรื่องนี้ไว้ด้วย
ใน auto-scaling group
จะเห็นได้ว่าใน auto-scaling group นั้น เราสามารถตั้งค่าให้ผสมระหว่าง On-demand กับ spot instance ได้ด้วย ทำให้เราสามารถ balance ระหว่างเรื่อง availability กับ cost-optimization ได้อย่างดี รวมถึงสามารถเลือก strategy ในการขอ spot instance ได้ว่าเราอยากจะเน้นเรื่อง availability (เลือก spot จาก instance type ที่มีคนใช้ไม่เยอะ) หรืออยากจะเน้นเรื่อง cost (เลือก spot จากราคาที่ต่ำที่สุด)
Tip & Trick ของการใช้ spot instance
เนื่องจากการใช้ spot มีความไม่แน่นอนเรื่อง availability (เพื่อแลกมาด้วยราคาที่ถูกลงมาก) การใช้ spot จึงมี practice บางอย่างที่จะทำให้เรายังมี availability ของระบบที่ดีอยู่ practice เหล่านี้คือสิ่งที่ผมใช้อยู่จากประสบการณ์ใช้งาน spot instance จริง ทั้งใน production และ non production environment
ใช้ Mixed fleet Auto-scaling Group ผสมระหว่าง on-demand instance กับ spot instance
การผสมเครื่องสองประเภททำให้เรายังสามารถมี availability ที่ดีของระบบแต่ก็ยังลดค่าใช้จ่ายส่วนหนึ่งไปได้ โดยเฉพาะหากระบบมี spike load แค่เป็นเพียงบางช่วงเวลา การ scale out ด้วย spot ทำให้เรามาค่าใช้จ่ายส่วนเพิ่มเติมนี้ลดลงได้
เลือกเครื่อง spot หลาย generation และ/หรือ family เพื่อให้โอกาสได้เครื่องสูงขึ้น
ในการทำ auto-scaling group เราสามารถเลือกเครื่อง spot หลาย generation/family เพื่อให้โอกาสได้เครื่องสูงขึ้น เช่น mixed ระหว่าง m5a, m5, m4 เป็นต้น รวมถึง family เช่น m5,m5a, m5d, m5ad ทั้งนี้เราต้องศึกษาความแตกต่างระหว่างรุ่นก่อน บางครั้งการผสมแบบนี้อาจเกิดปัญหาได้ เช่น ใน ECS cluster คุณจะใช้ความสามารถ ENI trunking เพื่อให้เครื่องสามารถรัน container ได้มากกว่าจำนวน network interface ที่ attach อยู่กับเครื่องได้ต้องเป็น เครื่องใน generation m5 เท่านั้น m4 หรือเก่ากว่าจะไม่สามารถใช้ได้ หากเราใช้ไปจะกลายเป็นว่าเราใช้เครื่อง m4 มากขึ้นกว่าเดิม กลายเป็นไม่ประหยัดไปแทนได้
เจอ Price Surge ไม่จำเป็นต้องขยับเครื่องไปรุ่นสูงขึ้นเสมอไป
เวลามีปัญหาราคา spot instance พุ่งจากการที่ instance family ที่เราใช้มี high demand ในช่วงเวลาหนึ่ง แทนที่จะขยับไปใช้เครื่องที่ใหญ่ขึ้น เช่น m5.large ไปเป็น m5.xlarge ให้ลองไปดูหน้าราคา spot instance ก่อน (EC2 → Spot Requests → Pricing history) บางทีเครื่องใน sub family เดียวจะมีราคาที่ถูกกว่า เช่น m5d บางครั้งจะราคาถูกว่า m5 หรือ m5a เพราะคนไม่ค่อยนิยมใช้ กลายเป็นเวลาเราได้เครื่องที่มี ssd attach มาด้วยในราคาที่ถูกกว่าเสียอีก
จากรูปจะเห็นได้ว่า แม้ราคา on-demand m5d.large จะแพงว่า m5.large แต่ราคา spot instance กลับใกล้เคียงกันมาก แถมบาง zone ยังถูกกว่าด้วย! แถมจะเห็นว่าราคามีความ stable กว่า เนื่องจากไม่ได้เป็นที่นิยมเหมือน m5.large ที่เป็นเครื่องระดับมาตรฐานรองรับ load ส่วนใหญ่ได้ หากคุณเลือกใช้ spot instance m5d แทน m5 คุณจะได้ SSD attach มากับ instance โดยที่จ่ายเท่ากัน!
Monitoring เป็นสิ่งจำเป็น
เนื่องจาก spot instance สามารถถูก AWS interrupt ดึงเครื่องคืนได้ทุกเวลา เราควรเซ็ทระบบ alert ขึ้นมาเพื่อให้เรารู้ได้กรณีที่เราถูกยึดเครื่องคืน หรือเกิดปัญหา price surge จนไม่สามารถ spin instance ขึ้นมาได้ การใช้ AWS cloudwatch + lambda + sns ร่วมกันเป็นวิธีการสร้าง monitoring ง่ายๆที่มีค่าใช้จ่ายต่ำและได้ผลลัพธ์ที่ดี
Stateful system อย่าลืมจัดการกับ state ที่เกิดขึ้น
หากมีการใช้ storage หรือระบบเป็น stateful ควรสร้าง ebs volume แยกไว้แล้วทำ script สำหรับ mount volume กลับไปเสมอ ในกรณีที่เราโดน AWS เรียกเครื่องคืน data ของเราจะได้ไม่สูญหาย (ebs volume ที่สร้างติดมากับ instance จะถูก terminate ไปพร้อมกับ ec2 instance) หรือจะใช้เป็น storage ประเภทอื่นเช่น EFS ก็ได้ขึ้นอยู่กับความต้องการใช้งาน
Spot instance ลดค่าใช้จ่ายได้แค่ไหน?
หากดูจาก pricing history จะเห็นได้ว่า สามารถประหยัดค่า instance จากในใช้ spot instance เทียบกับ on-demand instance ได้มากขึ้น 50–70% เลยทีเดียว ตัวอย่างเช่น เครื่อง m5.large หากเรารันแบบ 24x7x365 วัน เราจะต้องจ่าย
on-demand: 0.096x24x7x365= $5,886.72 ต่อปี
spot: 0.035x24x7x365 = $2,146.20 ต่อปี*
จะเห็นได้ว่าประหยัดเงินไปได้ $3740.52 ใน 1 ปีต่อ EC2 1 instance หรือกว่า 60% เลย
(*ทั้งนี้ราคา spot เป็น bid อาจจะแพงกว่านี้ตามช่วงเวลา แต่ราคาจะไม่เกินราคา on-demand เด็ดขาด)
โดย AWS เองมี report แสดงการใช้ spot ว่าช่วยคุณประหยัดไปเท่าไหร่แล้ว สามารถกดดูได้จาก หน้า spot request ใน EC2 Service (เอาตัวจริงมาให้ดูไม่ได้นะ)
ตัวอย่างการใช้งานจริง
หนึ่งในระบบงานที่ผมเลือกใช้ spot instance คือ CI/CD runner ของ GitLab โดย runner ของ GitLab แบบ self-hosted นั้นสามารถจะให้เป็นแบบ auto-scale บน AWS ได้ runner ที่ทำหน้าที่ execute งาน เมื่อเสร็จงานก็จะถูก terminate ไป มี life-cycle ของ instance ที่สั้น หากเครื่องถูก terminate ก็จะมีผลต่อแค่งาน build 1 job เท่านั้น (ซึ่งสามารถ retry ใหม่ได้) เหมาะกับการใช้เครื่องแบบ spot อย่างมาก รายละเอียดวิธี build runner ไว้ผมจะเขียนเป็นอีกบทความแยกไว้นะครับ
ระบบนี้รับ load จาก developer 8 ทีม (ทีมมี developer ทีมละ 4 คนโดยเฉลี่ย) สามารถรองรับการ push code พร้อมๆกันในวันใกล้ปิด sprint ได้โดย developer ไม่ต้องรอ feedback จาก build pipeline นานเกินไป (build start ภายใน 3 นาที) ค่าใช้จ่ายระบบนี้อยู่ที่ประมาณ $20 ต่อเดือน ซึ่งนับว่าถูกมากสำหรับการรองรับทีมขนาดนี้
บทส่งท้าย
การใช้ EC2 spot instance เป็นวิธีการลด cost บน AWS วิธีหนึ่งที่ทำได้ง่ายโดยแลกกับ availability ที่พร้อมจะถูก AWS terminate ตลอดเวลา หากระบบมีการจัดการที่ดีและเหมาะสม เราก็ยังสามารถทำระบบให้มี Availability ที่อยู่ในระดับยอมรับได้พร้อมกับการประหยัดค่าใช้จ่าย สุดท้ายอย่าลืมสิ่งสำคัญก่อนการทำ cost optimization ก็คือ “การสื่อสาร” กับ stakeholder ที่อาจได้รับผลกระทบ เช่น developer หรือ tester สำหรับ non production environment หรือ Business owner สำหรับ production environment หากการสื่อสารไม่ดี ความเสียหายที่เกิดขึ้นอาจจะมากกว่าค่าใช้จ่ายที่เราพยายามจะประหยัดก็ได้นะ