Introduction to Kubernetes – Chapter 1 From Monolith to Microservices

https://davidxiang.com/2022/01/24/monolith-to-microservices/

 

 

 

 

 

เกริ่นนำ

ตอนนี้หลายๆ บริษัทนั้นเอาระบบงานของตัวเองไปรันอยู่บน Cloud เช่นเหล่า Startup ต่างๆ รวมไปจนถึงบริษัทระดับ Enterprise ที่เริ่มมองเห็นแนวโน้มที่จะย้ายระบบต่างๆ ที่ตัวเองมีนั้นไปอยู่บน Cloud แต่ก็ไม่ใช่ทุกบริษัทที่จะย้ายไป Cloud ได้ง่ายๆ เพราะระบบงานต่างๆ ที่ใช้งานมานานนับสิบๆ ปีหรือมากกว่านั้นถูกพัฒนาด้วยเทคฯ เก่า และที่สำคัญคือมันเป็น Monolithic Applications

Monolith นั้นคืออะไร มันก็คือระบบงานที่มี Component หลายๆ ตัวรวมอยู่ในระบบงานเดียวและที่สำคัญมันมักจะพันกันวุ่นวายไปหมด ผลลัพธ์ของมันก็คือมันมักจะใช้ Resources เช่นพวก Hardware เปลืองและบริหารจัดการยากไม่ว่าจะเป็นเรื่องการเพิ่ม Feature หรือการ Deploy ระบบ

ลองนึกภาพตามกันดูว่า ถ้าบริษัทเรามีระบบงานนึงซึ่งมันทำงานแบบ “Black Box” น่ะครับ คือไม่มีใครรู้ว่าข้างในมันทำอะไรบ้างและที่สำคัญคือไม่มีเอกสารบอกเลยว่า Business logic ต่างๆ ที่อัดแน่นอยู่ในนั้นมันมีอะไรบ้าง
ทุกคนก็จะมึนๆ แล้วก็จะสงสัยว่าพอเรา Request ไปที่เจ้า App ตัวที่ว่าเนี่ยมันไปทำอะไรบ้างก็ไม่รู้ จะมารู้อีกทีก็ตอนเห็น Response ออกมานั่นแหละครับ แล้วลองนึกดูว่าถ้าคุณจะต้องเป็นคนที่มาทำให้ไอ้เจ้า “Black Box App” ที่ว่านี้ไปทำงานอยู่บน Cloud คุณจะต้องฝ่าด่านอรหันต์กี่ด่าน…

เอาล่ะ… เรามาดูกันให้ชัดอีกทีว่าเจ้า Monolith มันมักจะมีนิสัยยังไงกัน

  • Code เยอะๆ พันกันไปหมด
  • Build/compile ทีก็นานเหลือเกิน ยิ่งเพิ่ม Feature ยิ่งช้าไปเรื่อยๆ
  • ทำงานอยู่บน Server เครื่องเดียว ไม่ก็ทำงานบน VM (หรือ Mainframe กันเลยทีเดียว)

ช่วงแรก มันก็มักจะทำงานได้ตามที่ต้องการครับ
แต่พอระบบมัน Growth ไวขึ้นมันก็เริ่มจะออกอาการว่าทรัพยากรเครื่องเซิร์ฟเวอร์ที่เคยประเมินไว้ว่าพอมันก็ไม่พอใช้
แล้วทีนี้ทำยังไง … ใช่ครับเราก็เพิ่มให้มันสิครับ อัดมันเข้าไปทั้ง CPU ทั้ง RAM อัดไปให้เต็มความสามารถที่ Mainboard มันจะรับไหว

แต่ถ้าเพิ่มจนเต็ม จนไม่รู้จะเพิ่มยังไงอีก ทำไงต่อครับ
เพิ่มเครื่องสิครับ แล้วก็เอา LB มาคั่นข้างหน้า… และนี่น่าจะเป็นท่าที่หลายๆ ที่นิยมใช้กัน
ใช่ครับ มีเงินก็จ่ายไปครับ

แต่มันยังมีเรื่องอื่นๆ ด้วยครับ ไม่ใช่แค่เรื่องทรัพยากรไม่พอใช้ เช่น
แก้ไขระบบนิดหน่อย แต่ระบบใช้งานไม่ได้ทั้งหมด ซึ่งก็มีหลายที่แก้เรื่องนี้ด้วยการเพิ่มเครื่องแล้วทำ Active/Passive แต่มันก็ดันไปเพิ่มงานให้ฝั่ง Ops ที่ต้องคอยไปอัพเกรดทั้งสองข้างมันเป็น Version เดียวกันอยู่ตลอด
ยังครับ ยังมีเรื่องค่า License ต่างๆ ที่ต้องคูณเข้าไปอีก

มันก็เลยมีคำใหม่ … Microservice นั่นเอง

คือเราสามารถที่จะ Deploy แยกเฉพาะส่วนที่จำเป็นต้อง Deploy ก็พอไม่จำเป็นต้อง Deploy ไปทั้งหมดทั้งๆ ที่ไม่เกี่ยวอะไรกับการ Change ในครั้งนั้น
และที่สำคัญมันใช้ทรัพยากรแยกกันของใครของมันต่างหาก

โดย Microservices-based architecture เนี้ย มันก็ล้อตาม Event-driven architecture กับ Service-Oriented architecture (SOA) นั่นแหละครับคือแบ่งระบบงานออกเป็นส่วนย่อยๆ
แล้วแต่ละระบบย่อยๆ ก็คุยกันผ่าน API หรือจะคุยกับระบบข้างนอกก็ยังได้ ส่วนใหญ่แล้วแต่ละ Microservice มักถูกพัฒนาด้วยภาษาโปรแกรมมิ่งที่ค่อนข้างใหม่
ซึ่งทั้งนี้ก็ขึ้นอยู่กับว่างานในส่วนต่างๆ นั้นใช้ภาษาอะไรทำแล้วถึงจะเหมาะ ซึ่งข้อนี้ก็ช่วยได้มากในเรื่องการลดค่าใช้จ่ายเรื่อง Hardware เพราะบางภาษานั้นกินทรัพยากรเครื่องจริงๆ

แต่ก็ต้องยอมรับอย่างนึงว่าการทำ Microservice นั้นมันจะเพิ่มความวุ่นวาย (Complexity) ให้กับ Architecture โดยรวมของระบบแน่นอน (อย่างหลีกเลี่ยงไม่ได้)
แต่ประโยชน์ที่จะได้กลับมาก็คือเรื่อง Scalability คือการมีการใช้งาน Service ไหนมากๆ เราก็ไป Scale เฉพาะ Service นั้นๆ ก็พอ โดยจะ Scale แบบทำมือหรือจะแบบ Auto scaling ก็ยังได้
และอีกเรื่องที่ถือว่ามีประโยชน์มากๆ คือเมื่อไหร่ก็ตามที่มีการ Upgrade หรือ Patch เราไม่ต้องทำการ Build และ Restart ใหม่ทั้งหมดแบบที่เคยทำใน Monolith อีกต่อไป
คือเราสามารถทำเฉพาะส่วนที่มีการ Change เท่านั้นทำให้ระบบโดยรวมนั้นไม่มี Downtime

แล้วเราจะเปลี่ยนจาก Monolith เป็น Microservice ยังไงล่ะ?

ขั้นตอนในการเปลี่ยนจาก App ที่เป็น Monolith ไปสู่ App ที่เป็น Microservice นั้นเริ่มจากการทำ Refactor ครับ
แต่ถึงอย่างไรก็ดี การที่เราจะไปเปลี่ยน App ที่ใช้งานมาร่วมสิบๆ ปีเพื่อนำมันไปใช้งานบน Cloud นั้น
การทำ Refactor ก็นับได้ว่าเป็นความท้าทายใหญ่ที่เหล่าบริษัท Enterprise จะต้องเผชิญอย่างหลีกเลี่ยงไม่ได้ครับ

ซึ่งโดยปกติมันก็มีอยู่ 2 ท่าใหญ่ๆ ที่มักทำกันคือ “Big-bang” กับ “Incremental Refactoring”
โดย Big-bang นั้นจะทำกันโดย Refactor ทุกอย่างที่มีอยู่ใน Monolith ให้อยู่ในรูปแบบของ Microservice
แต่มันก็จะต้องแลกมาด้วยการที่ต้องหยุดการพัฒนาหรือการเพิ่ม Feature ใหม่ต่างๆ ลงไป

ส่วนอีกแบบนึงหรือที่เรียกว่า Incremental Refactoring นั้น จะโฟกัสไปที่การพัฒนา Feature ที่จะเพิ่มเข้าไป
ให้อยู่ในรูปแบบ Microservice และทำให้มันสื่อสารกับตัว Monolith เดิมผ่าน API นั่นเอง
ซึ่งข้อดีของมันก็คือเราไม่ต้องไปเขียนเพิ่ม Feature ใหม่ลงในตัว Monolith เดิม

แต่ไม่ว่าว่าเราจะเลือกวิธีไหนก็ตาม อีกสิ่งนึงที่มักจะเป็นคำถามที่เรียกว่ายากอย่างนึงก็คือ…
เราจะแยก Monolith ออกมาเป็น Microservice ยังไง? ต้องแยกเป็น Microservice กี่อัน?
ข้อมูลในฐานข้อมูลนั้นจะแยกกันอย่างไร สุดท้ายแล้วคือเราจะทดสอบ Microservice ที่เพิ่งสร้างมาได้อย่างไร
ในเมื่อมันก็มี Dependencies ของตัวมันเองอยู่

จากที่เล่าไปข้างต้นนั้นก็พอที่จะทำให้เห็นภาพว่า การ Refactor จาก Monolith ไปเป็น Microservice นั้นมันไม่ใช่เรื่องที่จะทำได้อย่างง่าย
เพราะมันจะมีความท้าทายหลายอย่างที่ต้องเจอในระหว่างที่ต้องทำ Refactor

และที่สำคัญอีกข้อนึงก็คือ “ไม่ใช่ทุก Monolith ที่จะสามารถ Refactor ไปเป็น Microservice ได้”
ถ้าจะให้เล่าก็คือระบบงานที่ใช้งานมานานๆ เช่นพวก Mainframe เนี่ย มันถูกเขียนขึ้นมาจากภาษาเก่าๆ เช่น Cobol ก็ดี RPG ก็ดี
ซึ่งระบบต่างๆ พวกนี้มักผูก Business logic เข้ากับ Data store ซึ่งมันทำให้ยากต่อการ Refactor (หรือเรียกอีกอย่างว่าปล่อยมันไว้แบบนั้นแหละ อย่าไปยุ่งกับมันเลย)

ยังครับ ความท้าทายมันยังไม่จบเท่านี้
หลังจากที่เรา Refactor จนออกมาเป็น Microservice สำเร็จแล้วเนี่ย
มันยังมีความท้าทายอีกข้อนึงคือเราจะเอา Microservice ที่ว่าเนี้ยไปรันที่ไหน แล้วรันด้วยอะไร?
ลองนึกภาพตามว่าถ้าเราเอา Microservice แต่ละตัวไปรันไว้ใน Server หรือ VM ตัวเดียวกัน
โอกาสที่ Libraries ของ Microservice แต่ละตัวจะตีกัน มีสูงมาก ซึ่งมันมักส่งผลทำให้เวลาทำงานอยู่ดีๆ ถ้า Libraries เกิดเปลี่ยนไป
ส่งผลทำให้ Microservice อีกตัวเดี้ยงขึ้นมาซะเฉยๆ อย่างนั้น เพราะ Server มันก็มี OS ซึ่งมันก็มี Libraries ของมันอยู่
การจะเปลี่ยนแปลงอะไรใน OS อาจจะส่งผลกระทบกับ Microservice อื่นๆก็ได้

มันก็เลยนำไปสู่การนำ App ที่ทำเป็น Microservice เนี้ยไปรันให้อยู่ในรูปแบบ Container
โดยเราสามารถระบุ Environment ให้ Container แต่ละตัวได้เลยของใครของมัน ไม่ขึ้นแก่กันและกัน
ซึ่งการทำแบบนี้เราจะเรียกว่า “Containerized application environments” ซึ่งประโยชน์ของมันก็มีหลายอย่างเลย เช่น scale แยกได้ของใครของมัน
ง่ายต่อการเปลี่ยนแปลงไม่ต้องกลัวไปทำให้ส่วนอื่นพัง แล้วก็ยังทำให้อยู่ในรูปแบบ automation ได้อีกด้วย (ก็พวกการทำ Pipeline CI/CD นั่นแหละ)

เอาล่ะครับ ที่เกริ่นมากทั้งหมดมันก็เป็นเพียงการปูทางเพื่อที่จะเข้าสู่เรื่อง Kubernetes นั่นเอง.. (ยาวชิบ)

 

 

 

Leave a Reply

Your email address will not be published. Required fields are marked *