paint-brush
Web IDE นี้จะรันโค้ดของคุณบนคลาวด์โดยไม่ทำให้แล็ปท็อปของคุณละลายโดย@oleksiijko
ประวัติศาสตร์ใหม่

Web IDE นี้จะรันโค้ดของคุณบนคลาวด์โดยไม่ทำให้แล็ปท็อปของคุณละลาย

โดย Oleksii Bondar12m2025/02/21
Read on Terminal Reader

นานเกินไป; อ่าน

โครงการนี้สร้างขึ้นบนหลักการของสถาปัตยกรรมไมโครเซอร์วิส ซึ่งช่วยให้คุณแบ่งฟังก์ชันการทำงานออกเป็นบริการอิสระได้ แต่ละส่วนประกอบมีหน้าที่รับผิดชอบงานเฉพาะทางสูง ซึ่งรับประกันความยืดหยุ่น ความสามารถในการปรับขนาด และการทนทานต่อข้อผิดพลาดของระบบ โครงการนี้ใช้ภาษาการเขียนโปรแกรม Go เป็นพื้นฐาน
featured image - Web IDE นี้จะรันโค้ดของคุณบนคลาวด์โดยไม่ทำให้แล็ปท็อปของคุณละลาย
Oleksii Bondar HackerNoon profile picture
0-item
1-item

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

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


1. ภาพรวมสถาปัตยกรรมและส่วนประกอบหลัก

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


ส่วนประกอบหลัก:


  • gRPC ใช้สำหรับการสื่อสารระหว่างบริการ เหมาะอย่างยิ่งสำหรับการถ่ายโอนข้อมูลระหว่างไมโครเซอร์วิส เนื่องจาก:
    • โปรโตคอลไบนารี (โปรโตคอลบัฟเฟอร์): รับประกันการถ่ายโอนข้อมูลที่รวดเร็วและกะทัดรัด
    • การพิมพ์ที่เข้มงวด: ช่วยหลีกเลี่ยงข้อผิดพลาดในการถ่ายโอนและประมวลผลข้อมูล
    • ความหน่วงต่ำ: ซึ่งเป็นสิ่งสำคัญสำหรับการโทรภายในระหว่างบริการ (เช่น ระหว่างเซิร์ฟเวอร์ gRPC และคิว Redis)
  • เซิร์ฟเวอร์ WebSocket: ให้การสื่อสารสองทางกับไคลเอนต์เพื่อส่งผลลัพธ์การดำเนินการแบบเรียลไทม์ เซิร์ฟเวอร์จะสมัครรับข้อมูลผลลัพธ์และส่งต่อข้อมูลไปยังไคลเอนต์ ทำให้แสดงบันทึกการคอมไพล์และการดำเนินการได้ทันที
  • เวิร์กเกอร์: บริการอิสระที่ดึงงานจากคิว สร้างสภาพแวดล้อมการทำงานชั่วคราว ตรวจสอบและดำเนินการรหัสในคอนเทนเนอร์ Docker ที่แยกจากกัน แล้วเผยแพร่ผลลัพธ์ของการดำเนินการกลับไปยังคิว
  • Redis: ใช้เป็นโบรกเกอร์ข้อความเพื่อโอนงานจากเซิร์ฟเวอร์ gRPC ไปยัง Worker และผลลัพธ์จาก Worker ไปยังเซิร์ฟเวอร์ WebSocket ข้อดีของ Redis คือความเร็วสูง รองรับ Pub/Sub และปรับขนาดได้ง่าย
  • โมดูลภายใน:
    • คอมไพเลอร์และ Docker Runner: โมดูลที่รับผิดชอบในการรันคำสั่ง Docker พร้อมการบันทึกสตรีม ช่วยให้สามารถตรวจสอบกระบวนการคอมไพเลอร์และการดำเนินการได้แบบเรียลไทม์
    • Language Runners: ผสมผสานตรรกะสำหรับการตรวจสอบ การคอมไพล์ และการดำเนินการของโค้ดสำหรับภาษาต่างๆ (C, C++, C#, Python, JavaScript, TypeScript) แต่ละโปรแกรมรันเนอร์ใช้อินเทอร์เฟซเดียว ซึ่งทำให้การขยายฟังก์ชันสำหรับภาษาใหม่ๆ ง่ายขึ้น


แผนภาพด้านล่างแสดงการไหลของข้อมูลจากไคลเอนต์ไปยังกระบวนการเวิร์กเกอร์และกลับมาโดยใช้ gRPC, Redis และ WebSocket


2. เทคโนโลยีและเหตุผลในการเลือก

ไป

ข้อดีของ Go:

  • ประสิทธิภาพและความสามารถในการปรับขนาด: Go มีความเร็วในการดำเนินการสูง ซึ่งมีความสำคัญอย่างยิ่งสำหรับการจัดการคำขอขนานจำนวนมาก

  • การรองรับการทำงานพร้อมกันในตัว: กลไกของ goroutines และช่องทางช่วยให้สามารถใช้งานการโต้ตอบแบบอะซิงโครนัสระหว่างส่วนประกอบต่างๆ ได้โดยไม่ต้องใช้รูปแบบมัลติเธรดที่ซับซ้อน


จีอาร์พีซี

ข้อดีของ gRPC:

  • การถ่ายโอนข้อมูลที่มีประสิทธิภาพ: ด้วยโปรโตคอลการถ่ายโอนข้อมูลไบนารี (Protocol Buffers) gRPC จึงให้ความหน่วงเวลาต่ำและโหลดเครือข่ายต่ำ
  • การพิมพ์ที่เข้มงวด: ช่วยลดจำนวนข้อผิดพลาดที่เกี่ยวข้องกับการตีความข้อมูลที่ไม่ถูกต้องระหว่างไมโครเซอร์วิส
  • รองรับการสตรีมแบบทิศทางสองทาง: ซึ่งมีประโยชน์อย่างยิ่งสำหรับการแลกเปลี่ยนบันทึกและผลลัพธ์การดำเนินการแบบเรียลไทม์

การเปรียบเทียบ: แตกต่างจาก REST API, gRPC มอบการสื่อสารระหว่างบริการที่มีประสิทธิภาพและเชื่อถือได้มากกว่า ซึ่งเป็นสิ่งสำคัญสำหรับระบบที่มีการทำงานพร้อมกันสูง


เรดิส

เหตุใดจึงเลือก Redis?

  • ประสิทธิภาพสูง: Redis สามารถจัดการการทำงานจำนวนมากต่อวินาที ซึ่งทำให้เหมาะอย่างยิ่งสำหรับคิวงานและผลลัพธ์

  • การรองรับ Pub/Sub และรายการ: ความเรียบง่ายของการนำคิวและกลไกการสมัครรับข้อมูลมาใช้ทำให้สามารถจัดระเบียบการโต้ตอบแบบอะซิงโครนัสระหว่างบริการต่างๆ ได้อย่างง่ายดาย

  • การเปรียบเทียบกับโบรกเกอร์ข้อความอื่น ๆ: ไม่เหมือน RabbitMQ หรือ Kafka, Redis ต้องมีการกำหนดค่าน้อยกว่าและมอบประสิทธิภาพเพียงพอสำหรับระบบเรียลไทม์


ด็อกเกอร์

บทบาทของ Docker:

  • การแยกสภาพแวดล้อม: คอนเทนเนอร์ Docker ช่วยให้คุณสามารถเรียกใช้โค้ดในสภาพแวดล้อมที่แยกออกจากกันโดยสมบูรณ์ ซึ่งจะเพิ่มความปลอดภัยในการดำเนินการและลดความเสี่ยงของการขัดแย้งกับระบบหลัก

  • การจัดการและความสอดคล้องกัน: การใช้ Docker มอบสภาพแวดล้อมแบบเดียวกันในการคอมไพล์และดำเนินการโค้ด โดยไม่คำนึงถึงระบบโฮสต์

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


เว็บซ็อกเก็ต

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


3. ประโยชน์ของสถาปัตยกรรมไมโครเซอร์วิส

โครงการนี้ใช้แนวทางไมโครเซอร์วิสซึ่งมีข้อดีสำคัญหลายประการ:


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


4. การวิเคราะห์เชิงเปรียบเทียบแนวทางสถาปัตยกรรม

เมื่อสร้าง WEB IDE ที่ทันสมัยสำหรับการรันโค้ดจากระยะไกล มักมีการเปรียบเทียบโซลูชันทางสถาปัตยกรรมต่างๆ ลองพิจารณาสองแนวทาง:


แนวทาง A: สถาปัตยกรรมไมโครเซอร์วิส (gRPC + Redis + Docker)


  • ความหน่วง: 40 มิลลิวินาที
  • ปริมาณงาน: 90 หน่วย
  • ระบบรักษาความปลอดภัย : 85 ยูนิต
  • ความสามารถในการขยาย: 90 หน่วย


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


แนวทาง B: สถาปัตยกรรมโมโนลิธิกแบบดั้งเดิม (HTTP REST + การดำเนินการแบบรวมศูนย์)


  • ความหน่วง: 70 มิลลิวินาที
  • ปริมาณงาน: 65 หน่วย
  • ระบบรักษาความปลอดภัย : 60 ยูนิต
  • ความสามารถในการขยาย: 70 หน่วย


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


หมายเหตุ: ในบริบทสมัยใหม่ของการพัฒนา WEB IDE แนวทาง HTTP REST และการดำเนินการแบบรวมศูนย์นั้นด้อยกว่าข้อดีของสถาปัตยกรรมไมโครเซอร์วิส เนื่องจากไม่ได้ให้ความยืดหยุ่นและความสามารถในการปรับขนาดตามที่จำเป็น


การแสดงภาพของเมตริกเชิงเปรียบเทียบ

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


5. สถาปัตยกรรม Docker: การแยกและความสามารถในการปรับขนาด

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


  • การแยกสภาพแวดล้อมการทำงาน: บริการแต่ละอย่าง (เซิร์ฟเวอร์ gRPC, Worker, เซิร์ฟเวอร์ WebSocket) และโบรกเกอร์ข้อความ (Redis) ทำงานในคอนเทนเนอร์ของตัวเอง ซึ่งช่วยลดความเสี่ยงของโค้ดที่ไม่ปลอดภัยที่จะส่งผลกระทบต่อระบบหลัก ในขณะเดียวกัน โค้ดที่ผู้ใช้เรียกใช้ในเบราว์เซอร์ (เช่น ผ่าน WEB IDE) จะถูกสร้างและดำเนินการในคอนเทนเนอร์ Docker แยกต่างหากสำหรับแต่ละงาน แนวทางนี้ช่วยให้มั่นใจได้ว่าโค้ดที่อาจไม่ปลอดภัยหรือผิดพลาดจะไม่ส่งผลกระทบต่อการทำงานของโครงสร้างพื้นฐานหลัก
  • ความสอดคล้องของสภาพแวดล้อม: การใช้ Docker ช่วยให้แน่ใจว่าการตั้งค่ายังคงเหมือนเดิมในสภาพแวดล้อมการพัฒนา การทดสอบ และการผลิต ซึ่งช่วยลดความซับซ้อนของการดีบักและทำให้แน่ใจถึงความสามารถในการคาดเดาการทำงานของโค้ด
  • ความยืดหยุ่นในการปรับขนาด: สามารถปรับขนาดแต่ละส่วนประกอบได้อย่างอิสระ ซึ่งช่วยให้คุณปรับตัวให้เข้ากับโหลดที่เปลี่ยนแปลงได้อย่างมีประสิทธิภาพ ตัวอย่างเช่น เมื่อจำนวนคำขอเพิ่มขึ้น คุณสามารถเปิดใช้คอนเทนเนอร์ Worker เพิ่มเติมได้ โดยแต่ละคอนเทนเนอร์จะสร้างคอนเทนเนอร์แยกกันสำหรับการดำเนินการโค้ดของผู้ใช้

ในโครงร่างนี้ Worker ไม่เพียงแต่จะรับงานจาก Redis แต่ยังสร้างคอนเทนเนอร์แยกต่างหาก (คอนเทนเนอร์: การดำเนินการรหัส) สำหรับแต่ละคำขอในการดำเนินการรหัสของผู้ใช้โดยแยกจากกันอีกด้วย


6. ส่วนเล็ก ๆ ของโค้ด

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

  1. กำหนดภาษาที่จะรันโดยใช้รีจิสทรีตัวรันระดับโลก
  2. เริ่มคอนเทนเนอร์ Docker เพื่อรันโค้ดผู้ใช้โดยใช้ฟังก์ชัน RunInDockerStreaming



1. การตรวจจับภาษาผ่านการลงทะเบียนนักวิ่ง

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


 package languages import ( "errors" "sync" ) var ( registry = make(map[string]Runner) registryMu sync.RWMutex ) type Runner interface { Validate(projectDir string) error Compile(ctx context.Context, projectDir string) (<-chan string, error) Run(ctx context.Context, projectDir string) (<-chan string, error) } func Register(language string, runner Runner) { registryMu.Lock() defer registryMu.Unlock() registry[language] = runner } func GetRunner(language string) (Runner, error) { registryMu.RLock() defer registryMu.RUnlock() if runner, exists := registry[language]; exists { return runner, nil } return nil, errors.New("unsupported language") }


ตัวอย่างการลงทะเบียนภาษาใหม่:


 func init() { languages.Register("python", NewGenericRunner("python")) languages.Register("javascript", NewGenericRunner("javascript")) }


ดังนั้นเมื่อได้รับคำขอระบบจะเรียกใช้งานดังนี้


 runner, err := languages.GetRunner(req.Language)


และรับตัวรันเนอร์ที่สอดคล้องเพื่อดำเนินการโค้ด


2. การเปิดตัวคอนเทนเนอร์ Docker เพื่อดำเนินการโค้ด

สำหรับคำขอรหัสผู้ใช้แต่ละราย จะมีการสร้างคอนเทนเนอร์ Docker แยกต่างหาก ซึ่งจะดำเนินการภายในเมธอดรันเนอร์ (ตัวอย่างเช่น ใน Run) ตรรกะหลักในการรันคอนเทนเนอร์อยู่ในฟังก์ชัน RunInDockerStreaming:


 package compiler import ( "bufio" "fmt" "io" "log" "os/exec" "time" ) func RunInDockerStreaming(image, dir, cmdStr string, logCh chan < -string) error { timeout: = 50 * time.Second cmd: = exec.Command("docker", "run", "--memory=256m", "--cpus=0.5", "--network=none", "-v", fmt.Sprintf("%s:/app", dir), "-w", "/app", image, "sh", "-c", cmdStr) cmd.Stdin = nil stdoutPipe, err: = cmd.StdoutPipe() if err != nil { return fmt.Errorf("error getting stdout: %v", err) } stderrPipe, err: = cmd.StderrPipe() if err != nil { return fmt.Errorf("error getting stderr: %v", err) } if err: = cmd.Start();err != nil { return fmt.Errorf("Error starting command: %v", err) } // Reading logs from the container go func() { reader: = bufio.NewReader(io.MultiReader(stdoutPipe, stderrPipe)) for { line, isPrefix, err: = reader.ReadLine() if err != nil { if err != io.EOF { logCh < -fmt.Sprintf("[Error reading logs: %v]", err) } break } msg: = string(line) for isPrefix { more, morePrefix, err: = reader.ReadLine() if err != nil { break } msg += string(more) isPrefix = morePrefix } logCh < -msg } close(logCh) }() doneCh: = make(chan error, 1) go func() { doneCh < -cmd.Wait() }() select { case err: = < -doneCh: return err case <-time.After(timeout): if cmd.Process != nil { cmd.Process.Kill() } return fmt.Errorf("Execution timed out") } }


ฟังก์ชันนี้จะสร้างคำสั่ง docker run โดยที่:


  • image เป็นภาพ Docker ที่เลือกสำหรับภาษาเฉพาะ (กำหนดโดยการกำหนดค่าตัวรันเนอร์)
  • dir คือไดเร็กทอรีที่มีรหัสที่สร้างขึ้นสำหรับคำขอนี้
  • cmdStr คือคำสั่งสำหรับการคอมไพล์หรือดำเนินการโค้ด


ดังนั้นเมื่อเรียกใช้เมธอด Run ของตัวเรียกใช้งาน จะเกิดขึ้นต่อไปนี้:


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


3. กระบวนการดำเนินการแบบบูรณาการ

ย่อส่วนของตรรกะหลักของการทำงานของโค้ด (executor.ExecuteCode):


 func ExecuteCode(ctx context.Context, req CodeRequest, logCh chan string) CodeResponse { // Create a temporary directory and write files projectDir, err: = util.CreateTempProjectDir() if err != nil { return CodeResponse { "", fmt.Sprintf("Error: %v", err) } } defer os.RemoveAll(projectDir) for fileName, content: = range req.Files { util.WriteFileRecursive(filepath.Join(projectDir, fileName), [] byte(content)) } // Get a runner for the selected language runner, err: = languages.GetRunner(req.Language) if err != nil { return CodeResponse { "", err.Error() } } if err: = runner.Validate(projectDir); err != nil { return CodeResponse { "", fmt.Sprintf("Validation error: %v", err) } } // Compile (if needed) and run code in Docker container compileCh, _: = runner.Compile(ctx, projectDir) for msg: = range compileCh { logCh < -"[Compilation]: " + msg } runCh, _: = runner.Run(ctx, projectDir) var output string for msg: = range runCh​​ { logCh < -"[Run]: " + msg output += msg + "\n" } return CodeResponse { Output: output } }


ในตัวอย่างขั้นต่ำนี้:


  • การตรวจจับภาษาจะดำเนินการโดยเรียก languages.GetRunner(req.Language) ซึ่งช่วยให้สามารถเพิ่มการรองรับสำหรับภาษาใหม่ได้อย่างง่ายดาย
  • การเปิดตัวคอนเทนเนอร์ Docker ถูกนำมาใช้ภายในวิธีการ Compile/Run ซึ่งใช้ RunInDockerStreaming เพื่อรันโค้ดแบบแยกส่วน


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

7. บทสรุป

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


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


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



ผู้แต่ง : โอเล็กซี บอนดาร์
วันที่ : 2025-02-07