- Monzo ได้รับคุณค่ามากมายจากการรันบริการมากกว่า 2,800 รายการด้วยสถาปัตยกรรม MSA
- แต่สถาปัตยกรรมลักษณะนี้ก็มาพร้อมความยากเช่นกัน หนึ่งในนั้นคือการเปลี่ยนแปลงไลบรารีในทุกบริการ
- โดยทั่วไปแล้ว คุณต้องเลือก 2 จาก 3 อย่างระหว่างไลบรารีที่ทันสมัย เวอร์ชันไลบรารีที่สอดคล้องกัน และความพยายามในการอัปเกรดที่ต่ำ
กลยุทธ์การย้ายแบบรวมศูนย์
- ที่ Monzo เชื่อว่าแนวทางการย้ายที่ขับเคลื่อนแบบรวมศูนย์สามารถทำให้บรรลุคุณสมบัติทั้งสามข้างต้นได้ในระดับสูง
- แทนที่จะผลักภาระการย้ายไปให้เจ้าของบริการ Monzo เลือกให้ทีมเดียวเป็นผู้ขับเคลื่อนการย้าย
- วิธีนี้ช่วยหลีกเลี่ยงภาระด้านการประสานงานที่สูง (ซึ่งนำไปสู่การย้ายที่ช้า) และความเสี่ยงที่โครงการจะหยุดชะงัก (ซึ่งนำไปสู่ความไม่สอดคล้องกัน)
- เพื่อให้ทีมเดียวสามารถทำการย้ายให้เสร็จได้ภายในเวลาที่เหมาะสม Monzo พึ่งพาสิ่งต่อไปนี้อย่างมาก:
- การเลือกเทคโนโลยีหลัก (เช่น ความสอดคล้องในระดับสูง, การใช้ monorepo)
- การใช้ระบบอัตโนมัติในวงกว้าง (เช่น เครื่องมือดีพลอยบริการจำนวนมาก, การตรวจสอบ rollback อัตโนมัติ)
การย้ายจาก OpenTracing SDK ไปยัง OpenTelemetry SDK
- Monzo เพิ่งนำกลยุทธ์นี้มาใช้จริงผ่านโครงการเปลี่ยนจาก OpenTracing SDK ไปเป็น OpenTelemetry SDK
- ทุกบริการจะส่งออกข้อมูล tracing ไปยัง Jaeger ก่อนหน้านี้ทำผ่าน OpenTracing และ Jaeger Go SDK
- ตอนนี้ไลบรารีเหล่านี้เลิกใช้งานแล้ว และชุมชนได้รวมไปที่ OpenTelemetry แทน
- เพื่อวางรากฐานสำหรับการปรับปรุงระบบ tracing ก่อนอื่น Monzo ต้องการแทนที่ไลบรารีที่เลิกใช้แล้วด้วย OpenTelemetry SDK
หลักการของการย้าย
- การย้ายแบบรวมศูนย์ที่โปร่งใสต่อเจ้าของบริการ Monzo เลือกใช้กลยุทธ์ที่ทีมเดียวสามารถทำแบบรวมศูนย์ได้ เพื่อลดภาระการประสานงานและลดความเสี่ยงที่การย้ายจะหยุดกลางคัน
- ไม่มี downtime การย้ายส่วนใหญ่เกี่ยวข้องกับบริการที่สำคัญต่อฟังก์ชันหลักของธนาคาร จึงไม่สามารถยอมรับ downtime ได้
- roll forward แบบค่อยเป็นค่อยไป และ rollback ได้รวดเร็ว สำหรับการเปลี่ยนแปลงขนาดใหญ่ ต้องสามารถ roll forward แบบค่อยเป็นค่อยไปเพื่อลด blast radius เมื่อเกิดปัญหา แต่ในขณะเดียวกันก็ต้อง rollback ได้อย่างรวดเร็วหากจำเป็น
- กฎ 80/20 สำหรับระบบอัตโนมัติ ในการย้ายขนาดใหญ่ โดยทั่วไปสัดส่วนสูงของการเปลี่ยนแปลงจะเข้ากับเทมเพลตร่วม ซึ่งสามารถทำให้เป็นอัตโนมัติได้ง่าย ส่วนกรณีใช้งานที่เฉพาะตัวกว่านั้น การทำอัตโนมัติจะให้ผลตอบแทนที่ลดลง และมักมีประสิทธิภาพกว่าหากจัดการเป็นกรณีไป เพื่อหลีกเลี่ยงเรื่องไม่คาดคิดและให้ติดตามความคืบหน้าได้ง่าย ควรจัดหมวดหมู่การเปลี่ยนแปลงที่จำเป็นล่วงหน้าเป็นสองกลุ่มนี้
กลยุทธ์การย้าย
- ที่ Monzo มีชุดขั้นตอนการย้ายที่ใช้อย่างเป็นระบบ
1. การวางแผนและการทำให้สอดคล้องกัน
- การย้ายมีความเสี่ยงไม่น้อย ไม่เพียงส่งผลต่อบริการจำนวนมาก แต่ทีมที่ดำเนินการย้ายอาจไม่มีบริบทมากนัก หรืออาจไม่มีเลย เกี่ยวกับบริการที่กำลังย้าย
- แม้จะมุ่งสู่ความสอดคล้องของบริการ แต่ก็มีข้อยกเว้นเสมอ และ Monzo ต้องการจับความประหลาดใจเหล่านี้ให้ได้เร็วที่สุด
- ดังนั้นจึงสำคัญมากที่กระบวนการวางแผนจะต้องโปร่งใส และวิศวกรทุกคนมีโอกาสมีส่วนร่วม
- สำหรับสิ่งนี้ Monzo มีกระบวนการอยู่สองแบบ:
- ข้อเสนอ: Monzo เขียนสิ่งนี้บ่อยมาก แทบทุกอย่างที่มีสาระสำคัญสุดท้ายจะถูกแชร์ในช่อง Slack เดียวที่ทุกคนในบริษัทสามารถแสดงความคิดเห็นได้
- การทบทวนสถาปัตยกรรม: สำหรับการเปลี่ยนแปลงที่ใหญ่ที่สุด จะมีการประชุมทบทวนสถาปัตยกรรมแบบ synchronous เพื่อเจาะลึกบางประเด็นที่มีข้อถกเถียงมากกว่าหรือมีความเสี่ยงมากกว่า เป้าหมายไม่ใช่เพื่อขออนุมัติหรือลายเซ็น แต่เพื่อผลักดันสถานะของการออกแบบให้ก้าวหน้าอย่างมีนัยสำคัญและเร่งโครงการ
2. ครอบไลบรารีเดิม
-
แทนที่จะติดตั้งไลบรารีใหม่และอัปเดตโค้ดของบริการให้เรียกใช้ Monzo ตัดสินใจครอบไลบรารีเดิมก่อน
- สามารถดักการเรียกไปยังไลบรารีพื้นฐานและตัดสินใจได้จากการกำหนดค่าแบบไดนามิกว่าจะใช้ implementation ใด ซึ่งทำให้ roll forward และ rollback ได้ง่ายโดยไม่ต้องดีพลอยทุกบริการใหม่
- ไลบรารีใหม่มีชนิดข้อมูล/ฟังก์ชันที่แตกต่างอย่างมาก การอัปเดตทุก call site ต้องใช้ความพยายามมาก และในบางกรณีประโยชน์จาก API ใหม่ก็มีน้อย การครอบไลบรารีเดิมช่วยให้ในกรณีเหล่านี้ยังคงอินเทอร์เฟซที่คล้ายของเดิมไว้ ทำให้อัปเดต call site ได้ง่ายขึ้น
-
ประโยชน์อื่นของการครอบไลบรารี:
- สามารถ instrument ด้วยไลบรารี telemetry ของตัวเองได้
- สามารถให้อินเทอร์เฟซที่ชัดเจนและกำหนดทิศทางมากขึ้นได้
3. อัปเดต call site
-
การใช้งานไลบรารีนี้เข้ากับแพตเทิร์นร่วม:
- มีฟังก์ชัน/ชนิดข้อมูลจำนวนไม่มากที่ถูกอ้างอิงหลายครั้งทั่วทั้งโค้ดเบส
- จากนั้นจะมีหางยาวของฟังก์ชัน/ชนิดข้อมูลที่ถูกอ้างอิงเพียงไม่กี่แห่ง
-
Monzo จัดการแต่ละกรณีแตกต่างกัน:
- สำหรับฟังก์ชัน/ชนิดข้อมูลส่วนน้อยที่ถูกอ้างอิงในหลายที่ จะทำให้เป็นอัตโนมัติให้มากที่สุด สำหรับไลบรารีนี้ Monzo พึ่งพา
goplsและgorenameเป็นหลักเพื่อทำ automated refactoring - สำหรับหางยาวของฟังก์ชัน/ชนิดข้อมูลที่ถูกอ้างอิงเพียงไม่กี่แห่ง จะใช้แนวทางแบบ manual เป็นรายกรณี บางกรณีทำการย้ายด้วยมือ ในกรณีอื่นพบว่าสามารถทำสิ่งเดียวกันได้ด้วย API ที่มีอยู่เดิมมากกว่า จึงเปลี่ยนไปใช้ทางนั้น ซึ่งหมายความว่าไม่จำเป็นต้องรองรับเป็นกรณีพิเศษอีกต่อไป และยังมีข้อดีเพิ่มเติมคือช่วยให้ API ของไลบรารี wrapper มีขนาดเล็กและชัดเจน
- สำหรับฟังก์ชัน/ชนิดข้อมูลส่วนน้อยที่ถูกอ้างอิงในหลายที่ จะทำให้เป็นอัตโนมัติให้มากที่สุด สำหรับไลบรารีนี้ Monzo พึ่งพา
-
นอกจากการครอบไลบรารีเดิมแล้ว Monzo ยังบล็อกไม่ให้เกิด dependency ใหม่กับไลบรารีเดิม โดยทำผ่านการเพิ่มการตรวจสอบใน CI ด้วย semgrep
4. ครอบไลบรารีใหม่
- เมื่อครอบไลบรารีเดิมแล้ว ก็สามารถเริ่มเพิ่มไลบรารีใหม่ไว้หลังไลบรารี wrapper ได้
- ในช่วงแรก implementation ใหม่จะถูกปิดไว้ผ่านการกำหนดค่า ซึ่งหมายความว่าไม่คาดว่าจะมีการเปลี่ยนแปลงพฤติกรรม และยังสามารถทยอย merge การเปลี่ยนแปลงเข้ากับ master branch ต่อไปได้
5. ดีพลอยบริการจำนวนมาก
- ก่อนเริ่มเปิดใช้ implementation ใหม่ ต้องมั่นใจก่อนว่าทุกบริการที่กำลังรันอยู่รองรับ implementation ใหม่นี้ได้
- สำหรับการเปลี่ยนแปลงไลบรารีประเภทอื่น อาจดีพลอยเพียงบางส่วนของบริการที่มีฟีเจอร์ใหม่ได้ในแต่ละครั้ง แต่สำหรับไลบรารี tracing หากมีบริการที่ถูกย้ายไปใช้ไลบรารีใหม่แล้ว บริการทั้งหมดที่มันอาจเรียกหาได้ในช่วงเปลี่ยนผ่านก็ต้องรองรับฟีเจอร์ใหม่นี้ด้วย
- เพื่อจัดการการดีพลอยบริการจำนวนมาก Monzo ได้สร้างเครื่องมือดีพลอยแบบจำนวนมากที่สามารถ push การเปลี่ยนแปลงไลบรารีไปยังทุกบริการได้ด้วยงาน batch แบบ asynchronous
- เพื่อลดผลกระทบจากการดีพลอยที่อาจผิดพลาด:
- ใช้การตรวจสอบ rollback อัตโนมัติ
- ดีพลอยบริการที่มีความสำคัญน้อยที่สุดก่อน ทุกบริการมีแท็ก "tier" และเครื่องมือดีพลอยแบบจำนวนมากจะใช้สิ่งนี้เพื่อจัดลำดับความสำคัญให้กับการดีพลอยที่มีความเสี่ยงต่ำที่สุด
6. ควบคุม rollout ผ่านการกำหนดค่า
- ปัญหาของเครื่องมือดีพลอยแบบจำนวนมากคือค่อนข้างช้า สิ่งที่ Monzo อยากหลีกเลี่ยงที่สุดคือการดีพลอยทุกบริการไปแล้ว แต่กลับพบว่าไลบรารีใหม่มีปัญหาและไม่สามารถ rollback ได้อย่างรวดเร็ว
- ดังนั้นแทนที่จะดีพลอยพร้อมเปิดใช้ implementation ใหม่ Monzo จึงดีพลอยความสามารถในการเปิดใช้ implementation ใหม่ผ่านระบบการกำหนดค่า
- เมื่อเทียบกับการดีพลอยตามปกติ ข้อดีของการใช้ระบบการกำหนดค่าคือความเร็ว ทุกบริการจะรีเฟรชการกำหนดค่าทุก 60 วินาที ดังนั้นหากจำเป็นก็สามารถ rollback ได้อย่างรวดเร็ว
- นอกจากนี้ยังให้การควบคุมมากขึ้นมากเกี่ยวกับช่วงเวลาที่ implementation ใหม่ถูกใช้งาน เช่น เปิดใช้เฉพาะกับชุดผู้ใช้บางกลุ่ม หรือกับเปอร์เซ็นต์แบบสุ่มของคำขอเท่านั้น
- ในกรณีนี้ Monzo เลือก rollout เฉพาะกับ API endpoint ที่ทีมเป็นเจ้าของ และเปิดใช้ตามความน่าจะเป็นที่เพิ่มขึ้นทีละน้อย
7. เก็บงานให้เรียบร้อย
- เมื่อเปลี่ยนไปใช้ implementation ใหม่ทั้งหมดแล้ว ก็ถึงเวลาของงานที่น่าพอใจคือการลบ implementation เดิมออกจากไลบรารี wrapper
พลังพิเศษของการย้ายระบบ
- การย้ายแบบรวมศูนย์ลักษณะนี้เป็นไปได้ที่ Monzo เพราะการตัดสินใจเชิงเทคนิคพื้นฐานและเครื่องมือที่ลงทุนพัฒนาอย่างต่อเนื่อง
- เทคโนโลยีที่สอดคล้องกัน: ทุกบริการเขียนด้วย Go และใช้เวอร์ชันเดียวกันของไลบรารีเดิม สิ่งนี้ทำให้การทำให้การเปลี่ยนแปลงเป็นอัตโนมัติง่ายขึ้นมาก ตัวอย่างเช่น ใช้เครื่องมือรีแฟกเตอร์เพียงตัวเดียวแทนที่จะต้องมีแยกตามภาษา
- Monorepo: โค้ดของทุกบริการอยู่ใน monorepo เดียว ทำให้การรีแฟกเตอร์ขนาดใหญ่ทำได้ง่ายกว่ามากในคอมมิตเดียว และยังช่วยให้บังคับใช้การตรวจสอบใน CI กับการใช้ไลบรารีบางตัวได้ทั่วทั้งระบบ ช่วยรักษาความสอดคล้อง
- การดีพลอยแบบจำนวนมาก: เมื่อมีองค์ประกอบที่ดีพลอยได้จำนวนมาก ก็จำเป็นต้องมีกระบวนการดีพลอยอัตโนมัติเพื่อ push การเปลี่ยนแปลงไลบรารี
- บริการกำหนดค่าที่เบาและยืดหยุ่น: กระบวนการดีพลอยปลอดภัยแต่ช้า (ใช้เวลาหลายนาทีต่อการดีพลอย) จึงต้องมีกระบวนการที่เบาและยืดหยุ่นกว่าสำหรับเปิด/ปิดฟีเจอร์ใหม่อย่างรวดเร็วและทันทีในบริการจำนวนมาก
บทสรุป
- ในอดีต Monzo เคยพยายามกระจายการย้ายออกไป แต่สิ่งนี้นำไปสู่การย้ายที่ไม่เสร็จสมบูรณ์และต้องใช้ความพยายามในการประสานงานจำนวนมากอย่างหลีกเลี่ยงไม่ได้
- นี่จึงเป็นเหตุผลที่ Monzo ชอบการย้ายแบบรวมศูนย์อย่างมาก แม้ว่าทีมเดียวจะต้องแบกรับต้นทุนค่อนข้างสูง แต่โดยรวมใช้ความพยายามน้อยกว่าและมีโอกาสสูงกว่ามากที่จะรักษาความสอดคล้องได้
- แนวทางนี้สร้างวงจรเชิงบวก:
- ทีมที่ดำเนินการย้ายมีแรงจูงใจอย่างมากในการลงทุนกับเครื่องมือเพื่อทำให้การย้ายเป็นอัตโนมัติ
- และยังช่วยรักษาความสอดคล้องทางเทคนิคไว้ด้วย (ซึ่งทำให้การสร้างเครื่องมือง่ายขึ้น)
- แต่ก็ยังคงปฏิบัติจริงต่อระดับของระบบอัตโนมัติ โดยใช้กฎ 80/20
- นอกเหนือจากเครื่องมือที่ Monzo ยังคงลงทุนแล้ว แนวทางนี้ยังเป็นไปได้เพราะการตัดสินใจเชิงเทคนิคหลักบางอย่างที่ทำไว้ตั้งแต่ต้น
- โดยหลักคือการใช้ชุดเทคโนโลยีที่มีทิศทางชัดเจนและจำกัด
ยังไม่มีความคิดเห็น