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

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

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

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

การปรับใช้ซอฟต์แวร์แบบสแตนด์อโลนเทียบกับแบบกระจาย

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

ปัญหากับการเปลี่ยนแปลงโปรโตคอล

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

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

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

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

เทคนิคการปรับใช้แบบสองระยะ

วิธีหนึ่งที่เราตรวจสอบให้แน่ใจว่าเราสามารถย้อนกลับได้อย่างปลอดภัยก็คือการใช้เทคนิคที่เป็นที่รู้จักกันในชื่อ การปรับใช้แบบสองระยะ ลองนึกถึงการทำตามสถานการณ์จำลองที่มีบริการที่จัดการข้อมูล (เขียนถึงและรับมาอ่าน) บน Amazon Simple Storage Service (Amazon S3) บริการจะทำงานบนฟลีตของเซิร์ฟเวอร์ทั่วทั้ง Availability Zone ที่หลากหลายเพื่อปรับขนาดและให้พร้อมใช้งาน

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

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

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

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

การป้องกันไว้ก่อนด้วยการปรับใช้แบบสองระยะ

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

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

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

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

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

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

แนวปฏิบัติที่ดีที่สุดสำหรับการซีเรียลไลซ์

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

• เรามักจะหลีกเลี่ยงการพัฒนารูปแบบการซีเรียลไลซ์ของลูกค้า

ลอจิกเบื้องต้นสำหรับการซีเรียลไลซ์ของลูกค้าอาจดูเป็นเรื่องธรรมดา และส่งเสริมประสิทธิภาพการทำงานให้ดีขึ้น อย่างไรก็ตาม การทำซ้ำรูปแบบในลำดับถัดๆ ไปจะแสดงให้เห็นถึงความท้าทายที่ได้รับการแก้ไขแล้วโดยเฟรมเวิร์กที่เริ่มขึ้นมาอย่างดี เช่น JSON, Protocol Buffers, Cap’n Proto และ FlatBuffers เมื่อใช้งานอย่างเหมาะสม เฟรมเวิร์กเหล่านี้จะมอบคุณลักษณะที่ปลอดภัยให้ เช่น การหลีก ความเข้ากันได้แบบย้อนหลัง และการติดตามการมีอยู่ของแอตทริบิวต์ (ซึ่งก็คือ ดูว่าช่องได้ตั้งไว้อย่างชัดเจนหรือกำหนดให้เป็นค่าเริ่มต้นโดยนัย)

• ในแต่ละการเปลี่ยนแปลง เราจะกำหนดเวอร์ชันที่แตกต่างกันลงในตัวซีเรียลไลซ์อย่างชัดเจน

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

• เราหลีกเลี่ยงการซีเรียลไลซ์โครงสร้างข้อมูลที่เราไม่สามารถควบคุมได้

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

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

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

การยืนยันว่าการเปลี่ยนแปลงนั้นปลอดภัยสำหรับการย้อนกลับ

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

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

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

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

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

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

สรุป

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

อ่านเพิ่มเติม

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับวิธีที่ Amazon เพิ่มความปลอดภัยและความพร้อมใช้งานของบริการ ในขณะเดียวกันก็เพิ่มความพอใจให้แก่ลูกค้าและประสิทธิภาพของนักพัฒนา ดูที่ การทำให้การปรับใช้ซอฟต์แวร์เป็นอัตโนมัติ


เกี่ยวกับผู้เขียน

Sandeep Pokkunuri เป็นหัวหน้าวิศวกรรมที่ AWS ตั้งแต่ที่เข้าร่วมกับ Amazon ในปี 2011 เขาได้ทำงานให้กับบริการหลากหลายอย่างรวมถึง Amazon DynamoDB และ Amazon Simple Queue Service (SQS) ขณะนี้เขากำลังให้ความสนใจกับเทคโนโลยี ML ที่เกี่ยวข้องกับภาษามนุษย์ (เช่น ASR, NLP, NLU และ Machine Translation) และเป็นหัวหน้าวิศวกรให้กับ Amazon Lex ก่อนที่จะเข้าร่วมกับ AWS เขาทำงานอยู่ที่ Google ในด้านแมชชีนเลิร์นนิ่ง เช่น สแปมและการตรวจจับเนื้อหาคุกคามในสื่อสังคมและการตรวจหาสิ่งผิดปกติในบันทึกการเข้าถึงเครือข่าย

ทำงานเร็วขึ้นด้วยการส่งมอบอย่างต่อเนื่อง