[gRPC] A high performance, open-source universal RPC framework (Theory)
ทุกวันนี้เทรนด์ของการสร้างระบบเป็น microservices ยิ่งมาแรงขึ้นเรื่อยๆ ซึ่งการสร้าง microservices นั้นอาจจะถูกเขียนขึ้นมาจากหลากหลายภาษา แต่ microservices จะต้องสามารถที่จะสื่อสารไปมาระหว่างกันได้ การที่ microservice แลกเปลี่ยนข้อมูลระหว่างกัน จะต้องมีกฎบางอย่างที่ตกลงกันเช่น
- API endpoint ที่ใช้
- Format ของ ข้อมูลที่จะรับหรือส่ง
- รูปแบบของ Error ที่ต้องจัดการ
- การทำ Load Balancing
- และอื่นๆ
ตัวอย่างที่มีความนิยมสูงในการสร้าง API ก็คือ REST (HTTP-JSON)
การสร้าง API นั้นเป็นเรื่องที่ไม่ง่าย ผมจะยกตัวอย่างว่ามีปัจจัยอะไรบ้างที่ต้องพิจารณา
- จะใช้ data model แบบไหน? (JSON, XML, Binary)
- ออกแบบ endpoint อย่างไร?(GET, POST : /api/v1/user/123/post/456)
- จะเรียกใช้มันอย่างไร และรับมือกับ Error อย่างไร?
- ต้องคิดถึงเรื่องประสิทธิภาพ เช่น จำนวนข้อมูลที่รับได้มากสุดในการเรียก 1 ครั้ง, ข้อมูลที่ได้มามีมากเกินไปหรือน้อยเกินไป?, ถ้าข้อมูลน้อยเกินไปสร้างหลายๆ API ดีไหม? เป็นต้น
- แล้วเรื่อง Latency ล่ะ?
- ถ้าต้องการ scale ให้รองรับ client จำนวน 1000 clients เข้าใช้งานพร้อมกันจะทำยังไง?
- การทำ Load balancing
- การคุยกันของ service ที่ถูกเขียนขึ้นมาจากหลายภาษา
- การทำ Authentication, Monitoring, Logging และอื่นๆ
เริ่มเห็นแล้วใช่ไหมว่าเรามีงานที่ต้องทำหลายอย่างมากๆ
แล้วถ้าเรามี Framework มาช่วยจัดการปัญหาเหล่านี้ล่ะคงจะดีเลยไม่น้อย ใช่แล้ว มันคือ gRPC Framework ซึ่งวันนี้เราจะมาทำความรู้จักกับ gRPC กันว่ามันคืออะไร
gRPC คืออะไร?
- gRPC เป็นโปรเจค open-source ที่ใช้งานฟรีและถูกพัฒนาโดย Google
- gRPC เป็นส่วนหนึ่งของ the Cloud Native Computation Foundation (CNCF) เช่นเดียวกับ Docker และ Kubernetes
- gRPC เป็น High level programming เราสามารถที่จะ define Request และ Response สำหรับ RPC (Remote Procedure Calls) ส่วนที่เหลือมันจะจัดการให้เรา
- บน gRPC นั้นใช้เทคโนโลยี HTTP/2, low latency, รองรับ Streaming, language dependent ทำให้ง่ายต่อการนำไปทำอย่างอื่นเช่น การทำ authentication, load balancing, logging และ monitoring
RPC คืออะไร?
- RPC คือ Remote Procedure Call
- ถ้ามองโค้ดในส่วนของ client มันคล้ายกับเราเรียกใช้ฟังก์ชันที่อยู่บนเซิร์ฟเวอร์ (แค่คล้ายนะ)
- RPC ไม่ใช่ new concept (Common Object Request Broker Architecture หรือ CORBA เคยทำมาก่อน)
- gRPC มันถูกพัฒนาขึ้นมาให้ใช้งานแบบเรียบง่าย และแก้ไขปัญหาต่างๆ ที่เป็น pain point มากมายก่อนหน้านี้
จากรูปด้านบนจะเห็นได้ว่าในแต่ละ service ได้ถูก implement มาจากภาษาที่แตกต่างกัน (C++, Ruby, Java) แต่สามารถคุยกันได้แค่เอา gRPC interface มาจัดการเรื่อง request, response และในโค้ดส่วนอื่นๆ ยังคงเหมือนเดิม
แล้วเราจะเริ่มมันยังไงดี?
สิ่งที่ขาดไม่ได้เลยคือจะต้อง define message ที่จะใช้ส่งหากันโดยใช้สิ่งที่เรียกว่า Protocol Buffers ซึ่งส่วนที่เหลือของโค้ดจะถูก generate ให้เรา เราแค่นำส่วนที่ถูก generate ออกมาไปใช้ต่อ (ขึ้นอยู่กับภาษาที่สั่งให้ compile)
ไฟล์ .proto 1 ไฟล์ สามารถที่จะ generate ออกมาได้ถึง 12 ภาษา (ทั้ง server และ client)
เรามาดูตัวอย่าง code ไฟล์ .proto กัน
จากรูปจะเห็นได้ว่า เรา define service ที่ชื่อว่า GreetService โดยรับ GreetRequest และ return เป็น GreetResponse ซึ่ง GreetRequest ถูก define ว่ามีตัวแปรชื่อว่า greeting ชนิดของข้อมูลเป็น Greeting ซึ่งภายในประกอบด้วย string 2 ตัวคือ first_name กับ last_name (ใน GreetRequest สามารถใส่ string 2 ตัวนี้ได้เลยโดยไม่ต้องสร้างตัวแปรประเภท Greeting เพิ่ม แต่นี่ต้องการแสดงให้เห็นว่าสามารถ define type เป็น structure เพิ่มได้) ส่วน GreetResponse จะ return string result
ข้อสังเกตอีก 1 อย่างคือ หลังเครื่องหมายเท่ากับ จะมีหมายเลขกำกับไว้ซึ่งหมายถึงลำดับของตัวแปรต้องเรียงจาก 1 ไปถึง n ห้ามข้ามเด็ดขาด (เกี่ยวกับการส่งข้อมูลเป็น binary แบบ serialized ซึ่งจะไม่ขอพูดในบทความนี้)
ทำไมต้องใช้ Protocol Buffers?
- Protocol Buffers เป็นภาษาที่ไม่ขึ้นอยู่กับภาษาอื่นๆ (angostic language ไม่รู้จะแปลว่ายังไงดี 555)
- โค้ดสามารถถูก generate ให้เป็นภาษาอื่นๆ ได้ (อย่างที่เคยพูดไว้ก่อนหน้านี้)
- ข้อมูลที่ถูกส่งเป็น Binary serialized (payloads ขนาดเล็กมาก)
- สะดวกในการส่งข้อมูลจำนวนมาก
ทำไมเราต้องเรียนรู้มัน?
- หลายบริษัทได้ใช้ gRPC ใน production เช่น Google, Netflix, Square, CoreOS, CoackroachDB เป็นต้น
- gRPC เป็นอนาคตของ microservices API และ mobile-server API (และอาจเป็น Web APIs ในอนาคตด้วย)
API บน gRPC มีทั้งหมด 4 ประเภท
1. Unary
แบบแรกคือแบบ Unary ซึ่งก็คือ one request one response คล้ายๆ กับ traditional API (HTTP REST) ที่เราคุ้นเคยกันในชีวิตประจำวัน เช่น client ขอรายชื่อหนังสือ server ให้รายชื่อหนังสือกลับมา เป็นต้น
2. Server Streaming
Server Streaming คือ one request multiple responses ซึ่งใช้ความสามารถของ HTTP/2 ที่เราเคยพูดถึงก่อนหน้านี้ ซึ่งทั้ง client และ server สามารถที่จะตัด connection stream ได้ เช่น client ได้รับข้อมูลครบถ้วนแล้ว หรือ server ส่งข้อมูลครบแล้ว
3. Client Streaming
Client Streaming คือ multiple requests one response จะตรงข้ามกับ Server Streaming ซึ่ง client จะเป็นฝ่ายส่งข้อมูลไปยัง server โดย client สามารถจะหยุดส่งตอนไหนก็ได้แล้วแต่จะกำหนดไว้หรือ server เป็นฝ่ายบอกให้หยุดส่งก็ได้เช่นกัน (ไม่จำเป็นว่า client ต้องส่งข้อมูลให้หมดถึงจะได้รับ response จาก server)
4. Bi-Directional Streaming
Bi-Directional Streaming คือ multiple requests multiple response เป็นการส่งข้อมูลแบบ asynchronous เช่น จากภาพมีข้อมูลที่ส่งไป 4 ชุด client อาจจะส่งข้อมูลชุดแรกไปแล้วได้ response อันแรกกลับมาทันที ทำแบบนี้ไปเรื่อยๆ ไม่จำเป็นต้องรอให้ส่งครบทุกชุดก่อน use case ที่นำไปใช้ เช่นทำระบบ chat เป็นต้น
มาดูไฟล์ .proto กันว่าเราจะ define service แต่ละประเภทกันยังไง
จากภาพจะเห็นว่าสามารถที่จะมองแล้วเข้าใจความหมายได้เลยว่ารับ request เป็นอะไรแล้ว return response เป็นอะไร หากมีคำว่า stream อยู่แสดงว่าเป็นการส่งข้อมูลเป็น stream
ในบทความถัดไปเราจะพูดถึงการ implement gRPC API ทั้ง 4 ประเภท => มาฝึกเขียน gRPC กัน (Hands-On)
มาดูเรื่อง Scalability ของ gRPC กันบ้าง
gRPC เป็น asynchronous โดย default ซึ่งหมายความว่าจะไม่มีการ block thread ขณะที่มี request ดังนั้น gRPC server สามารถที่จะ serve request จำนวนมากๆ แบบ parallel ในส่วนของ gRPC client สามารถเป็นได้ทั้ง asynchronous และ synchronous (blocking) ซึ่งอาจจะต้องตัดสินใจว่าแบบไหน perfomance ดีที่สุด และความสามารถของ gRPC client คือมี load balancing ในฝั่ง client ให้ด้วย
สิ่งที่ยืนยันว่าประโยคข้างบนนี้เป็นจริงคือ ปัจจุบัน Google มี 10 พันล้าน requests ต่อวินาทีที่ request กันอยู่แบบ internal
แล้วเรื่อง Security ล่ะ
โดย default ของ gRPC นั้นสนับสนุนให้ใช้ SSL (encryption over the wire) สำหรับทุกๆ API อยู่แล้ว ซึ่งหมายความว่า gRPC อยู่ในระดับที่เรียกว่าเป็น first class citizen และทุกๆ ภาษาที่จะใช้งาน gRPC จะ require certificates และรองรับการ encryption ในตัวอยู่แล้ว แทบไม่ต้องทำอะไรเลย หากต้องการจำกัดให้เรียกใช้งานกันได้เฉพาะที่อนุญาต ก็สามารถ implement authentication เพิ่มเติมได้ เรียกได้ว่าค่อนข้างจะปลอดภัย
มาเปรียบเทียบให้เห็นกัน จะ จะ ระหว่าง gRPC vs REST
gRPC มีประสิทธิภาพมากกว่า REST API ถึง 25 เท่า (พิจารณาจากระยะเวลาระหว่าง request กับ response อ่านเพิ่มเติมได้จาก https://husobee.github.io/golang/rest/grpc/2016/05/28/golang-rest-v-grpc.html)
สรุป ทำไมเราถึงใช้ gRPC
- เขียนโค้ดไฟล์ .proto เพื่อ define service และ variable แค่ไฟล์เดียว แต่สามารถ compile เพื่อนำไปใช้ร่วมกับภาษาอื่นๆ ได้ถึง 11 ภาษา
- ส่งข้อมูลบน HTTP/2 (อ่านต่อได้ที่ =>HTTP/2 คืออะไร)
- มีฟังก์ชันสำหรับ SSL built in มาให้
- รองรับ Streaming APIs
- gRPC เป็น API oriented ไม่ใช่ Resource oriented
Reference