เมื่อเราย้ายจากแอปพลิเคชันขนาดใหญ่ไปสู่สถาปัตยกรรมไมโครเซอร์วิส เราก็เผชิญกับความท้าทายใหม่ๆ
ในแอปพลิเคชันแบบเสาหิน มักจะค่อนข้างง่ายในการพิจารณาว่าส่วนใดของระบบที่เกิดข้อผิดพลาด เป็นไปได้มากว่าปัญหาอยู่ในโค้ดของเสาหินนั้นเองหรือในฐานข้อมูล แต่เมื่อเราเริ่มมองหาปัญหาในสถาปัตยกรรมไมโครเซอร์วิส ทุกอย่างก็ไม่ชัดเจนอีกต่อไป เราจำเป็นต้องค้นหาเส้นทางทั้งหมดที่คำขอใช้ตั้งแต่ต้นจนจบ และเลือกจากไมโครเซอร์วิสหลายร้อยรายการ ยิ่งไปกว่านั้น หลายแห่งยังมีสิ่งอำนวยความสะดวกในการจัดเก็บของตัวเอง ซึ่งอาจทำให้เกิดข้อผิดพลาดเชิงตรรกะ รวมถึงปัญหาด้านประสิทธิภาพและความทนทานต่อข้อผิดพลาด
ฉันมองหาเครื่องมือที่จะช่วยรับมือกับปัญหาดังกล่าวมานานแล้ว (ฉันเขียนเกี่ยวกับเรื่องนี้ในHabré:
การติดตามแบบกระจายเป็นวิธีแก้ไขปัญหาทั่วไปในการค้นหาข้อผิดพลาดในระบบแบบกระจาย แต่จะเกิดอะไรขึ้นถ้ายังไม่ได้ใช้แนวทางในการรวบรวมข้อมูลเกี่ยวกับการโต้ตอบของเครือข่ายในระบบหรือที่แย่กว่านั้นคือในส่วนของระบบมันทำงานได้ถูกต้องแล้ว แต่ส่วนหนึ่งไม่ได้เนื่องจากยังไม่ได้เพิ่มในบริการเก่า ? เพื่อระบุสาเหตุที่แท้จริงของปัญหา จำเป็นต้องมีภาพที่สมบูรณ์ของสิ่งที่เกิดขึ้นในระบบ สิ่งสำคัญอย่างยิ่งคือต้องเข้าใจว่าไมโครเซอร์วิสใดบ้างที่เกี่ยวข้องกับเส้นทางสำคัญทางธุรกิจ
ในที่นี้แนวทางการบริการแบบตาข่ายสามารถช่วยเราได้ ซึ่งจะจัดการกับเครื่องจักรทั้งหมดสำหรับการรวบรวมข้อมูลเครือข่ายในระดับที่ต่ำกว่าบริการที่ดำเนินการเอง วิธีการนี้ช่วยให้เราสามารถสกัดกั้นการรับส่งข้อมูลทั้งหมดและวิเคราะห์ได้ทันที ยิ่งไปกว่านั้น แอปพลิเคชันไม่จำเป็นต้องรู้อะไรเลยด้วยซ้ำ
แนวทางการบริการแบบตาข่าย
แนวคิดหลักของแนวทางการบริการแบบตาข่ายคือการเพิ่มโครงสร้างพื้นฐานอีกชั้นหนึ่งบนเครือข่าย ซึ่งจะช่วยให้เราทำอะไรก็ได้ที่มีการโต้ตอบระหว่างบริการ การใช้งานส่วนใหญ่ทำงานดังนี้: มีการเพิ่มคอนเทนเนอร์ไซด์คาร์เพิ่มเติมพร้อมพร็อกซีแบบโปร่งใสลงในแต่ละไมโครเซอร์วิส ซึ่งการรับส่งข้อมูลขาเข้าและขาออกของบริการทั้งหมดจะถูกส่งผ่าน และนี่คือที่ที่เราสามารถสร้างสมดุลให้กับลูกค้า ใช้นโยบายความปลอดภัย กำหนดข้อจำกัดเกี่ยวกับจำนวนคำขอ และรวบรวมข้อมูลที่สำคัญเกี่ยวกับการโต้ตอบของบริการในการผลิต
โซลูชั่น
มีการนำแนวทางนี้ไปใช้หลายประการแล้ว:
ด้วยเหตุนี้ เราจึงพิจารณาว่าความสามารถใดที่เราต้องการในตอนนี้ และตัดสินใจว่าเหตุผลหลักที่เราเริ่มใช้โซลูชันดังกล่าวคือความสามารถในการรวบรวมข้อมูลการติดตามจากทั้งระบบอย่างโปร่งใส นอกจากนี้เรายังต้องการควบคุมการโต้ตอบของบริการและดำเนินการต่างๆ กับส่วนหัวที่ถ่ายโอนระหว่างบริการต่างๆ
เป็นผลให้เราตัดสินใจ:
เนตราเมช
เป้าหมายหลักของโซลูชันใหม่คือต้นทุนทรัพยากรที่ต่ำและประสิทธิภาพสูง ในบรรดาคุณสมบัติหลักต่างๆ เราต้องการส่งช่วงการติดตามไปยังระบบ Jaeger ของเราอย่างโปร่งใสในทันที
ปัจจุบัน โซลูชันคลาวด์ส่วนใหญ่มีการใช้งานใน Golang และแน่นอนว่ามีเหตุผลสำหรับเรื่องนี้ การเขียนแอปพลิเคชันเครือข่ายใน Golang ที่ทำงานแบบอะซิงโครนัสกับ I/O และปรับขนาดข้ามคอร์ได้ตามต้องการนั้นสะดวกและค่อนข้างง่าย และที่สำคัญมากก็คือประสิทธิภาพก็เพียงพอที่จะแก้ไขปัญหานี้ได้ นั่นเป็นเหตุผลที่เราเลือก Golang ด้วย
การปฏิบัติ
เราได้มุ่งเน้นความพยายามของเราในการบรรลุผลผลิตสูงสุด สำหรับโซลูชันที่ใช้งานถัดจากแต่ละอินสแตนซ์ของบริการ ต้องใช้เวลา RAM และ CPU เพียงเล็กน้อย และแน่นอนว่าการตอบสนองล่าช้าก็ควรจะน้อยเช่นกัน
มาดูกันว่าเราได้ผลลัพธ์อะไรบ้าง
แรม
Netramesh กิน ~10Mb โดยไม่มีการรับส่งข้อมูล และสูงสุด 50Mb พร้อมโหลดสูงสุด 10000 RPS ต่ออินสแตนซ์
พร็อกซีทูต Istio ใช้งาน ~300Mb เสมอในคลัสเตอร์ของเราซึ่งมีอินสแตนซ์นับพันรายการ ซึ่งไม่อนุญาตให้ปรับขนาดเป็นทั้งคลัสเตอร์
ด้วย Netramesh เราได้รับการลดการใช้หน่วยความจำลงประมาณ 10 เท่า
ซีพียู
การใช้งาน CPU ค่อนข้างเท่ากันภายใต้ภาระงาน ขึ้นอยู่กับจำนวนคำขอต่อหน่วยเวลาในการส่งรถเทียมข้างรถจักรยานยนต์ ค่าที่ 3000 คำขอต่อวินาทีที่จุดสูงสุด:
มีจุดสำคัญอีกประการหนึ่ง: Netramesh - โซลูชันที่ไม่มีระนาบควบคุมและไม่มีโหลดจะไม่ใช้เวลา CPU เมื่อใช้ Istio รถเทียมข้างรถจักรยานยนต์จะอัปเดตจุดสิ้นสุดบริการเสมอ เป็นผลให้เราสามารถเห็นภาพนี้โดยไม่ต้องโหลด:
เราใช้ HTTP/1 เพื่อการสื่อสารระหว่างบริการต่างๆ เวลาตอบสนองที่เพิ่มขึ้นสำหรับ Istio เมื่อทำการพร็อกซีผ่านทูตนั้นสูงถึง 5-10 มิลลิวินาที ซึ่งถือว่าค่อนข้างมากสำหรับบริการที่พร้อมตอบสนองในเสี้ยววินาที ด้วย Netramesh เวลานี้ลดลงเหลือ 0.5-2ms
ความสามารถในการปรับขนาด
ทรัพยากรจำนวนเล็กน้อยที่ใช้โดยแต่ละพรอกซีทำให้สามารถวางไว้ข้างๆ แต่ละบริการได้ Netramesh ถูกสร้างขึ้นโดยเจตนาโดยไม่มีส่วนประกอบของระนาบควบคุมเพื่อให้รถเทียมข้างรถจักรยานยนต์แต่ละคันมีน้ำหนักเบา บ่อยครั้งในโซลูชันโครงข่ายบริการ ส่วนควบคุมจะกระจายข้อมูลการค้นหาบริการไปยังรถเทียมข้างรถจักรยานยนต์แต่ละคัน พร้อมด้วยข้อมูลเกี่ยวกับการหมดเวลาและการตั้งค่าสมดุล ทั้งหมดนี้ช่วยให้คุณทำสิ่งที่มีประโยชน์มากมาย แต่น่าเสียดายที่มันขยายขนาดรถเทียมข้างรถจักรยานยนต์
การค้นพบบริการ
Netramesh ไม่ได้เพิ่มกลไกเพิ่มเติมใดๆ สำหรับการค้นหาบริการ การรับส่งข้อมูลทั้งหมดได้รับพร็อกซีอย่างโปร่งใสผ่าน netra sidecar
Netramesh รองรับโปรโตคอลแอปพลิเคชัน HTTP/1 เพื่อกำหนดจะใช้รายการพอร์ตที่กำหนดค่าได้ โดยทั่วไป ระบบจะมีพอร์ตหลายพอร์ตที่ใช้สื่อสาร HTTP ตัวอย่างเช่น เราใช้ 80, 8890, 8080 สำหรับการโต้ตอบระหว่างบริการและคำขอภายนอก ในกรณีนี้ สามารถตั้งค่าได้โดยใช้ตัวแปรสภาพแวดล้อม NETRA_HTTP_PORTS
.
หากคุณใช้ Kubernetes เป็นผู้เรียบเรียงและกลไกเอนทิตีบริการสำหรับการสื่อสารภายในคลัสเตอร์ระหว่างบริการ กลไกดังกล่าวจะยังคงเหมือนเดิมทุกประการ ขั้นแรก ไมโครเซอร์วิสจะได้รับที่อยู่ IP ของบริการโดยใช้ kube-dns และเปิดการเชื่อมต่อใหม่ การเชื่อมต่อนี้สร้างขึ้นครั้งแรกกับ netra-sidecar ในเครื่อง และแพ็กเก็ต TCP ทั้งหมดจะมาถึง netra ในขั้นต้น ถัดไป netra-sidecar จะสร้างการเชื่อมต่อกับจุดหมายปลายทางดั้งเดิม NAT บน IP ของพ็อดบนโหนดยังคงเหมือนเดิมทุกประการเมื่อไม่มี netra
การติดตามแบบกระจายและการส่งต่อบริบท
Netramesh มีฟังก์ชันการทำงานที่จำเป็นในการส่งช่วงการติดตามเกี่ยวกับการโต้ตอบ HTTP Netra-sidecar แยกวิเคราะห์โปรโตคอล HTTP วัดความล่าช้าของคำขอ และแยกข้อมูลที่จำเป็นจากส่วนหัว HTTP ในที่สุด เราก็ได้รับร่องรอยทั้งหมดในระบบเยเกอร์เพียงระบบเดียว สำหรับการกำหนดค่าแบบละเอียด คุณยังสามารถใช้ตัวแปรสภาพแวดล้อมที่มาจากไลบรารีอย่างเป็นทางการได้
แต่มีปัญหาอยู่ จนกว่าบริการจะสร้างและส่งส่วนหัว uber พิเศษ เราจะไม่เห็นช่วงการติดตามที่เชื่อมต่ออยู่ในระบบ และนี่คือสิ่งที่เราต้องค้นหาสาเหตุของปัญหาอย่างรวดเร็ว ที่นี่ Netramesh มีวิธีแก้ปัญหาอีกครั้ง พร็อกซีอ่านส่วนหัว HTTP และหากไม่มีรหัสการติดตาม uber ให้สร้างขึ้นใหม่ Netramesh ยังจัดเก็บข้อมูลเกี่ยวกับคำขอขาเข้าและขาออกไว้ในรถเทียมข้างรถจักรยานยนต์และจับคู่คำขอเหล่านั้นด้วยการเพิ่มคุณค่าให้กับส่วนหัวคำขอขาออกที่จำเป็น สิ่งที่คุณต้องทำในบริการคือส่งส่วนหัวเพียงอันเดียว X-Request-Id
ซึ่งสามารถกำหนดค่าได้โดยใช้ตัวแปรสภาพแวดล้อม NETRA_HTTP_REQUEST_ID_HEADER_NAME
. หากต้องการควบคุมขนาดของบริบทใน Netramesh คุณสามารถตั้งค่าตัวแปรสภาพแวดล้อมต่อไปนี้: NETRA_TRACING_CONTEXT_EXPIRATION_MILLISECONDS
(เวลาที่บริบทจะถูกจัดเก็บ) และ NETRA_TRACING_CONTEXT_CLEANUP_INTERVAL
(ความถี่ของการล้างบริบท)
นอกจากนี้ยังสามารถรวมหลายเส้นทางในระบบของคุณโดยการทำเครื่องหมายด้วยโทเค็นเซสชันพิเศษ Netra ให้คุณติดตั้งได้ HTTP_HEADER_TAG_MAP
เพื่อเปลี่ยนส่วนหัว HTTP ให้เป็นแท็กการขยายการติดตามที่สอดคล้องกัน สิ่งนี้มีประโยชน์อย่างยิ่งสำหรับการทดสอบ หลังจากผ่านการทดสอบการทำงาน คุณจะสามารถดูได้ว่าส่วนใดของระบบที่ได้รับผลกระทบจากการกรองด้วยคีย์เซสชันที่เกี่ยวข้อง
การกำหนดแหล่งที่มาของคำขอ
หากต้องการทราบว่าคำขอมาจากไหน คุณสามารถใช้ฟังก์ชันการเพิ่มส่วนหัวพร้อมแหล่งที่มาโดยอัตโนมัติได้ การใช้ตัวแปรสภาพแวดล้อม NETRA_HTTP_X_SOURCE_HEADER_NAME
คุณสามารถระบุชื่อส่วนหัวที่จะติดตั้งโดยอัตโนมัติได้ โดยใช้ NETRA_HTTP_X_SOURCE_VALUE
คุณสามารถตั้งค่าที่จะตั้งค่าส่วนหัว X-Source สำหรับคำขอขาออกทั้งหมดได้
ซึ่งช่วยให้การกระจายส่วนหัวที่มีประโยชน์นี้สามารถกระจายอย่างสม่ำเสมอทั่วทั้งเครือข่าย จากนั้นคุณจะสามารถใช้ในบริการและเพิ่มลงในบันทึกและหน่วยวัดได้
การกำหนดเส้นทางการรับส่งข้อมูลและภายใน Netramesh
Netramesh ประกอบด้วยสององค์ประกอบหลัก ประการแรก netra-init กำหนดกฎเครือข่ายเพื่อสกัดกั้นการรับส่งข้อมูล เขาใช้ INBOUND_INTERCEPT_PORTS, OUTBOUND_INTERCEPT_PORTS
.
เครื่องมือนี้ยังมีคุณสมบัติที่น่าสนใจ - การกำหนดเส้นทางที่น่าจะเป็น หากคุณใช้ Netramesh เพื่อรวบรวมช่วงการติดตามโดยเฉพาะ ในสภาพแวดล้อมการใช้งานจริง คุณจะประหยัดทรัพยากรและเปิดใช้งานการกำหนดเส้นทางที่น่าจะเป็นได้โดยใช้ตัวแปร NETRA_INBOUND_PROBABILITY
и NETRA_OUTBOUND_PROBABILITY
(ตั้งแต่ 0 ถึง 1) ค่าเริ่มต้นคือ 1 (การรับส่งข้อมูลทั้งหมดถูกดัก)
หลังจากการสกัดกั้นสำเร็จ netra sidecar ก็ยอมรับการเชื่อมต่อและการใช้งานใหม่ SO_ORIGINAL_DST
ตัวเลือกซ็อกเก็ตเพื่อรับปลายทางเดิม จากนั้น Netra จะเปิดการเชื่อมต่อใหม่ไปยังที่อยู่ IP เดิม และสร้างการสื่อสาร TCP แบบสองทางระหว่างทั้งสองฝ่าย โดยรับฟังการรับส่งข้อมูลทั้งหมดที่ส่งผ่าน หากพอร์ตถูกกำหนดให้เป็น HTTP Netra จะพยายามแยกวิเคราะห์และติดตามพอร์ตนั้น หากการแยกวิเคราะห์ HTTP ล้มเหลว Netra จะถอยกลับไปเป็น TCP และมอบพร็อกซีไบต์อย่างโปร่งใส
การสร้างกราฟการพึ่งพา
หลังจากได้รับข้อมูลการติดตามจำนวนมากใน Jaeger ฉันต้องการรับกราฟการโต้ตอบในระบบที่สมบูรณ์ แต่หากระบบของคุณมีภาระงานค่อนข้างมากและมีช่วงการติดตามนับพันล้านรายการสะสมต่อวัน การรวมเข้าด้วยกันจะไม่ใช่เรื่องง่าย มีวิธีอย่างเป็นทางการในการดำเนินการนี้:
หากคุณใช้ Elasticsearch เพื่อจัดเก็บช่วงการติดตาม คุณสามารถใช้ได้
วิธีการใช้งาน Netramesh
คุณสามารถเพิ่ม Netra ลงในบริการใด ๆ ที่ใช้งาน orchestrator ได้อย่างง่ายดาย คุณสามารถดูตัวอย่างได้
ในขณะนี้ Netra ยังไม่มีความสามารถในการนำรถเทียมข้างรถจักรยานยนต์ไปใช้กับบริการโดยอัตโนมัติ แต่มีแผนในการดำเนินการ
อนาคตของเนตราเมช
เป้าหมายหลัก
ในอนาคต Netramesh จะรองรับโปรโตคอลเลเยอร์แอปพลิเคชันอื่นๆ นอกเหนือจาก HTTP การกำหนดเส้นทาง L7 จะพร้อมใช้งานในอนาคตอันใกล้นี้
ใช้ Netramesh หากคุณพบปัญหาที่คล้ายกันและเขียนถึงเราพร้อมคำถามและข้อเสนอแนะ
ที่มา: will.com