gRPC กับ REST: เริ่มต้นใช้งานโปรโตคอล API ที่ดีที่สุด
เผยแพร่แล้ว: 2022-07-22ในแนวเทคโนโลยีในปัจจุบัน โครงการส่วนใหญ่ต้องการการใช้ API APIs เชื่อมโยงการสื่อสารระหว่างบริการต่างๆ ที่อาจเป็นตัวแทนของระบบเดียวที่ซับซ้อน แต่อาจอยู่ในเครื่องที่แยกจากกัน หรือใช้เครือข่ายหรือภาษาที่เข้ากันไม่ได้หลายเครื่อง
เทคโนโลยีมาตรฐานจำนวนมากตอบสนองความต้องการด้านการสื่อสารระหว่างบริการของระบบแบบกระจาย เช่น REST, SOAP, GraphQL หรือ gRPC แม้ว่า REST จะเป็นวิธีที่ได้รับความนิยม แต่ gRPC ก็เป็นคู่แข่งที่คู่ควร โดยนำเสนอประสิทธิภาพสูง สัญญาที่พิมพ์ได้ และเครื่องมือที่ยอดเยี่ยม
ภาพรวมส่วนที่เหลือ
การถ่ายโอนสถานะตัวแทน (REST) เป็นวิธีการดึงหรือจัดการข้อมูลของบริการ โดยทั่วไป REST API ถูกสร้างขึ้นบนโปรโตคอล HTTP โดยใช้ URI เพื่อเลือกทรัพยากรและกริยา HTTP (เช่น GET, PUT, POST) เพื่อเลือกการดำเนินการที่ต้องการ เนื้อหาคำขอและการตอบสนองมีข้อมูลเฉพาะสำหรับการดำเนินการ ในขณะที่ส่วนหัวให้ข้อมูลเมตา มาดูตัวอย่างง่ายๆ ของการดึงข้อมูลผลิตภัณฑ์ผ่าน REST API
ที่นี่ เราขอทรัพยากรผลิตภัณฑ์ที่มีรหัส 11
และสั่งให้ API ตอบสนองในรูปแบบ JSON:
GET /products/11 HTTP/1.1 Accept: application/json
เมื่อได้รับคำขอนี้ คำตอบของเรา (ละเว้นส่วนหัวที่ไม่เกี่ยวข้อง) อาจมีลักษณะดังนี้:
HTTP/1.1 200 OK Content-Type: application/json { id: 11, name: "Purple Bowtie", sku: "purbow", price: { amount: 100, currencyCode: "USD" } }
แม้ว่า JSON อาจอ่านได้โดยมนุษย์ แต่ก็ไม่เหมาะสมเมื่อใช้ระหว่างบริการต่างๆ ลักษณะซ้ำๆ ของการอ้างอิงชื่อพร็อพเพอร์ตี้ แม้จะบีบอัดแล้วก็ตาม อาจนำไปสู่ข้อความที่ป่องได้ ลองดูทางเลือกอื่นเพื่อจัดการกับข้อกังวลนี้
ภาพรวม gRPC
gRPC Remote Procedure Call (gRPC) เป็นโปรโตคอลการสื่อสารข้ามแพลตฟอร์มแบบโอเพนซอร์สที่อิงตามสัญญา ซึ่งช่วยลดความยุ่งยากและจัดการการสื่อสารระหว่างบริการโดยเปิดเผยชุดของฟังก์ชันต่อไคลเอ็นต์ภายนอก
gRPC สร้างขึ้นบน HTTP/2 โดยใช้ประโยชน์จากคุณสมบัติต่างๆ เช่น การสตรีมแบบสองทิศทางและ Transport Layer Security (TLS) ในตัว gRPC ช่วยให้สามารถสื่อสารได้อย่างมีประสิทธิภาพมากขึ้นผ่านเพย์โหลดไบนารีแบบซีเรียลไลซ์ โดยค่าเริ่มต้นจะใช้บัฟเฟอร์โปรโตคอลเป็นกลไกสำหรับการจัดลำดับข้อมูลที่มีโครงสร้าง ซึ่งคล้ายกับการใช้ JSON ของ REST
อย่างไรก็ตาม บัฟเฟอร์โปรโตคอลต่างจาก JSON มากกว่ารูปแบบซีเรียลไลซ์ ประกอบด้วยส่วนสำคัญอื่นๆ อีกสามส่วน:
- ภาษาคำจำกัดความของสัญญาที่พบในไฟล์ .
.proto
(เราจะทำตาม proto3 ซึ่งเป็นข้อกำหนดภาษาบัฟเฟอร์โปรโตคอลล่าสุด) - รหัสฟังก์ชั่นการเข้าถึงที่สร้างขึ้น
- ไลบรารีรันไทม์เฉพาะภาษา
ฟังก์ชันระยะไกลที่มีอยู่ในบริการ (กำหนดไว้ในไฟล์ .proto
) จะแสดงรายการภายในโหนดบริการในไฟล์บัฟเฟอร์ของโปรโตคอล ในฐานะนักพัฒนา เราจะต้องกำหนดฟังก์ชันเหล่านี้และพารามิเตอร์โดยใช้ระบบ Rich Type ของบัฟเฟอร์โปรโตคอล ระบบนี้สนับสนุนประเภทตัวเลขและวันที่ รายการ พจนานุกรม และค่า nullables ต่างๆ เพื่อกำหนดข้อความอินพุตและเอาต์พุตของเรา
ข้อกำหนดบริการเหล่านี้ต้องพร้อมใช้งานสำหรับทั้งเซิร์ฟเวอร์และไคลเอ็นต์ ขออภัย ไม่มีกลไกเริ่มต้นในการแบ่งปันคำจำกัดความเหล่านี้ นอกเหนือจากการให้การเข้าถึงโดยตรงไปยังไฟล์ . .proto
ไฟล์ .proto
ตัวอย่างนี้กำหนดฟังก์ชันเพื่อส่งคืนรายการผลิตภัณฑ์ โดยระบุ ID:
การพิมพ์ที่เข้มงวดและการจัดลำดับฟิลด์ของ proto3 ทำให้การดีซีเรียลไลเซชันข้อความมีการเก็บภาษีน้อยกว่าการแยกวิเคราะห์ JSON
การเปรียบเทียบ REST กับ gRPC
สรุป จุดที่สำคัญที่สุดเมื่อเปรียบเทียบ REST กับ gRPC คือ:
พักผ่อน | gRPC | |
---|---|---|
ข้ามแพลตฟอร์ม | ใช่ | ใช่ |
รูปแบบข้อความ | กำหนดเองแต่โดยทั่วไป JSON หรือ XML | บัฟเฟอร์โปรโตคอล |
ขนาดเพย์โหลดข้อความ | กลาง/ใหญ่ | เล็ก |
ความซับซ้อนในการประมวลผล | สูงกว่า (การแยกวิเคราะห์ข้อความ) | ต่ำกว่า (โครงสร้างไบนารีที่กำหนดไว้อย่างดี) |
รองรับเบราว์เซอร์ | ใช่ (ดั้งเดิม) | ใช่ (ผ่าน gRPC-เว็บ) |
ในกรณีที่คาดว่าจะมีสัญญาที่เข้มงวดน้อยกว่าและต้องเพิ่มน้ำหนักบรรทุกบ่อยครั้ง JSON และ REST นั้นเหมาะสมอย่างยิ่ง เมื่อสัญญามีแนวโน้มที่จะคงที่มากขึ้นและความเร็วมีความสำคัญสูงสุด โดยทั่วไป gRPC จะชนะ ในโครงการส่วนใหญ่ที่ฉันทำงานอยู่ gRPC ได้รับการพิสูจน์แล้วว่าเบากว่าและมีประสิทธิภาพมากกว่า REST
การใช้งานบริการ gRPC
มาสร้างโปรเจ็กต์ที่มีความคล่องตัวเพื่อสำรวจว่าการนำ gRPC มาใช้นั้นง่ายเพียงใด
การสร้างโครงการ API
ในการเริ่มต้น เราจะสร้างโปรเจ็กต์ .NET 6 ใน Visual Studio 2022 Community Edition (VS) เราจะเลือกเทมเพลต ASP.NET Core gRPC Service และตั้งชื่อทั้งโปรเจ็กต์ (เราจะใช้ InventoryAPI
) และโซลูชันแรกของเราภายในนั้น ( Inventory
)
ทีนี้มาเลือกกัน NET 6.0 (การสนับสนุนระยะยาว) ตัวเลือกสำหรับเฟรมเวิร์กของเรา:
การกำหนดบริการผลิตภัณฑ์ของเรา
ตอนนี้เราได้สร้างโครงการแล้ว VS จะแสดงตัวอย่างบริการนิยามต้นแบบ gRPC ชื่อ Greeter
เราจะนำไฟล์หลักของ Greeter
กลับมาใช้ใหม่เพื่อให้เหมาะกับความต้องการของเรา
- ในการสร้างสัญญาของเรา เราจะแทนที่เนื้อหาของ
greet.proto
ด้วย Snippet 1 โดยเปลี่ยนชื่อไฟล์product.proto
- ในการสร้างบริการของเรา เราจะแทนที่เนื้อหาของไฟล์
GreeterService.cs
ด้วย Snippet 2 โดยเปลี่ยนชื่อไฟล์ProductCatalogService.cs
บริการส่งคืนผลิตภัณฑ์แบบฮาร์ดโค้ดแล้ว เพื่อให้การบริการทำงานได้ เราต้องเปลี่ยนการลงทะเบียนบริการใน Program.cs
เพื่ออ้างอิงชื่อบริการใหม่เท่านั้น ในกรณีของเรา เราจะเปลี่ยนชื่อ app.MapGrpcService<GreeterService>();
ไปที่ app.MapGrpcService<ProductCatalogService>();
เพื่อให้ API ใหม่ของเราทำงานได้
คำเตือนที่เป็นธรรม: ไม่ใช่การทดสอบโปรโตคอลมาตรฐานของคุณ
แม้ว่าเราอาจถูกล่อลวงให้ลองใช้งาน แต่เราไม่สามารถทดสอบบริการ gRPC ของเราผ่านเบราว์เซอร์ที่มุ่งไปที่ปลายทางได้ หากเราพยายามทำเช่นนี้ เราจะได้รับข้อความแสดงข้อผิดพลาดที่ระบุว่าการสื่อสารกับปลายทาง gRPC ต้องทำผ่านไคลเอ็นต์ gRPC
การสร้างลูกค้า
ในการทดสอบบริการของเรา ให้ใช้เทมเพลต Console App พื้นฐานของ VS และสร้างไคลเอ็นต์ gRPC เพื่อเรียกใช้ API ฉันตั้งชื่อ InventoryApp
ของฉัน
เพื่อความได้เปรียบ ให้อ้างอิงเส้นทางของไฟล์ที่เกี่ยวข้องซึ่งเราจะแบ่งปันสัญญาของเรา เราจะเพิ่มการอ้างอิงด้วยตนเองในไฟล์ .csproj
จากนั้น เราจะอัปเดตเส้นทางและตั้งค่าโหมด Client
หมายเหตุ: ฉันแนะนำให้คุณทำความคุ้นเคยและมั่นใจในโครงสร้างโฟลเดอร์ในเครื่องของคุณก่อนที่จะใช้การอ้างอิงแบบสัมพัทธ์
ต่อไปนี้คือข้อมูลอ้างอิง .proto
ตามที่ปรากฏในไฟล์บริการและโปรเจ็กต์ไคลเอ็นต์:
ไฟล์โครงการบริการ (รหัสที่จะคัดลอกไปยังไฟล์โครงการของลูกค้า) | ไฟล์โครงการลูกค้า (หลังจากวางและแก้ไข) |
---|---|
|
|
ตอนนี้ เพื่อเรียกใช้บริการของเรา เราจะแทนที่เนื้อหาของ Program.cs
รหัสของเราจะบรรลุวัตถุประสงค์หลายประการ:
- สร้างแชนเนลที่แสดงตำแหน่งของจุดปลายของบริการ (พอร์ตอาจแตกต่างกันไป ดังนั้นโปรดอ่านไฟล์
launchsettings.json
สำหรับค่าจริง) - สร้างวัตถุไคลเอนต์
- สร้างคำของ่ายๆ
- ส่งคำขอ
เตรียมเปิดตัว
ในการทดสอบโค้ดของเรา ใน VS เราจะคลิกขวาที่โซลูชันและเลือก Set Startup Projects ในกล่องโต้ตอบหน้าคุณสมบัติของโซลูชัน เราจะ:
- เลือกปุ่มตัวเลือกข้าง Multiple startupโปรเจ็ กต์ และในเมนูดรอปดาวน์ Action ตั้งค่าทั้งสองโปรเจ็กต์ (
InventoryAPI
และInventoryApp
) เป็น Start - คลิก ตกลง
ตอนนี้ เราสามารถเริ่มวิธีแก้ปัญหาโดยคลิก เริ่ม ในแถบเครื่องมือ VS (หรือโดยการกดปุ่ม F5 ) หน้าต่างคอนโซลใหม่สองบานจะแสดงขึ้น: อันหนึ่งเพื่อบอกเราว่าบริการกำลังฟังอยู่ อีกบานหนึ่งเพื่อแสดงรายละเอียดของผลิตภัณฑ์ที่ดึงมา
การแบ่งปันสัญญา gRPC
ตอนนี้ ลองใช้วิธีอื่นในการเชื่อมต่อไคลเอ็นต์ gRPC กับคำจำกัดความของบริการของเรา โซลูชันการแชร์สัญญาที่ลูกค้าเข้าถึงได้มากที่สุดคือการทำให้คำจำกัดความของเราพร้อมใช้งานผ่าน URL ตัวเลือกอื่นอาจเปราะบางมาก (ไฟล์ที่แชร์ผ่านพาธ) หรือต้องใช้ความพยายามมากขึ้น (สัญญาที่แชร์ผ่านแพ็กเกจดั้งเดิม) การแชร์ผ่าน URL (เช่น SOAP และ Swagger/OpenAPI) มีความยืดหยุ่นและต้องใช้โค้ดน้อยกว่า
ในการเริ่มต้น ให้ไฟล์ .proto
พร้อมใช้งานเป็นเนื้อหาแบบคงที่ เราจะอัปเดตโค้ดของเราด้วยตนเองเนื่องจาก UI ในการดำเนินการบิลด์ถูกตั้งค่าเป็น "Protobuf Compiler" การเปลี่ยนแปลงนี้สั่งให้คอมไพเลอร์คัดลอกไฟล์ .proto
เพื่อให้สามารถให้บริการจากที่อยู่เว็บได้ หากการตั้งค่านี้เปลี่ยนแปลงผ่าน VS UI บิลด์จะพัง ขั้นตอนแรกของเราคือการเพิ่ม Snippet 4 ลงในไฟล์ InventoryAPI.csproj
:
ต่อไป เราแทรกโค้ดใน Snippet 5 ที่ด้านบนของไฟล์ ProductCatalogService.cs
เพื่อตั้งค่าปลายทางเพื่อส่งคืนไฟล์ .proto
ของเรา:
และตอนนี้ เราได้เพิ่ม Snippet 6 ก่อน app.Run()
ในไฟล์ ProductCatalogService.cs
ด้วย:
เมื่อเพิ่ม Snippets 4-6 แล้ว เนื้อหาของไฟล์ .proto
ควรจะมองเห็นได้ในเบราว์เซอร์
ลูกค้าทดสอบใหม่
ตอนนี้ เราต้องการสร้างไคลเอนต์คอนโซลใหม่ที่เราจะเชื่อมต่อกับเซิร์ฟเวอร์ที่มีอยู่ของเราด้วยตัวช่วยสร้างการพึ่งพาของ VS ปัญหาคือวิซาร์ดนี้ไม่พูดถึง HTTP/2 ดังนั้นเราจึงต้องปรับเซิร์ฟเวอร์ของเราให้สามารถพูดคุยผ่าน HTTP/1 และเริ่มเซิร์ฟเวอร์ได้ เมื่อเซิร์ฟเวอร์ของเราสร้างไฟล์ .proto
ให้ใช้งานได้แล้ว เราจึงสามารถสร้างไคลเอนต์ทดสอบใหม่ที่เชื่อมต่อกับเซิร์ฟเวอร์ของเราผ่านวิซาร์ด gRPC
- หากต้องการเปลี่ยนเซิร์ฟเวอร์ของเราให้พูดผ่าน HTTP/1 เราจะแก้ไขไฟล์
appsettings.json
JSON ของเรา:- ปรับฟิลด์
Protocol
(อยู่ที่เส้นทางKestrel.EndpointDefaults.Protocols
) เพื่ออ่านHttps
- บันทึกไฟล์.
- ปรับฟิลด์
- เพื่อให้ลูกค้าใหม่ของเราอ่านข้อมูล
proto
นี้ เซิร์ฟเวอร์ต้องทำงานอยู่ เดิมที เราเริ่มต้นทั้งไคลเอนต์ก่อนหน้าและเซิร์ฟเวอร์ของเราจากกล่องโต้ตอบ Set Startup Projects ของ VS ปรับโซลูชันเซิร์ฟเวอร์เพื่อเริ่มเฉพาะโครงการเซิร์ฟเวอร์ จากนั้นเริ่มโซลูชัน (ตอนนี้เราได้แก้ไขเวอร์ชัน HTTP แล้ว ไคลเอ็นต์เก่าของเราไม่สามารถสื่อสารกับเซิร์ฟเวอร์ได้อีกต่อไป) - ถัดไป สร้างไคลเอนต์ทดสอบใหม่ เปิดอินสแตนซ์อื่นของ VS เราจะทำซ้ำขั้นตอนตามรายละเอียดในส่วน การสร้างโครงการ API แต่คราวนี้เราจะเลือกเทมเพลต แอปคอนโซล เราจะตั้งชื่อโครงการและโซลูชันของเรา
InventoryAppConnected
- เมื่อสร้างแชสซีไคลเอ็นต์แล้ว เราจะเชื่อมต่อกับเซิร์ฟเวอร์ gRPC ของเรา ขยายโครงการใหม่ใน VS Solution Explorer
- คลิกขวาที่ Dependencies และในเมนูบริบท ให้เลือก Manage Connected Services
- บนแท็บ Connected Services ให้คลิก Add a service reference แล้วเลือก gRPC
- ในกล่องโต้ตอบเพิ่มการอ้างอิงบริการ ให้เลือกตัวเลือก URL และป้อนเวอร์ชัน
http
ของที่อยู่บริการ (อย่าลืมดึงหมายเลขพอร์ตที่สร้างแบบสุ่มจากlaunchsettings.json
) - คลิก เสร็จสิ้น เพื่อเพิ่มการอ้างอิงบริการที่สามารถดูแลรักษาได้ง่าย
อย่าลังเลที่จะตรวจสอบงานของคุณกับโค้ดตัวอย่างสำหรับตัวอย่างนี้ เนื่องจากภายใต้ประทุน VS ได้สร้างไคลเอนต์เดียวกันกับที่เราใช้ในการทดสอบรอบแรกของเรา เราจึงสามารถใช้เนื้อหาของไฟล์ Program.cs
ซ้ำจากคำต่อคำของบริการก่อนหน้าได้
เมื่อเราเปลี่ยนสัญญา เราจำเป็นต้องแก้ไขข้อกำหนด .proto
ของลูกค้าเพื่อให้ตรงกับคำจำกัดความ .proto ที่อัปเดต ในการดำเนินการดังกล่าว เราจำเป็นต้องเข้าถึง Connected Services ของ VS และรีเฟรชรายการบริการที่เกี่ยวข้องเท่านั้น ตอนนี้ โปรเจ็กต์ gRPC ของเราเสร็จสมบูรณ์แล้ว และง่ายต่อการซิงค์บริการและไคลเอ็นต์ของเรา
ผู้สมัครโครงการต่อไปของคุณ: gRPC
การใช้งาน gRPC ของเราช่วยให้เห็นประโยชน์ของการใช้ gRPC ได้โดยตรง REST และ gRPC ต่างก็มีกรณีการใช้งานที่เหมาะสมที่สุด ขึ้นอยู่กับประเภทของสัญญา อย่างไรก็ตาม เมื่อทั้งสองตัวเลือกเหมาะสม เราขอแนะนำให้คุณลองใช้ gRPC ซึ่งจะทำให้คุณล้ำหน้าในอนาคตของ API