เสียงของบาซาร์

เผยแพร่แล้ว: 2024-04-24

บทความเกี่ยวกับการปรับปรุงระบบเดิมให้ทันสมัยนี้เป็นส่วนหนึ่งของการเสวนาที่ฉันนำเสนอเมื่อเร็ว ๆ นี้ที่ AWS Data Summit สำหรับบริษัทซอฟต์แวร์เกี่ยวกับการสร้างมูลค่าจากข้อมูลโดยใช้ประโยชน์จากแนวทางปฏิบัติที่ดีที่สุดของเราเพื่อรับประกันความสำเร็จในโครงการ Machine Learning คุณสามารถกระโดดลงไปด้านล่างเพื่อดูได้หากต้องการ


ยอมรับเถอะว่าซอฟต์แวร์เขียนได้ง่ายกว่าการบำรุงรักษา นี่คือเหตุผลว่าทำไมเราในฐานะวิศวกรซอฟต์แวร์ถึงชอบที่จะ "ฉีกมันออกแล้วเริ่มต้นใหม่" แทนที่จะพยายามทำความเข้าใจว่านักพัฒนาคนอื่น (หรือตัวเราในอดีต) กำลังคิดอะไรอยู่ ดูเหมือนว่าเราจะลืมไปแล้วว่า “ต้องเขียนโปรแกรมเพื่อให้คนอ่าน และบังเอิญเท่านั้นที่เครื่องจะทำงาน”

คุณรู้ว่ามันเป็นความจริง เราทุกคนต่างต้องพยายามติดตามหม้อปรุงอาหารที่มีรหัสสปาเก็ตตี้และภาพนามธรรมสไตล์โลกเก่าบางๆ ที่ขุดหาเนื้อของโปรแกรมเพียงเพื่อจะไม่พบอะไรเลยนอกจากความยุ่งเหยิงที่ด้านล่างของจานของเรา

มันง่ายที่จะตะโกนว่า “WTF” และตำหนิผู้พัฒนาคนก่อนๆ แต่ความจริงมักจะซับซ้อนกว่า เราไม่สามารถมองเห็นอนาคตได้ ดังนั้นจึงเป็นไปไม่ได้ที่จะเข้าใจว่าความต้องการ เทคโนโลยี หรือเป้าหมายทางธุรกิจจะเติบโตอย่างไรเมื่อเราออกแบบระบบใหม่ เป็นผลให้ระบบไม่สามารถอ่านได้เนื่องจากขอบเขตเพิ่มขึ้นพร้อมกับการพึ่งพาของธุรกิจ นี่เป็นความขัดแย้งเล็กน้อย: ระบบที่เก่ากว่าและบำรุงรักษายากมักจะให้คุณค่าสูงสุด พวกเขาทำงานหนักเพราะพวกเขาเติบโตไปพร้อมกับบริษัท และน่ากลัวที่จะทำงานต่อไปเพราะการทำลายมันอาจเป็นหายนะ

ฉันจะโทรหาคุณที่นี่: หากคุณชอบปัญหาที่ยากและคุ้มค่า… ลองดูสิ ใช้ระบบที่เก่าแก่ที่สุดที่คุณมีและทำให้สามารถบำรุงรักษาได้ คุณรู้จักคนที่ฉันกำลังพูดถึง — คนที่ไม่มีใคร "เป็นเจ้าของ" ได้ สิ่งหนึ่งที่แผนกอื่นๆ พึ่งพาแต่วิศวกรเกลียด อันที่คุณต้องแก้ไข Log4Shell ก่อน ทำมัน. ฉันท้าคุณ.

เมื่อเร็วๆ นี้ ฉันมีโอกาสอัปเดตระบบการเรียนรู้ของเครื่องที่มีอายุร่วมทศวรรษที่ Bazaarvoice ดูเผินๆ ฟังดูไม่ น่าตื่นเต้นเลย เพราะสิ่งนี้ไม่มีโครงข่ายประสาทด้วยซ้ำ! ใครสน! ก็…มันสำคัญ ระบบนี้ประมวลผลเกือบทุกรีวิวผลิตภัณฑ์ที่ผู้ใช้สร้างขึ้นซึ่ง Bazaarvoice ได้รับ — เกือบ 9 ล้านรายการต่อเดือน — และดำเนินการดังกล่าวด้วยการเรียกโมเดลการเรียนรู้ของเครื่องจักรถึง 90 ล้านครั้ง ใช่แล้ว — 90 ล้านการอนุมาน! มันมีขนาดใหญ่มาก และฉันแทบรอไม่ไหวที่จะเข้าไปดำดิ่งลงไป

ในโพสต์นี้ ผมจะแชร์ว่าการปรับปรุงระบบเดิมให้ทันสมัยด้วยสถาปัตยกรรมใหม่ แทนที่จะเขียนใหม่ ช่วยให้เราสามารถปรับขนาดได้และคุ้มต้นทุนโดยไม่ต้องฉีกโค้ดทั้งหมดแล้วเริ่มต้นใหม่ ผลลัพธ์ที่ได้คือระบบไร้เซิร์ฟเวอร์ มีคอนเทนเนอร์ และสามารถบำรุงรักษาได้ พร้อมทั้งลดต้นทุนการโฮสต์ของเราลงเกือบ 80%

ระบบเดิมคืออะไร?

ระบบเดิมหมายถึงซอฟต์แวร์คอมพิวเตอร์และ/หรือฮาร์ดแวร์ที่ล้าสมัยซึ่งยังคงใช้งานอยู่ แม้ว่าจะยังคงบรรลุวัตถุประสงค์เดิม แต่ก็ยังขาดความสามารถในการขยายขนาดสำหรับการเติบโตในอนาคต

ระบบมรดกเก่า

ก่อนอื่น เรามาดูกันว่าเรากำลังเผชิญกับอะไรที่นี่ ระบบเดิมที่ทีมของฉันกำลังอัปเดตจะกลั่นกรองเนื้อหาที่ผู้ใช้สร้างขึ้นสำหรับ Bazaarvoice ทั้งหมด โดยเฉพาะอย่างยิ่งจะกำหนดว่าเนื้อหาแต่ละชิ้นเหมาะสมกับเว็บไซต์ของลูกค้าของเราหรือไม่

ภาพถ่ายโดยไดแอน พิคคิออตติโน

ฟังดูตรงไปตรงมา — กำจัดการละเมิดที่ชัดเจน เช่น คำพูดแสดงความเกลียดชัง ภาษาหยาบคาย หรือการชักชวน — แต่ในทางปฏิบัติ มีความเหมาะสมยิ่งขึ้นมาก ลูกค้าแต่ละรายมีข้อกำหนดเฉพาะสำหรับสิ่งที่พวกเขาเห็นว่าเหมาะสม ตัวอย่างเช่น แบรนด์เบียร์คาดว่าจะมีการพูดคุยเรื่องเครื่องดื่มแอลกอฮอล์ แต่แบรนด์สำหรับเด็กอาจไม่คาดหวัง เรารวบรวมตัวเลือกเฉพาะไคลเอนต์เหล่านี้เมื่อเราเริ่มต้นใช้งานลูกค้าใหม่ และทีมบริการลูกค้าของเราจะเข้ารหัสตัวเลือกเหล่านั้นลงในฐานข้อมูลการจัดการ

เพื่อความซับซ้อนที่เพิ่มเข้ามา เรายังสุ่มตัวอย่างเนื้อหาบางส่วนของเราเพื่อให้ผู้ดูแลที่เป็นมนุษย์เป็นผู้ตรวจสอบ สิ่งนี้ช่วยให้เราสามารถวัดประสิทธิภาพของโมเดลของเราได้อย่างต่อเนื่องและค้นพบโอกาสในการสร้างโมเดลเพิ่มเติม

สถาปัตยกรรมทั้งหมดของระบบเดิมของเราแสดงไว้ด้านล่าง:

ระบบเดิม

ระบบนี้มีข้อบกพร่องร้ายแรงบางประการ โดยเฉพาะอย่างยิ่ง — โมเดลทั้งหมดโฮสต์อยู่บน EC2 instance เดียว นี่ไม่ได้เกิดจากวิศวกรรมที่ไม่ดี — เพียงแต่โปรแกรมเมอร์ดั้งเดิมไม่สามารถคาดการณ์ขนาดที่บริษัทต้องการได้ ไม่มีใครคิดว่ามันจะเติบโตได้มากเท่านี้

นอกจากนี้ ระบบยังได้รับผลกระทบจากการปฏิเสธของนักพัฒนา: มันถูกเขียนด้วย Scala ซึ่งมีวิศวกรเพียงไม่กี่คนที่เข้าใจ ดังนั้นจึงมักถูกมองข้ามการปรับปรุงเนื่องจากไม่มีใครอยากแตะต้องมัน

เป็นผลให้ระบบยังคงเติบโตอย่างต่อเนื่องในลักษณะเปิดไฟ เมื่อเราปรับสถาปัตยกรรมมันใหม่แล้ว มันก็ทำงานบนอินสแตนซ์ x1e.8xlarge เดียว สิ่งนี้มี RAM เกือบเทราไบต์และมีค่าใช้จ่ายประมาณ 5,000 เหรียญสหรัฐต่อเดือน (ไม่สงวนไว้) ในการดำเนินการ ไม่ต้องกังวล เราเพิ่งเปิดตัวส่วนที่สองสำหรับการสำรองและส่วนที่สามสำหรับ QA

ระบบนี้มีค่าใช้จ่ายสูงในการทำงานและมีความเสี่ยงสูงที่จะเกิดความล้มเหลว (โมเดลที่ไม่ดีเพียงตัวเดียวอาจทำให้บริการทั้งหมดล่มได้) นอกจากนี้ ฐานโค้ดยังไม่ได้รับการพัฒนาอย่างจริงจัง และล้าสมัยอย่างมากด้วยแพ็คเกจวิทยาศาสตร์ข้อมูลสมัยใหม่ และไม่ปฏิบัติตามหลักปฏิบัติมาตรฐานของเราสำหรับบริการที่เขียนด้วย Scala

ระบบใหม่

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

การออกแบบใหม่ที่เราสร้างขึ้นมีดังต่อไปนี้:

ระบบเดิม
สถาปัตยกรรมใหม่ของเราจะปรับใช้แต่ละโมเดลกับปลายทาง SageMaker Serverless ซึ่งช่วยให้เราสามารถขยายจำนวนโมเดลได้ไม่จำกัดโดยยังคงรักษาต้นทุนเพียงเล็กน้อย

แนวทางของเราในการแก้ปัญหาทั้งหมดนี้คือการวางโมเดล Machine Learning แต่ละโมเดลไว้บนจุดสิ้นสุด SageMaker Serverless ที่แยกออกมา เช่นเดียวกับฟังก์ชัน AWS Lambda ตำแหน่งข้อมูลแบบไร้เซิร์ฟเวอร์จะปิดเมื่อไม่ได้ใช้งาน ซึ่งช่วยเราประหยัดค่าใช้จ่ายรันไทม์สำหรับรุ่นที่ไม่ค่อยได้ใช้ นอกจากนี้ยังสามารถขยายขนาดได้อย่างรวดเร็วเพื่อตอบสนองต่อปริมาณการเข้าชมที่เพิ่มขึ้น

นอกจากนี้ เรายังเปิดเผยตัวเลือกไคลเอ็นต์กับไมโครเซอร์วิสเดียวที่กำหนดเส้นทางเนื้อหาไปยังโมเดลที่เหมาะสม นี่เป็นโค้ดใหม่ส่วนใหญ่ที่เราต้องเขียน: API ขนาดเล็กที่ง่ายต่อการบำรุงรักษาและให้นักวิทยาศาสตร์ข้อมูลของเราอัปเดตและปรับใช้โมเดลใหม่ได้ง่ายขึ้น

วิธีนี้มีประโยชน์ดังต่อไปนี้:

  • ลดเวลาในการสร้างมูลค่าลงมากกว่า 6 เท่า โดยเฉพาะอย่างยิ่ง การกำหนดเส้นทางการรับส่งข้อมูลไปยังโมเดลที่มีอยู่นั้นสามารถทำได้ทันที และการปรับใช้โมเดลใหม่สามารถทำได้ภายในเวลาไม่ถึง 5 นาที แทนที่จะเป็น 30 นาที
  • ปรับขนาดได้ไม่จำกัด – ขณะนี้เรามีโมเดล 400 โมเดล แต่วางแผนที่จะขยายเป็นหลายพันโมเดลเพื่อเพิ่มปริมาณเนื้อหาที่เรากลั่นกรองได้โดยอัตโนมัติ
  • เห็นการลดต้นทุนถึง 82% โดยย้ายออกจาก EC2 เนื่องจากฟังก์ชันปิดเมื่อไม่ได้ใช้งาน และเราไม่ได้จ่ายเงินสำหรับเครื่องจักรระดับสูงที่มีการใช้งานน้อยเกินไป

อย่างไรก็ตาม การออกแบบสถาปัตยกรรมในอุดมคติเพียงอย่างเดียวไม่ใช่ส่วนที่ยาก ที่น่าสนใจ จริงๆ ในการสร้างระบบเดิมขึ้นมาใหม่ — คุณต้อง ย้าย ไปยังระบบนั้น

ความท้าทายแรกของเราในการย้ายข้อมูลคือการหาวิธีย้ายโมเดล Java WEKA เพื่อทำงานบน SageMaker ไม่ต้องพูดถึง SageMaker Serverless

โชคดีที่ SageMaker ปรับใช้โมเดลในคอนเทนเนอร์ Docker ดังนั้นอย่างน้อยเราก็สามารถหยุดเวอร์ชัน Java และการอ้างอิงเพื่อให้ตรงกับโค้ดเก่าของเราได้ สิ่งนี้จะช่วยให้แน่ใจว่าโมเดลที่โฮสต์อยู่ในระบบใหม่จะให้ผลลัพธ์เหมือนกับโมเดลเดิม

ภาพจากเจเจ หญิง

หากต้องการทำให้คอนเทนเนอร์เข้ากันได้กับ SageMaker สิ่งที่คุณต้องทำคือติดตั้งตำแหน่งข้อมูล HTTP เฉพาะบางอย่าง:

  • POST /invocation — ยอมรับอินพุต อนุมาน และส่งคืนผลลัพธ์
  • GET /ping — คืนค่า 200 หากเซิร์ฟเวอร์ JVM มีประสิทธิภาพดี

(เราเลือกที่จะเพิกเฉยต่อข้อขัดแย้งทั้งหมดเกี่ยวกับคอนเทนเนอร์หลายแบบจำลอง BYO และชุดเครื่องมืออนุมานของ SageMaker)

สรุปสั้นๆ สั้นๆ เกี่ยวกับ com.sun.net.httpserver.HttpServer และเราพร้อมแล้ว

และคุณรู้อะไรไหม? นี่มันสนุกจริงๆ การใช้คอนเทนเนอร์ Docker และบังคับให้บางสิ่งบางอย่างอายุ 10 ปีเข้าสู่ SageMaker Serverless ให้ความรู้สึกที่ยุ่งยากเล็กน้อย มันค่อนข้างน่าตื่นเต้นเมื่อเราทำให้มันใช้งานได้ โดยเฉพาะอย่างยิ่งเมื่อเราได้รับโค้ดระบบเดิมเพื่อสร้างมันใน sbt stack ใหม่ของเราแทนที่จะเป็น maven

สแต็ก sbt ใหม่ทำให้ทำงานได้ง่าย และการวางคอนเทนเนอร์ทำให้เรามั่นใจได้ว่าเราจะมีพฤติกรรมที่เหมาะสมขณะทำงานในสภาพแวดล้อม SageMaker

การย้ายไปยังระบบใหม่

เรามีโมเดลในคอนเทนเนอร์และสามารถปรับใช้กับ SageMaker ได้ — เกือบจะเสร็จแล้วใช่ไหม ไม่มาก.

บทเรียนที่ยากเกี่ยวกับการโยกย้ายไปยังสถาปัตยกรรมใหม่คือคุณต้องสร้างระบบจริงของคุณสามครั้งเพื่อรองรับการย้าย นอกจากระบบใหม่แล้ว เรายังต้องสร้าง:

  • ไปป์ไลน์การจับข้อมูลในระบบเก่าเพื่อบันทึกอินพุตและเอาต์พุตจากโมเดล เราใช้สิ่งเหล่านี้เพื่อยืนยันว่าระบบใหม่จะให้ผลลัพธ์เหมือนเดิม
  • ไปป์ไลน์การประมวลผลข้อมูลในระบบใหม่เพื่อคำนวณผลลัพธ์และเปรียบเทียบกับข้อมูลจากระบบเก่า สิ่งนี้เกี่ยวข้องกับการวัดจำนวนมากด้วย Datadog และจำเป็นต้องเสนอความสามารถในการเล่นข้อมูลซ้ำเมื่อเราพบความคลาดเคลื่อน
  • ระบบการปรับใช้โมเดลเต็มรูปแบบเพื่อหลีกเลี่ยงผลกระทบต่อผู้ใช้ระบบเก่า (ซึ่งจะอัปโหลดโมเดลไปยัง S3) เรารู้ว่าในที่สุดเราต้องการย้ายพวกมันไปยัง API แต่สำหรับการเปิดตัวครั้งแรก เราจำเป็นต้องดำเนินการอย่างราบรื่น

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

คาดหวังสิ่งนี้ล่วงหน้า

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

การปรับปรุงระบบเดิมให้ทันสมัยด้วยสถาปัตยกรรมใหม่

ครั้งต่อไปที่คุณถูกล่อลวงให้สร้างระบบใหม่ตั้งแต่เริ่มต้นโค้ด ฉันขอแนะนำให้คุณลองย้ายสถาปัตยกรรมแทนโค้ด คุณจะพบกับความท้าทายด้านเทคนิคที่น่าสนใจและคุ้มค่า และจะสนุกไปกับมันมากกว่าการดีบักกรณี Edge ที่ไม่คาดคิดของโค้ดใหม่ของคุณ

ต้องการเรียนรู้เพิ่มเติมหรือไม่? ดูการบรรยายที่ฉันบรรยายที่ AWS Data Summit ด้านล่าง ซึ่งจะเจาะลึกเกี่ยวกับ MLOps