Devfavor

Back

gRPC คืออะไร — เรียกฟังก์ชันข้ามเครื่องให้เหมือนเรียกในเครื่องตัวเองBlur image

ลองนึกถึงระบบที่มี service หลายสิบตัวคุยกันตลอดเวลา ทุกครั้งที่ service หนึ่งอยากได้ข้อมูลจากอีกตัว ก็ต้องสร้าง JSON ขึ้นมา ยิงผ่าน HTTP แล้วฝั่งรับก็แกะ JSON กลับเป็น object พอทำแบบนี้วันละหลายล้านครั้ง เวลาที่เสียไปกับการแปลงข้อมูลไปกลับก็เริ่มกลายเป็นต้นทุนจริงที่มองเห็นได้ในบิล

แล้วยังมีปัญหาเรื่องสัญญาด้วย — ฝั่งหนึ่งเปลี่ยนชื่อ field จาก userId เป็น user_id อีกฝั่งไม่รู้ ระบบไม่ฟ้องตอน compile แต่ไปพังตอน runtime กลางดึก กว่าจะรู้ว่าพังเพราะอะไรก็เสียเวลาไปหลายชั่วโมง

gRPC เกิดมาเพื่อแก้สองปัญหานี้พอดี แนวคิดหลักคือทำให้ client เรียก method บน server ที่อยู่คนละเครื่องได้เหมือนเรียกฟังก์ชันในเครื่องตัวเอง โดยข้อมูลที่วิ่งไปมาเป็น binary ขนาดเล็ก และมีสัญญา (contract) ที่ทั้งสองฝั่งต้องตกลงกันก่อนเสมอ

มาดูกันว่า gRPC ทำงานยังไง เหมาะกับงานแบบไหน และมีจุดที่ต้องระวังตรงไหนบ้างก่อนเอาไปใช้จริง


🤝 gRPC คืออะไรกันแน่#

gRPC คือ framework สำหรับ Remote Procedure Call (RPC) แบบ open source ที่เน้นประสิทธิภาพสูง สร้างขึ้นโดย Google และตอนนี้อยู่ภายใต้การดูแลของ Cloud Native Computing Foundation (CNCF)

หัวใจของแนวคิดอยู่ที่คำว่า RPC — client เรียก method บน server เครื่องอื่นได้ “เหมือน” เรียก object ในเครื่องตัวเอง เราเขียนโค้ดเรียกเหมือนเรียกฟังก์ชันธรรมดา แต่เบื้องหลังจริง ๆ คือการคุยข้ามเครื่อง การสร้าง distributed application เลยง่ายขึ้นมาก เพราะไม่ต้องมานั่งจัดการรายละเอียดของ network เองทุกครั้ง

ที่มาของ gRPC ไม่ใช่ของใหม่ที่เพิ่งคิดขึ้นมาลอย ๆ แต่ต่อยอดมาจากระบบ RPC ภายในของ Google ชื่อ Stubby ที่ใช้เชื่อม microservices ภายในและข้าม data center มากว่าสิบปี gRPC ถูก release ออกสู่สาธารณะครั้งแรกในปี 2015 ซึ่งเป็นปีเดียวกับที่ HTTP/2 ออกพอดี

ชื่อ gRPC เองก็เป็น recursive acronym ที่ย่อมาจาก “gRPC Remote Procedure Calls” — เล่นคำกับตัวเองนิดหน่อย ที่สนุกกว่านั้นคือตัว “g” ไม่ได้ถูกตรึงความหมายไว้ตายตัว แต่ละ release ทีมงานจะตีความ “g” ใหม่ทุกครั้ง เช่น “good”, “green” สลับกันไป


⚙️ สองเทคโนโลยีที่ทำให้ gRPC เร็ว#

gRPC ไม่ได้เร็วขึ้นมาเองลอย ๆ แต่มาจากการเลือกใช้สองอย่างนี้เป็นฐาน

อย่างแรกคือ HTTP/2 เป็น transport — HTTP/2 มี feature ชื่อ multiplexing ที่ส่งหลาย request และ response ผ่าน TCP connection เดียวได้พร้อมกัน บวกกับ header compression และ binary framing ทำให้ส่งข้อมูลได้มีประสิทธิภาพกว่า HTTP/1.1 ที่เราคุ้นเคยกันใน REST

อย่างที่สองคือ Protocol Buffers (Protobuf) — ตัวนี้ทำหน้าที่สองอย่างในเวลาเดียวกัน คือเป็นทั้ง IDL (Interface Definition Language) ที่ใช้นิยามว่า service มี method อะไรบ้าง และเป็นรูปแบบการ serialize ข้อมูลเป็น binary

จุดสำคัญคือ Protobuf serialize ข้อมูลเป็น binary ไม่ใช่ text แบบ JSON หรือ XML ข้อมูลเลยกะทัดรัดกว่ามาก ส่งเร็วกว่า และ serialize/deserialize ได้เร็วกว่าด้วย ตรงนี้ต้องแยกสองมิติให้ชัด เพราะมักถูกพูดปนกัน — ในแง่ ขนาด payload ตามแหล่งข้อมูล benchmark ทั่วไป Protobuf เล็กกว่า JSON ที่เทียบเท่ากันราว 3-5 เท่า (แล้วแต่ชนิดข้อมูล ถ้าเป็น string ล้วน ๆ บางกรณีอาจเล็กกว่าแค่ไม่กี่เปอร์เซ็นต์) ส่วนในแง่ ความเร็วในการ serialize/parse Protobuf เร็วกว่าได้ราว 3-10 เท่า และ benchmark บางตัวแสดงว่า p99 latency ต่ำกว่าเมื่อมี call volume สูง

มีแหล่งฝั่ง vendor (Kong) ที่ claim ว่า gRPC เร็วกว่า REST ได้ราว 7-10 เท่า ตัวเลขนี้เป็น claim ของผู้ขาย ไม่ใช่ benchmark กลาง เลยอยากให้รับไว้เป็นแนวทางคร่าว ๆ มากกว่าตัวเลขที่ยึดตายตัว


📝 หน้าตาของ .proto และวิธี implement#

เวลาเริ่มงานกับ gRPC เราไม่ได้เริ่มจากการเขียนโค้ด แต่เริ่มจากการนิยาม service ในไฟล์ .proto ก่อน วิธีคิดแบบนี้เรียกว่า contract-first คือตกลงสัญญากันให้ชัดก่อน แล้วค่อยลงมือ

ตัวอย่างนิยามแบบขั้นต่ำสุดหน้าตาประมาณนี้

service Greeter {
  rpc SayHello (HelloRequest) returns (HelloReply) {}
}

message HelloRequest {
  string name = 1;
}

message HelloReply {
  string message = 1;
}
proto

จากไฟล์นี้ เราใช้ compiler ชื่อ protoc generate code ฝั่ง client และ server ออกมาตามภาษาที่เลือก เช่นฝั่ง Go ใช้ flag --go_out และ --go-grpc_out จะได้ไฟล์ที่มีทั้งโค้ดสำหรับ populate/serialize message และโค้ด client/server ส่วนฝั่ง Python ใช้ package grpcio-tools ที่รวม protoc มาให้ พอ generate เสร็จก็แค่ implement service method แล้วสตาร์ท server (ใน Python มักสร้าง server ด้วย ThreadPoolExecutor แล้วเรียก server.start())

ข้อดีของวิธีนี้คือทั้งสองฝั่งทำงานจากสัญญาเดียวกัน ถ้า field ไม่ตรงกัน ระบบจะรู้ตั้งแต่ตอน generate code ไม่ใช่ไปพังตอน runtime

ส่วนภาษาที่ gRPC รองรับก็ครอบคลุมพอสมควร: C#/.NET, C++, Dart, Go, Java, Kotlin, Node, Objective-C, PHP, Python, Ruby, Rust และ Swift จุดนี้เลยทำให้ gRPC เหมาะกับระบบที่เขียนด้วยหลายภาษาปนกัน (polyglot)


🔄 4 รูปแบบการเรียกที่ gRPC ทำได้#

จุดที่ gRPC ทำได้มากกว่าการ request-response ธรรมดาคือเรื่อง streaming gRPC นิยามรูปแบบการเรียกไว้ 4 แบบ

  • Unary — client ส่ง 1 request ได้ 1 response เหมือนเรียกฟังก์ชันปกติ เป็นแบบที่ใช้บ่อยที่สุด
  • Server Streaming — client ส่ง request ครั้งเดียว แล้ว server ส่ง stream ของ message กลับมาเรื่อย ๆ จน stream หมด เหมาะกับการส่งข้อมูลที่ทยอยมา
  • Client Streaming — client เขียน sequence ของ message ส่งผ่าน stream แล้วรอ server ตอบ response เดียวตอนจบ
  • Bidirectional Streaming — ทั้งสองฝั่งมี stream อ่าน-เขียนของตัวเองที่ทำงานอิสระต่อกัน อ่าน/เขียนสลับลำดับกันได้ตามใจ

แบบสุดท้ายนี่แหละที่เป็นจุดเด่นจริง ๆ เพราะ REST ทำแบบนี้ไม่ได้ตรง ๆ การที่สองฝั่งคุยกันได้พร้อมกันแบบ full-duplex บน connection เดียวเปิดทางให้ทำงานแบบ real-time sync ได้สวยงาม


🎯 เอาไปใช้ตอนไหนถึงจะคุ้ม#

gRPC ไม่ใช่ของที่หยิบมาใช้แทน REST ได้ทุกที่ แต่มีโซนที่ gRPC โดดเด่นชัดเจน

Internal service-to-service — แนวปฏิบัติทั่วไปคือใช้ gRPC สำหรับการสื่อสารแบบ synchronous ระหว่าง microservices ภายใน เพราะได้ low latency, strong typing และ contract-based development ส่วน API ที่หันออกข้างนอก (external-facing) มักใช้ REST หรือ GraphQL มากกว่า

Use case จริงที่ยืนยันได้ มีหลายตัวอย่าง เช่น

  • Kubernetes — kubelet ในแต่ละ node ใช้ gRPC ผ่าน Container Runtime Interface (CRI) ทำหน้าที่เป็น client คุยกับ container runtime อย่าง containerd หรือ CRI-O บน node เดียวกัน (ผ่าน Unix socket) เพื่อจัดการ image และ lifecycle ของ container
  • Financial services — ส่ง real-time market data ให้ trader ที่ต้องการความเร็ว
  • Gaming — ใช้ bidirectional streaming sync ข้อมูลเกมระหว่าง server กับ client
  • IoT / connected devices — จัดการ data stream ต่อเนื่องจาก smart home, wearable หรือ industrial sensor
  • Mobile apps — payload เล็กและ latency ต่ำเข้ากันได้ดีกับสภาพ mobile network

นอกจากนี้ยังเหมาะกับงาน latency-sensitive อย่าง ML inference และ polyglot system ที่มีหลายภาษาทำงานร่วมกัน


⚖️ ข้อเสียและ tradeoff ที่ต้องชั่งใจ#

ของดีย่อมมีราคา gRPC ก็เหมือนกัน แก่นของ tradeoff สรุปได้ประมาณว่า เราแลก performance กับ contract ที่รัดกุม โดยยอมเสีย universality และความง่ายในการเริ่มต้นไป

  • รองรับ browser ได้จำกัด — browser ไม่เปิด HTTP/2 framing layer ในระดับต่ำพอที่ gRPC ต้องใช้สำหรับ trailer-based status ทำให้เรียก gRPC จาก browser ตรง ๆ ไม่ได้ ต้องใช้ gRPC-Web หรือ proxy คั่น ด้วยเหตุนี้ gRPC ส่วนใหญ่เลยอยู่ฝั่ง backend
  • debug ยากกว่า — payload เป็น binary ไม่ human-readable เปิดดูด้วยตาเปล่าไม่ได้แบบ JSON ต้องพึ่งเครื่องมือเสริมอย่าง gRPC CLI หรือ server reflection
  • learning curve สูง — ต้องเรียนรู้ Protobuf, tooling และดูแล .proto ที่ซับซ้อนขึ้นเมื่อระบบโต
  • กินทรัพยากรมากกว่า — ใช้ CPU/memory มากกว่า protocol อื่น เลยไม่ค่อยเหมาะกับ device ที่ทรัพยากรจำกัด

ถ้างานเป็น API ง่าย ๆ ที่ไม่ต้องการ streaming, ระบบ legacy ที่ไม่รองรับ gRPC หรือโปรเจกต์ที่พึ่งพา browser เป็นหลัก — REST มักจะเป็นทางเลือกที่เหมาะกว่า


🪤 Gotchas ที่เจอบ่อยตอนขึ้น production#

ตรงนี้คือส่วนที่เอกสาร quickstart ไม่ค่อยบอก แต่เจอจริงเมื่อระบบขึ้น production มาเก็บไว้ก่อนจะได้ไม่ต้องไปเจ็บตัวเอง

Load balancing เพี้ยน — HTTP/2 multiplex หลาย request บน connection เดียวที่อยู่ยาว ผลคือ Layer 4 load balancer ที่เคยใช้ได้ดีกับ HTTP/1 กระจายโหลดได้แย่ลงมาก เพราะมองเห็นแค่ connection ไม่เห็น request ข้างใน ต้องขยับไปใช้ L7 load balancer แทน

เรื่อง TLS — gRPC มักต้องใช้ TLS ตลอดทางจาก client ถึง server ทำให้ terminate TLS ที่ load balancer ตรง ๆ ไม่ได้ ฟีเจอร์อย่าง SSL offloading หรือ advanced routing เลยทำได้ยากขึ้น

Message size limit 4 MB — gRPC มี default message size limit ที่ 4 MB และ message ถูกโหลดเข้า memory ทั้งก้อน เลยควรเลี่ยง message ขนาดใหญ่ โดยเฉพาะในภาษาที่มี garbage collector

Connection ค้าง — long-lived connection อาจค้างไม่จบถ้าไม่ตั้ง keepalive และ timeout ให้ดี นำไปสู่ infinite timeout ได้ การ misconfigure timeout/retry/backoff ก็เกิดบ่อยตอนข้ามหลาย environment

จุดที่ทำให้งง — การแปลง Protobuf เป็น JSON จะตัด default value ออกจาก output ทำให้ client ที่คาดว่าทุก field จะมีค่าสับสนได้ และ SendMsg จริง ๆ เป็นการ queue ไม่ใช่ส่งทันที ทำให้ debug ปัญหาระดับ transport ยาก สุดท้าย proxy หรือ firewall ที่ไม่รู้จัก gRPC อาจ drop หรือ reset connection เงียบ ๆ โดยไม่มี error ชัดเจน


🧭 gRPC ในภาพรวมปี 2026#

ถ้าถามว่าควรเทียบ gRPC กับอะไร คำตอบไม่ใช่ “เลือกตัวเดียวให้ชนะ” แต่เป็นการเลือกตามขอบเขตของงาน

  • REST — universal, ง่าย, เหมาะกับ public API และงานที่ interaction ไม่ซับซ้อน
  • GraphQL — query ยืดหยุ่น เหมาะกับงานที่ client เป็นคนกำหนดว่าอยากได้ข้อมูลแบบไหน
  • tRPC — end-to-end type safety สำหรับงานสาย TypeScript ล้วน
  • gRPC — high-performance service-to-service ภายใน backend

มี protocol น่าสนใจที่โตขึ้นเรื่อย ๆ อย่าง Connect protocol และ ConnectRPC (จาก buf.build) ที่ปรับ developer experience ของ gRPC ให้ดีขึ้นและรองรับ browser ได้ดีกว่าเดิม

แนวทางที่ลงตัวในปี 2026 คือไม่ผูกตัวเองกับ protocol เดียว แต่เลือกตาม boundary ของระบบ — public API เป็น REST, frontend อาจใช้ tRPC, ส่วน microservices ฝั่ง backend ที่ต้องการความเร็วและสัญญาที่รัดกุมก็ให้ gRPC รับไป

gRPC ไม่ใช่ของวิเศษที่ใช้แทนทุกอย่าง แต่ในโซนที่เหมาะ — internal service ที่คุยกันถี่ ๆ ต้องการความเร็วและ contract ที่แน่น — gRPC ทำงานได้ดีจนยากจะหาตัวแทน ลองเริ่มจากเขียน .proto เล็ก ๆ สัก service หนึ่งดู

😎 ☕

Code, coffee, and calm — the holy trinity of a good day. ☕

gRPC คืออะไร — เรียกฟังก์ชันข้ามเครื่องให้เหมือนเรียกในเครื่องตัวเอง
Author Coffee Stack
Published at 25 มิถุนายน 2026