The Twelve-Factor App ในการทำ Microservices

Sakul Montha
4 min readFeb 10, 2021

--

ปัจจุบันเรามักจะได้ยินคนกล่าวถึงคำว่า Microservices กันมากขึ้นเรื่อย ๆ ไม่ว่าจะได้ยินมาจากเหล่า Start up จากเพื่อน หรือ จากองค์กรขนาดใหญ่ก็ตาม ซึ่งมันก็เป็นโอกาสที่ดี ที่ไม่ว่าคุณจะทำงานอยู่ที่ไหนก็ตามแล้วได้มีโอกาสได้ทำ Microservices แต่มันก็จะตามมาด้วยปัญหาที่ว่า แล้วเราจะออกแบบ แนวทาง Microservices ของเราอย่างไรให้มันออกมา “ดี” ได้หละ เรามักจะพบว่ามีหลักการมากมาย ในการเขียนโปรแกรมเชิงวัตถุ เช่น การใช้ SOLID หรือ GRASP หรือ พวกการออกแบบ SOA

จนกระทั่ง ผมมาเจอ The Twelve Factors ที่เราจะสามารถนำมา Apply เข้ากับ สถาปัตยกรรม Microservice ของเราได้ จากรุ่นพี่ท่านนึงผู้ไม่ขอออกนาม ซึ่งท่านผู้อ่าน สามารถไปอ่าน Official ได้จาก ที่นี่ หรือ ถ้าขี้เกียจ มาดูที่ผมสรุปเอาไว้ก็ได้

The Twelve Factors

The Twelve Factors เขียนโดย คุณ Adam Wiggins ผู้ก่อตั้ง Heroku ซึ่งให้แปลตาม พจนานุกรม แปลว่า “12 ปัจจัย” ซึ่งนั่นก็เป็นที่มาครับ ว่ามันมีอยู่ด้วยกัน 12 หลักการ โดย The Twelve-factor app เป็น Methodology สำหรับสร้าง software-as-a-service และ มันสามารถนำมา Applied ในการช่วยสร้าง สถาปัตยกรรม Microservice ได้

1. Codebase

Codebase ใน Revision control ไม่ว่าคุณจะใช้ Git หรือ Mercurial หรือ Subversion คุณควรจะใช้ Codebase เดียวกัน Repo เดียวกัน หรือหนึ่ง Microservice หนึ่ง Repo และหนึ่ง Codebase ควรที่จะสามารถ Deploy ได้ตั้งแต่ Non-prod ไปจนถึง Prod.

2. Dependencies

ในการเขียนโปรแกรมส่วนใหญ่ ก็มักจะมี Package สำหรับการดึง Library ต่าง ๆ มาใช้ หรือ ก็คือพวก Library package manager เช่น CPAN สำหรับ Perl, Rubygems สำหรับ Ruby หรือ pip ใน python นั่นเอง เราควรระบุ Dependencies ให้ชัดเจนว่าเราจะใช้ Package อะไร version ไหนเพื่อป้องกันความผิดพลาดไปในตัวด้วย (อันนี้ผมว่าทุกคนทำกันอยู่แล้วแหละ ไม่งั้นก็ต้องมานั่งหาเองลงเองทุกอย่าง ซึ่งปัจจุบันคงไม่มีใครทำกันแล้วมั้ง)

3. Config

Config เป็นอะไรที่สำคัญมาก ๆ อย่างนึง ซึ่งค่าที่อยู่ใน config มักจะแตกต่างกันตามแต่ละ Environment ซึ่งเราควรเก็บค่า config แยกไว้ในแต่ละ Environment ซึ่งทั้งนี้ จะเก็บค่า config ไว้ที่ไหน ก็ขึ้นอยู่กับ แต่ละ service และ การใช้งาน

4. Backing services

ข้อนี้จะบอกว่า อะไรก็ตามที่เราไปเรียกใช้ เช่น datastore, queue, smtp หรือ caching ต่าง ๆ ก็ตาม เมื่อมันได้ตาย หรือจากไป มันจะต้องสามารถนำมาเสียบแทนที่ได้ โดยที่ระบบของเรายังคงต้องรันได้ และ ต้องไม่มีการแก้ไข Code ใด ๆ

Backing Service

5. Build, Release and Run

ในส่วนนี้ เขาได้แบ่งออกเป็น 3 หัวข้อย่อยในการ Deploy ออกมา

Build state: ส่วนนี้จะเป็นส่วนของการ build โปรแกรมที่เราได้เขียนออกมาจาก Source code ที่เราได้ทำการ Commit ขึ้นมา นำมาทำการ Deployment

Release stage: ขั้นตอนการ Release จะสร้างขึ้นกับจากการ Build stage และ รวมเข้ากันกับตัว config ตาม Environment ของเรา

Run stage: เป็นส่วนของ Runtime ซึ่งจะเรียกใช้ Application ที่เราทำการ Release ใน Environment และ Version ที่เรากำหนด

Build, Release and Run

6. Process

Execute the app as one or more stateless processes
ในแนวคิดของ Twelve Factors เขาแนะนำให้การทำงานของแต่ละ Process ให้ทำงานเป็นแบบ Stateless Process ไม่ควรเก็บข้อมูลต่าง ๆ เช่น เก็บ Session เอาไว้ที่ Server ที่ User เข้ามาเนื่องจากการเข้ามาของ User ในครั้งต่อ ๆ ไปอาจจะไม่ได้เข้ามาที่เครื่องเดิมก็ได้ ถ้าจะยกตัวอย่างให้เห็นภาพง่าย ๆ ก็จะเป็น การที่ Service A จะต้องต่อเข้าไปที่ Service B ถ้าเราเก็บ Session ของลูกค้าไว้ที่ Service A พอลูกค้าเข้ามาอีกครั้ง ก็จะยังทำงานได้ตามปกติ แต่ทว่า ถ้าหาก Service ของเรามีหลาย ๆ Container หละ เราก็จะมีการทำ Load Balance ถ้าครั้งแรกลูกค้าเข้ามา Service A1 -> Service B1 ยังทำงานได้ตามปกติ แต่ถ้าครั้งต่อไป Load Balance ให้วิ่งไป Service A2 เมื่อนั้น หายนะจะเกิด เนื่องจากเราดันไปเก็บ Session เอาไว้ที่ Service A1 ประมาณนี้

ดังนั้นเมื่อมีความจำเป็นจะต้องการเก็บข้อมูลใด ๆ ก็ควรที่จะเก็บเอาไว้ใน Backing service แทนเช่น การเก็บข้อมูลเอาไว้ใน Redis แล้วให้ Service ของเรามาเรียกเอาไปใช้ เป็นต้น

7. Port binding

Export services via port binding
ใน Twelve Factors จะมองว่าเป็น Self-contained และไม่อาศัย Runtime ของ Webserver ไม่ต้องสนใจว่าปลายทางจะเป็น IP Address อะไร (เนื่องจากในโลกของ Container มีการเกิดขึ้น ตั้งอยู่ และดับไปเสมอ) รู้แค่ว่าถ้าอยู่ในวงเดียวกัน แต่เรียกด้วย Port นี้ จะเป็น Service นี้เสมอ

8. Concurrency

Scale out via the process model
จากข้อที่ 6 เราได้เห็นการทำงาน Stateless Process เมื่อส่วนไหนที่มีการไหล หรือการใช้ทรัพยากรเยอะก็สามารถที่จะ Scale out ได้ หลักการมันก็จะคล้าย ๆ การทำงานของ Microservice ที่เราคุ้นเคยกันโดยแบ่ง Service ต่าง ๆ ออกจากกัน

ท่านสามารถอ่านต่อในเรื่องของ Scale up — Scale out ต่อได้ที่นี่

https://12factor.net/concurrency

9. Disposability

Maximize robustness with fast startup and graceful shutdown
เค้าแนะนำให้ Application ควรที่จะ Fast startup และเมื่อมีความต้องการที่จะ Stop service ก็ควรที่จะทำ Graceful shutdown เอาง่าย ๆ เลยก็คือ เริ่มดี จบสวยอะครับ

บางท่านอาจจะยังไม่รู้จักว่า Graceful shutdown เป็นอย่างไร ผมขอเล่าสั้น ๆ ก็คือ เมื่อเราทำการ Shutdown service ใด ๆ สัก Service นึง โดยปกติ ถ้าเกิดเราไม่ทำ Graceful shutdown สิ่งที่เกิดขึ้นคือ ไม่ว่าอะไรที่ค้างอยู่ก็ตาม มันจะไม่ได้รับ Response และการทำงานบางอย่าง มันอาจจะไปสะดุด เช่น Request นี้มีการ Update database และทำการ Update เรียบร้อยแล้ว แต่ผู้ Request ไม่ได้รับ Response กลับไป เนื่องจาก Service ได้ทำการปิดตัวลง จึงอาจจะทำให้เกิดการ Request เข้ามาใหม่ ทำให้มีโอกาสเกิด Transaction ซ้ำซ้อนขึ้นมาได้ แต่ถ้าหากเรามีการทำ Graceful shutdown เมื่อเราทำการ Shutdown service มันจะปิดกั้นการเข้าถึง แต่ Thread ใด ๆ ที่อยู่ภายใน Service ที่ยังทำงานไม่เสร็จ จะทำงานจนกว่าจะเสร็จ จากนั้นถึงจะ Close จริง ที่จริงเรื่องนี้มันจะมีให้เล่ายาวกว่านี้ เอาไว้มีโอกาส ผมจะเขียนให้อ่านกันอีกครั้งครับ

ปัจจุบันพวก platform-as-a-service ยอดนิยมต่าง ๆ ก็สามารถทำได้กันหมดแล้ว

10. Dev/prod parity

Keep development, staging, and production as similar as possible
ส่วนนี้เค้าจะพูดถึงเรื่องของ Environment ให้มีความใกล้เคียงกันมากที่สุด

Twelve Factors เค้าได้แบ่งเอาไว้ 3 หัวข้อ Time, Personnel และ Tools

The time gap: ก่อนหน้านี้ต้องใช้เวลาเป็นเดือน กว่าจะเอา Application ขึ้น Prod ได้ เค้าแนะนำให้ลดช่องว่างพวกนี้ให้เหลือหลัก ชั่วโมง หรือตามแต่ใจต้องการ

The personnel gap: ก่อนหน้านี้ Developer เขียนโปรแกรมเสร็จ ก็ให้ Operation เป็นคน Deploy ให้ เค้าแนะนำให้ลดเรื่องกระบวนการเกี่ยวกับโพรเซสเหล่านี้ลงไป โดยการให้เกือบทุกอย่าง จบที่ Developer

The tools gap: ก่อนหน้านี้เหล่า Developer อาจจะใช้พวก Nginx, SQLite, and OS X แต่บน Prod ใช้ Apache มันก็จะมีความแตกต่างกันในเรื่องของ Tools เค้าแนะนำให้ Developer ใช้ Tools ที่มีความคล้ายคลึงกับบน Prod มากที่สุดเท่าที่จะเป็นไปได้
ตรงนี้การมาของ Docker ช่วยได้เยอะ

https://12factor.net/dev-prod-parity

11. Logs

Treat logs as event streams
Log เป็น Event streams ของเหตุการณ์ ตามลำดับเวลาที่รวบรวมจาก Stream output โดยที่มันจะช่วยทำให้มองเห็นลักษณะการทำงานของ Application ที่กำลังทำงานอยู่ โดยปกติมักจะเขียน Log ลงบนดิสก์ และมักจะเป็นรูปแบบข้อความที่มีหนึ่งเหตุการณ์ต่อหนึ่งบรรทัด Log จะไม่มีจุดสิ้นสุดที่ตายตัว แต่จะไหลมาอย่างต่อเนื่อง ตราบเท่าที่ Application ของเรายังทำงาน หรือยังไม่บึ้มไปนั่นเอง

ใน Twelve-factor เค้าได้แนะนำว่าให้พ่น Log ออกมาเป็น stdout แทนการบันทึกลงดิกส์ (เนื่องจากการบันทึกลงดิกส์ มันจำเป็นต้องมีการไปเปิดไฟล์ก่อน แล้วถึงจะค้นหาได้) จากนั้นค่อยนำ Tools มาเก็บต่อไป แล้วเค้าก็มีแนะนำให้ทำอีกนิดหน่อย เช่น
- การค้นหาเหตุการณ์ เฉพาะในอดีต (ใช่แหละ หาอนาคตไม่ได้หนิ แต่ทำข้อถัดไปได้)
- สร้างกราฟเพื่อดู Trends (เช่น Request per minute เพื่อนำไปวิเคราะห์)
- แจ้งเตือนตามการวิเคราะห์พฤติกรรมที่ผู้ใช้กำหนด (เช่น การแจ้งเตือนเมื่อจำนวนข้อผิดพลาดต่อนาทีเกินเกณฑ์ที่กำหนด)

ท่านสามารถอ่านเรื่อง Log Level ต่อได้ที่นี่

12. Admin process

Run admin/management tasks as one-off processes
เค้าให้แยกพวก Admin tools หรือ Server ต่าง ๆ เช่น Database migrations, Shell หรือพวก Command ออกจาก Application ของเรา แต่ถ้ามีอะไรที่มันจำเป็นต้องใช้ร่วมกัน ก็ใช้ได้ แต่เมื่อใช้เสร็จก็ควรที่จะแยก หรือลบทิ้งไป

เรื่องพวกนี้เป็นเรื่องที่สายนักพัฒนาอาจจะไม่ค่อยถูกใจนัก ที่ต้องมากังวลเรื่องนี้เพิ่มอีก แต่ที่จริงแล้วมันเป็นสิ่งที่ควรทำมากเลยนะครับ จะได้ป้องกันการที่จะมีอะไรไม่ชอบมาพากลได้ด้วยอีกแรง ถ้าเป็น บริษัทใหญ่หน่อยเค้าก็มักจะมีทีม Infrastructure ที่คอยช่วย Concern เรื่องเหล่านี้อยู่แล้ว ในการที่จะ Release ของออกไป

Conclusion

ผมเริ่ม Draft บทความนี้มาตั้งแต่ช่วงกลางปี 2018 แต่ทำไม่เสร็จสักที เนื่องจากมันเยอะฮ่า ๆ ช้ามากจนได้เห็นพี่ ๆ หลายคนเริ่มเขียนเรื่องนี้กันบ้างแล้ว ตอนนี้พอมีเวลาเลยมาขอต่อให้จบ

ก็หวังว่ามันจะพอที่จะช่วยให้การทำ Microservices ของทุกท่านมีความราบรื่นมากยิ่งขึ้นไปนะครับ

--

--

Sakul Montha
Sakul Montha

Written by Sakul Montha

Chief Product Officer, a man who’s falling in love with the galaxy.

No responses yet