จากการไปแบ่งปันเรื่องของ Software Architecture ในมุมมองด้านโครงสร้าง
พบว่าจะมีโครงสร้างของระบบหลายรูปแบบ
แต่ส่วนใหญ่ที่พบคือ จะแยกเป็น tier ต่าง ๆ ออกมา
แล้วแต่ละ tier จะมีขนาดที่ใหญ่มาก ๆ ตามเวลาหรือจำนวน feature
ไม่ว่าจะเป็น web tier, business tier, service tier และ database tier
โดยการโตแบบนี้จะเรียกว่า Monolith
หรือบ่อยครั้งจะเรียกว่า Legacy system นั่นเอง
ส่งผลให้ดูแลรักษายาก
พัฒนายาก
build นาน
scale ยาก !!
และต่อมาก็คิดว่าแยกออกไปเป็น service เล็ก ๆ จะช่วยได้
ทั้ง micro-service, nano-service หรือ macro-service
แต่ก็ไม่ได้ช่วย อาจจะสร้างปัญหาใหม่ ๆ ขึ้นมาอีก !!
ดังนั้นแนวทางที่มักจะแนะนำก่อนที่จะแยกคือ ทำของเดิมให้มันดีขึ้นก่อนไหม ?
Q: ถ้าระบบมีปัญหาแก้ไขอย่างไร ?
A: restart ไงละ
Q: ถ้ามีปัญหาทุก ๆ วัน แก้ไขอย่างไร ?
A: ตั้ง schedule restart มันทุกวันไงละ ง่ายจะตาย !!
เราคงไม่ทำในระยะยาวกันนะ แต่ระยะสั้น ๆ อาจจะทำก็ได้
ถ้าความต้องการของระบบต้องการ scale ให้รองรับผู้ใช้งานที่มากขึ้น
คำว่ามากขึ้นมีทั้ง
- ผู้ใช้งานมากขึ้น
- ข้อมูลมากขึ้น
แต่ก่อนอื่นระบบงานต้องมีระบบ monitoring หรือ observability ที่ดีก่อน
ทั้ง log, metric และ tracing
เพื่อช่วยให้การวิเคราะห์ การปรับปรุงได้ดียิ่งขึ้น
มาเริ่มกันเลย
ก่อนอื่นต้องเข้าใจก่อนว่า เมื่อระบบโตขึ้น
feature มากขึ้น
ผู้ใช้งานมากขึ้น
ข้อมูลมากยิ่งขึ้น
มันส่งผลต่อการพัฒนา ทดสอบ และ deploy รวมทั้งการ scale ด้วยหรือไม่ ?
ถ้าใช่ แสดงว่า เราเจอปัญหาเข้าให้แล้ว
จำเป็นจะต้องแก้ไขปัญหานั้น ๆ ให้เร็วที่สุด
อย่าผลัดวันประกันพรุ่ง !!
ตัวอย่างของ scale ระบบที่มักจะทำกันอย่างแรกคือ Vertical scale หรือ Scale up
คือการขยายเครื่องให้ใหญ่ขึ้นทั้ง CPU, Memory, Disk และ Network
มีกี่เครื่อง หรือ กี่ส่วนของขยายกันไป
ยิ่งระบบไหนอยู่บน cloud ได้ลากไปทางขวากันง่าย ๆ และ สนุกเลย !!
เป็นแนวทางที่เรียบง่าย
ไม่ต้องเปลี่ยนแปลง architecture
ไม่ต้องเปลี่ยนแปลงรูปแบบการ deploy
ไม่ต้องเปลี่ยนแปลงรูปแบบการ monitor
แต่การ scale แบบนี้ก็มี limit ที่กำหนดไว้
ยิ่งกว่านั้นเมื่อค่าใช้จ่ายที่ใช้ไป
มันไม่สมเหตุสมผลต่อทาง business
ค่าใช้จ่ายมากกว่ารายรับที่ได้
รวมทั้ง performance ที่ได้รับกลับมา
ยิ่งถ้าล่มไปกระทบต่อผู้ใช้งาน และ business อีก
โดนด่าอีก
มี single-point-of-failure อีก
ดังนั้นอาจจะต้อง scale ในรูปแบบของ Horizontal scale หรือ Scale out
คือการเพิ่มเครื่องเข้าไป
ทั้งฝั่งของ frontend
ทั้งฝั่งของ backend/service
ทั้งฝั่งของ database
และยังต้องเพิ่มพวก Load balance เข้ามา
เพื่อช่วยกระจาย load ไปยังเครื่องต่าง ๆ ที่เพิ่มเข้ามา
หรืออาจจะมี API gateway เข้ามาอีก
ซึ่งแน่นอนว่า ช่วยทำให้ระบบงานดีขึ้น รองรับผู้ใช้งานได้มากขึ้น
แต่ตามมาด้วยความซับซ้อนที่สูงขึ้น
อีกอย่าง Architecture ของระบบงานที่ออกแบบและพัฒนากันมา
สนับสนุนโครงสร้างแบบนี้หรือไม่ ? (Stateless vs Stateful)
รูปแบบของการ monitor และ deploy ก็เปลี่ยนไป
ต้องทำการเพิ่ม Caching ใน layer/tier ต่าง ๆ ด้วยหรือไม่ ?
เพื่อปรับ response time ให้รวดเร็วมากขึ้น
ลด load ต่าง ๆ ที่เข้ามาในระบบ เช่น
- Web browser caching
- CDN caching
- Application-level caching
- Database query caching
จะจัดการเรื่อง caching ได้ดี
จำเป็นต้องเข้าใจการใช้งานข้อมูล (Read vs Write)
การออกแบบ data model ที่เหมาะสมต่อการใช้งาน
อย่าลืมว่า caching มันคือ การสร้าง duplication data ขึ้นมานะ !!
ต่อมาในส่วนของ Database ก็ต้อง scale ด้วย
เช่นการทำ replica เพื่อรองรับการ read ที่มากขึ้น
แต่ระวังเรื่อง lag time ระหว่างการ write ที่ primary กับการ read ที่ replica ด้วย
ยังไม่พอเรื่องของ data model ที่ใช้งาน
ต้องมองทั้งการ read และ write
บ่อยครั้งพบว่า เรามักจะออกแบบ model เดียวแล้วใช้ทั้ง read และ write
ซึ่งอาจจะไม่เหมาะสมนัก
จึงต้องปรับปรุงเรื่องนี้ เพื่อลดการ read หรือ query ที่หนักเกินไป
เพราะว่าจะใช้งาน CPU และ memory ของ database มากเกินไป
จากนัั้นก็จะกระทบต่อ operation อื่น ๆ
ในเรื่องนี้อาจจะเรียกว่าการทำ
- Materialized view
- Denormalization vs Nomalizarion
- Pre-aggregate/summarize data
ในเรื่องของข้อมูลใน database ก็เช่นเดียวกัน
ข้อมูลอะไรไม่ใช้งานแล้ว หรือ นาน ๆ ใช้ครั้ง
อาจจะต้องแยกออกจากกัน
มิเช่นนั้น ระบบอาจจะมีปัญหาเมื่อ data สูงขึ้นเรื่อย ๆ
ในส่วนนี้อาจจะทำพวก house keeping ก็ได้
ทำ data partitioning ก็ได้
ทำ data sharding ก็ได้
อยู่ที่ use case ของระบบงานนั่นเอง
ใน database นั้นอย่าลืมดูพวก slow query ด้วย
เพื่อทำการปรับปรุงให้ดีขึ้น
หรือแม้แต่ query ไหนที่ใช้งานเยอะ ๆ
ก็ต้องปรับในส่วนของ application ให้ใช้งานลดลง
เช่น caching และ data model ก่อนหน้านั่นเอง
ยังไม่พออาจจะทำการแยกงานบางอย่างออกมาจากระบบ
เช่นงานที่ใช้ resource เยอะ หรือ งานที่ทำงานนาน ๆ
สามารถแยกออกไปทำด้วยการใช้งาน messaging queue เข้ามาช่วย
เช่น
- Upload file
- ส่ง email หรือพวก notification ต่าง ๆ
- การ generate report
- พวก batch operation
จะช่วยลดการใช้งาน resource ในส่วนหลักไปได้เยอะ
หรือสร้าง buffer ขึ้นมาให้ระบบงานค่อย ๆ ทำงานไปนั่นเอง
ดังนั้นจะเห็นได้ว่าระบบ Monilith นั้นมีรูปแบบของการปรับปรุงหลายรูปแบบ
เราจำเป็นที่จะต้องเรียนรู้ด้วยเช่นกัน
ว่าระบบงานของเราอยู่ใน stage ไหน
จะได้เลือกวิธีการที่เหมาะสม
ก่อนที่สุดท้ายจึงจะแยกออกมาเป็น service เล็ก ๆ
เพราะว่าทุกครั้งที่เราแยกอะไรออกมา
จะทำให้ระบบเราซับซ้อนขึ้นอย่างมาก (มีได้ก็มีเสีย)
ขั้นตอนทั่วไป ที่ผมชอบทำ มีดังนี้
- ปรับปรุง code และ การ query database ก่อน
- เพิ่ม caching เข้าไปในจุดที่เจอปัญหา
- ขยายเครื่องก่อน จนค่าใช้จ่ายไม่สมเหตุสมผล
- ทำการเพิ่มเครื่องทั้ง web, business และ database ตามปัญหาที่พบเจอ
- จัดการข้อมูลให้ดี
- ใช้ messaging queue เข้ามาช่วย
ลองดูว่าระบบของเราเป็นอย่างไร ?