รู้ไว้(ใช่ว่า) ก่อนไป Microservice

Pongsakorn Semsuwan
4 min readApr 12, 2021

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

1. แตก service ยังไง สำคัญมาก

หลักการการเลือกแตก service มีผลตามมาอย่างมาก ทั้งในเรื่องของ extra development cost ที่จะเกิดหลังจากนี้, ความซับซ้อนของทั้งการ read และ write, การจัดการ database, caching เรียกได้ว่าแตกดีมีชัยไปกว่าครึ่ง แตกผิดมีความเสี่ยงต้องกลับมาแก้สูง

ส่วนตัวแนะนำให้แยกพวกที่มันไม่ transactional ออกไปก่อน ส่วนพวก business service ที่มันค่อนข้างผูกกัน เอาไว้หลังๆ

smell ง่ายๆอย่างนึงคือ ถ้าเราพบว่าเวลาเราจะเขียน read เพื่อเอาข้อมูล entity ชนิดนึงแล้วเราเจอว่าเราต้อง compose API จาก อีก service นึงด้วยเสมอ อาจเป็นได้ว่าไอสอง service นี้มันควรอยู่ด้วยกันตั้งแต่แรกรึเปล่านะ

2. แตกเมื่อไหร่ดี

ส่วนตัวคิดว่าควรเริ่มด้วย monolith เสมอ เพราะสำหรับ start up นั้น ความเสี่ยงในการปล่อยของไปแล้ว fail นี่ มีสูงมาก การเอาของขึ้นให้เร็ว เปลี่ยนให้เร็วตามตลาด/ความต้องการของลูกค้า มีความสำคัญอย่างมากในช่วงแรก

ส่วนตัวคิดว่าช่วงที่เหมาะกับการแตก service คือช่วง ปลายๆ ของการ scale ไปจนถึงช่วงที่กลายเป็น corporate แล้ว ซึ่ง business จะเริ่มนิ่ง มี engineer มากพอ และ pain ของการ deliver feature มันเริ่มไปอยู่ที่การ coupling ของแต่ละทีม/service
ไม่จำเป็นต้องรีบทำ microservice เอาเท่ห์ ตามบริษัทใหญ่ๆ ขนาดนั้น

ปิดท้ายด้วย quote ของลุง martin fowler

Almost all the successful microservice stories have started with a monolith that got too big and was broken up

Almost all the cases where I’ve heard of a system that was built as a microservice system from scratch, it has ended up in serious trouble.

แต่ผมฟัง talk นึงก็มีบริษัทที่เริ่มด้วย microservice ตั้งแต่แรกเลยนะ (CTO/co-founder มาพูดเอง) อันนี้แกจะเน้นเรื่องการทำ tools / generator / automate ให้คนในบริษัทใช้ เพื่อความเป็นระเบียบ

3. ความยุ่งยากของการ Read (API Composition / CQRS)

ก่อนตัดสินใจแตก microservice อยากให้เห็นภาพความยุ่งยากที่จะตามมา ซึ่งจะยากกว่าเดิมประมาณ 187%

กล่าวคือปกติเวลาเราจะ query ถ้าข้อมูลมันอยู่ที่ถังเดียวกัน เราก็ join กันมายัดเป็น model ส่งกลับมาหน้าบ้านคูลๆใช่มั้ยครับ ทีนี้ถ้าข้อมูลมันอยู่คนละถัง เราจะไม่สามารถทำได้ละ เช่น มีถัง customer service กับถัง order service แยกกัน สิ่งที่เราทำได้คือเราจะดึง customer มาก่อน แล้วค่อยยิงไปหาว่า customer นี้มี order อะไรบ้างจาก order service ซึ่งท่านี้เราเรียกว่า API Composition ครับ เป็นการทำ in-memory join แทนที่จะ join มาจาก database เลย

จริงๆ API Composition ไม่ใช่เรื่องใหม่ เราใช้กันมาตั้งแต่ยุคที่ front end เป็นคนเรียกแต่ละ api มาแสดงผล เพียงแต่เดี๋ยวนี้เค้านิยมทำ backend for frontend มาเป็นอีก layer นึงเพื่อให้ frontend (ซึ่งเดี๋ยวนี้มีทั้ง web, mobile, tv, smartdevice) ใช้ได้เป็นระเบียบ และจัดการอะไรหลายๆอย่างในที่เดียว (เช่น authen)

Tool นึงที่ผมชอบมากสำหรับการทำ API Composition คือ GraphQL ครับ มันออกแบบมาให้มี resolver เพื่อไปดึงข้อมูลเพิ่มจาก service อื่น (ถ้าต้องการใช้ ถ้าไม่ใช้ก็ไม่ดึง) และมีการทำ batching เพื่อรองรับการดึงพร้อมกันหลายๆ (เช่น มี 10 customer แล้วเราอยากดึง order ของทั้ง 10 customer เราสามารถทำได้ใน request เดียว แล้วเดี๋ยวมันมาแมพ order เข้าแต่ละ customer ให้ครับ)

อย่างไรก็ตาม กลับมาที่ตัวอย่างเมื่อกี้ ความฉิบหายจะบังเกิดหาก order service ไม่สามารถจบได้ด้วยตัวเองอีก เช่นใน order ดันมีข้อมูลที่ต้องไปดึงจาก service อื่นต่อ ซึ่งจะเห็นได้ว่ามีผลกระทบหลายๆอย่าง เช่นเปลือง mem เปลือง bandwidth มันก็เลยมีอีกท่านึงมาเรียก CQRS (command query responsibility segregation) ครับ

อธิบายง่ายๆคือ ถ้า query ไหนมันหนัก ก็ทำ service มาอีกอันนึงเพื่อ serve query นั้นโดยเฉพาะไปเลย เช่น ถ้าเราพบว่าไอ query customer+order เนี่ย มันถูกเรียกใช้เยอะและหนัก ตอนเรา write customer + order เนี่ย ก็ให้เรา publish message แล้วสร้างอีก service นึง (สมมติชื่อ customer order service) มา consume message พวกนี้ แล้วสร้าง view มารอไว้เลย ทีนี้เวลาเราจะ query customer + order ก็มี query ที่ service นี้ แทนที่จะไปยิงทีละ service ครับ เป็น workaround ท่านึงสำหรับกรณีแบ่ง service ไม่ดีด้วยนะ :D

4. ความยุ่งยากของการ Write (SAGA Choreography / Orchestration)

กรณีที่ transaction นึงมันต้อง แตกไปหลาย service แล้วมันต้องลงพร้อมกัน (เช่น ซื้อของ ตัดบัตรเครดิต ลดของในคลัง) ถ้าในกรณี monolith เราคุมมันได้ด้วย transaction ใช่มั้ยครับ ถ้าอันไหนพังก็ rollback transaction ทีนี้พอมันอยู่คนละ service เราจะ rollback ยากขึ้นละ

ท่านึงที่เค้าใช้กันเรียกว่า SAGA ครับ ซึ่งแบ่งออกเป็น choreography กับ orchestration

Choreography คือเวลาเรา design แต่ละ action/journey เนี่ย เราต้องลิส service ผู้เกี่ยวข้องมา โดยที่แต่ละ service ต้องเขียน logic รองรับทั้ง fail case และ success case ของ service ที่เป็นผู้ร่วมชะตากรรมของ journey นั้น ท่านี้เหมาะสำหรับสายที่ไม่ยาวมาก และระบบที่ journey ไม่เยอะมาก ข้อเสียของมันคือถ้าระบบมันมี journey เยอะๆ คนมาดูทีหลังจะงงครับว่า จะจบ journey นี้ได้ มันมี message อะไรบ้าง service ไหนบ้าง

Orchestration คือแทนที่เราจะให้แต่ละ service เป็นคนคุยกันเอง เราจะสร้าง orchestrator มาตัวนึง สำหรับ journey / saga นั้นให้เป็นศูนย์กลางการส่งข้อความระหว่าง service ท่านี้ข้อดีคือจะเป็นระเบียบกว่า

เดี๋ยวมีเวลา จะมาลอง implement saga กันครับ

5. Communication & Message Design

เมื่อเราไปทาง Microservice แล้ว ดีไซน์ API อย่างเดียวไม่พอแล้วครับ เราต้องดีไซน์ตัว message ด้วย รวมถึงต้องตัดสินใจว่า journey ไหนควรเป็น API (ต้องการ response ทันที) อันไหนเป็น consume event เอา การ configuration ต่างๆที่เพิ่มขึ้น ซึ่งถ้าตรงนี้ไม่มีระเบียบการจัดการที่ดี จะทำให้ระบบมันซับซ้อนขึ้นครับ

6. DevOps / automation

key นึงที่สำคัญสำหรับการทำ microservice คือการทำ automation ครับ ทั้ง tools พวก generator (ซึ่งก็จะไปโดนเรื่อง standard), autotest, autodeploy, scaling, infra, monitoring & alert ซึ่งถ้า DevOps ไม่แข็ง Infra ไม่พร้อม เราจะเจอปัญหาแน่ๆในการ deliver งานครับ สำหรับ บ เล็กๆที่ช่วงแรกอาจจะโฟกัสเรื่อง business requirement ให้รองรับตลาด อาจจะต้องแบ่งกำลังมาลงทุนเรื่องพวกนี้ด้วย ก่อนที่จะไป microservice กันครับ

7. Team mindset

สุดท้ายที่อยากพูดถึงคือเรื่องของคนครับ จะเห็นได้ว่าแค่เรื่อง read / write ก็สนุกแล้วสำหรับการทำ microservice อีกปัจจัยนึงที่เราต้องคำนึงคือความพร้อมของทีมครับ คือทีมพร้อมหรือยังสำหรับ การเขียนโค้ดแบบใหม่นี้ ในช่วงแรกจะมีแรงต้านเสมอๆครับ (ซึ่งก็ make sense ดูจากความยุ่งยาก) ต้องอาศัยกำลังภายในของ techlead ในการตัดสินว่าคุ้มหรือไม่ การ educate และ drive team ให้ adopt change นี้ และก้าวไปด้วยกันครับ (หล่อมาก)

จะเห็นได้ว่าการแตกไป microservice มีความยุ่งยากกว่าเดิมประมาณ 230% ซึ่งผู้ลงทุนควรใช้วิจารญาณก่อนตัดสินใจ ถึงความจำเป็นและความพร้อมก่อนตัดสินใจลงทุนครับ

--

--