การสื่อสารระหว่างบริการ: REST และ gRPC
เชื่อมต่อบริการแบบทำงานพร้อมกันอย่างมีประสิทธิภาพ
การสื่อสารระหว่างบริการ: REST และ gRPC เป็นบทเรียน PHP Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน PHP Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส PHP Academy มีบทเรียนทั้งหมด 4 บทเรียน
REST และ gRPC
บริการจำเป็นต้องสื่อสารกันแบบทำงานพร้อมรอผล: ส่งคำขอออกไป แล้วได้รับคำตอบกลับมา ตัวเลือกหลักสองแบบคือ REST ผ่าน HTTP/JSON และ gRPC ผ่าน HTTP/2 + Protobuf แต่ละแบบเหมาะกับเป้าหมายต่างกัน — REST เหมาะกับการเข้าถึงได้กว้างและใช้งานเข้าใจง่าย ส่วน gRPC เหมาะกับความเร็วและสัญญาที่เข้มงวด
บทเรียนนี้จะแสดงทั้งสองแบบจากมุมมองของ PHP และอธิบายว่าควรเลือกใช้แบบใด
REST: ภาษากลาง
REST จัดทรัพยากรไว้ภายใต้ URL และใช้กริยา HTTP กับรหัสสถานะเพื่อสื่อความหมาย จุดเด่นคือมีเครื่องมือรองรับทั่วไป แคชได้ แก้จุดบกพร่องด้วย curl ได้ และไม่ต้องใช้ไคลเอนต์พิเศษ จุดด้อยคือ JSON มีรายละเอียดมาก ไม่มีสคีมาบังคับใช้ และรองรับเฉพาะคำขอกับการตอบกลับ
สำหรับ API สาธารณะและจุดปลายทางที่เบราว์เซอร์เรียกใช้ REST มักเป็นตัวเลือกที่เหมาะสมที่สุด
การเรียกใช้บริการ REST
ใช้ไคลเอนต์ HTTP ตามมาตรฐาน PSR-18 (ตัวอย่างนี้ใช้ Guzzle) ควรกำหนด ระยะหมดเวลาการเชื่อมต่อและการร้องขอเสมอ — การเรียกที่ไม่มีขอบเขตเวลาไปยังบริการเพื่อนบ้านที่ช้าอาจใช้กระบวนการทำงานของ PHP-FPM จนหมด และทำให้ระบบขัดข้องลุกลาม
<?php
require 'vendor/autoload.php';
use GuzzleHttp\Client;
$http = new Client([
'base_uri' => 'http://customers-svc/',
'connect_timeout' => 1.0, // never block forever on connect
'timeout' => 3.0, // total request budget
'http_errors' => false,
]);
$res = $http->get('customers/42', ['headers' => ['Accept' => 'application/json']]);
if ($res->getStatusCode() === 200) {
$customer = json_decode((string) $res->getBody(), true);
echo $customer['email'] . "\n";
}รหัสสถานะคือสัญญา
ในการสื่อสาร REST ระหว่างบริการ รหัสสถานะ HTTP คือโพรโทคอลข้อผิดพลาดของคุณ จงจัดการโดยตั้งใจ:
2xxสำเร็จ;4xxเป็นความผิดของผู้เรียก (อย่าลองใหม่โดยไม่พิจารณา);5xx/หมดเวลาเป็นกรณีที่ควรลองใหม่- ใช้
409สำหรับข้อขัดแย้ง422สำหรับการตรวจสอบข้อมูล และ429สำหรับการจำกัดอัตรา (ให้ปฏิบัติตามRetry-After)
การลองใหม่เมื่อได้ 400 มีแต่จะทำให้เสียการเรียกใช้โดยเปล่าประโยชน์ ส่วนการลองใหม่เมื่อได้ 503 โดยเพิ่มช่วงหน่วงนั้นถูกต้อง
<?php
function isRetryable(int $status): bool {
return $status === 0 // timeout/connection error
|| $status === 429
|| ($status >= 500 && $status !== 501);
}
var_dump(isRetryable(503)); // true
var_dump(isRetryable(400)); // falsegRPC: เริ่มจากสัญญาและรวดเร็ว
gRPC ใช้ โปรโตคอลบัฟเฟอร์: คุณกำหนดบริการและข้อความในไฟล์ .proto แล้วสร้างสตับไคลเอนต์/เซิร์ฟเวอร์ที่มีชนิดข้อมูลชัดเจน เมื่อทำงานผ่าน HTTP/2 ด้วย Protobuf แบบไบนารี จะมีขนาดกะทัดรัดกว่าและมีเวลาแฝงต่ำกว่า JSON มาก อีกทั้งยังรองรับการสตรีมข้อมูล
syntax = "proto3";
package customers;
service Customers {
rpc GetCustomer (GetCustomerRequest) returns (Customer);
}
message GetCustomerRequest { string id = 1; }
message Customer {
string id = 1;
string email = 2;
int32 loyalty_points = 3;
}การสร้างสตับ PHP
ติดตั้งส่วนขยาย gRPC ของ PHP และปลั๊กอิน protoc จากนั้นสร้างคลาสไคลเอนต์จากไฟล์ .proto PHP สามารถทำหน้าที่เป็น ไคลเอนต์ gRPC ที่มีความสามารถครบถ้วนผ่าน ext-grpc ได้ ส่วนการทำงานเป็น เซิร์ฟเวอร์ gRPC แบบ PHP โดยตรงโดยทั่วไปต้องใช้ Roadrunner หรือ Swoole
pecl install grpc
composer require grpc/grpc google/protobuf
protoc --proto_path=. \
--php_out=./generated \
--grpc_out=./generated \
--plugin=protoc-gen-grpc=$(which grpc_php_plugin) \
customers.protoการเรียกใช้จากไคลเอนต์ gRPC
สตับที่สร้างขึ้นจะมอบคำขอและคำตอบที่มีชนิดข้อมูลกำกับ การเรียก gRPC จะส่งคืนข้อความและออบเจ็กต์ status — ควรตรวจสอบรหัสสถานะทุกครั้งก่อนเชื่อถือคำตอบ
<?php
require 'vendor/autoload.php';
use Customers\CustomersClient;
use Customers\GetCustomerRequest;
use Grpc\ChannelCredentials;
$client = new CustomersClient('customers-svc:50051', [
'credentials' => ChannelCredentials::createInsecure(),
]);
$req = (new GetCustomerRequest())->setId('42');
[$reply, $status] = $client->GetCustomer($req)->wait();
if ($status->code === \Grpc\STATUS_OK) {
echo $reply->getEmail(), "\n";
} else {
fwrite(STDERR, "gRPC error: {$status->details}\n");
}การพัฒนาสคีมา
Protobuf สร้างขึ้นเพื่อรองรับความเข้ากันได้ไปข้างหน้าและย้อนหลัง — หากคุณปฏิบัติตามกฎของมัน:
- ห้ามนำหมายเลขฟิลด์กลับมาใช้ซ้ำหรือเปลี่ยนแปลง ให้เพิ่มฟิลด์ใหม่ด้วยหมายเลขใหม่
- ทำเครื่องหมายฟิลด์ที่ลบออกด้วย
reservedเพื่อไม่ให้หมายเลขนั้นถูกนำกลับมาใช้ใหม่ - ไคลเอนต์รุ่นเก่าจะข้ามฟิลด์ที่ไม่รู้จัก ส่วนฟิลด์ที่ไม่มีค่าจะใช้ค่าเริ่มต้นของชนิดข้อมูล
JSON/REST ไม่มีสิ่งเหล่านี้ให้โดยอัตโนมัติ — คุณต้องบังคับใช้ความเข้ากันได้ด้วยข้อตกลง และควรมีสคีมา OpenAPI ที่ใช้ร่วมกันพร้อมการทดสอบสัญญา
message Customer {
string id = 1;
string email = 2;
reserved 3; // old 'loyalty_points', never reuse 3
reserved "loyalty_points";
string display_name = 4; // new field, safe additive change
}การสตรีมข้อมูล
gRPC รองรับการเรียกสี่ประเภท ส่วน REST รองรับโดยตรงเพียงประเภทแรก:
- แบบคำขอเดียว–คำตอบเดียว — หนึ่งคำขอ หนึ่งคำตอบ
- การสตรีมจากเซิร์ฟเวอร์ — หนึ่งคำขอและคำตอบต่อเนื่อง (เช่น การอัปเดตแบบสด)
- การสตรีมจากไคลเอนต์ — คำขอต่อเนื่องและคำตอบเดียว (เช่น การอัปโหลดจำนวนมาก)
- สองทิศทาง — ทั้งสองฝ่ายสตรีมพร้อมกัน
หากกรณีใช้งานของคุณเป็นการส่งข้อมูลจากเซิร์ฟเวอร์หรือการไหลของข้อมูลที่มีอายุยาวนาน การสตรีมของ gRPC เหมาะกว่าการสำรวจจุดปลายทาง REST เป็นระยะ
การส่งต่อบริบทและกำหนดเวลาสิ้นสุด
การเรียกแบบทำงานพร้อมรอผลจะก่อตัวเป็นห่วงโซ่ ดังนั้นทุกคำขอต้องส่งข้อมูลสองอย่างไปด้วย: รหัสสหสัมพันธ์/การติดตามสำหรับการติดตามตั้งแต่ต้นจนจบ และ กำหนดเวลาสิ้นสุดเพื่อไม่ให้บริการปลายทางที่ช้าทำให้ห่วงโซ่ทั้งหมดค้าง gRPC รองรับกำหนดเวลาสิ้นสุดโดยตรง ส่วน REST จำลองสิ่งนี้ด้วยงบระยะหมดเวลาที่ลดลงและส่งต่อไปยังบริการถัดไป
<?php
// REST: shrink the remaining budget as the call chain deepens
function forwardHeaders(array $incoming, float $remainingMs): array {
return [
'X-Correlation-Id' => $incoming['X-Correlation-Id'] ?? bin2hex(random_bytes(8)),
// downstream must finish within what's left of our budget
'X-Timeout-Ms' => (string) max(0, (int) $remainingMs),
];
}
print_r(forwardHeaders(['X-Correlation-Id' => 'trace-9'], 1500));การเลือกระหว่างสองแบบ
แนวทางตัดสินใจที่ใช้ได้จริง:
- REST สำหรับ API สาธารณะ/พาร์ทเนอร์ ไคลเอนต์เบราว์เซอร์ การดำเนินการพื้นฐานกับข้อมูล การแก้จุดบกพร่องที่ง่าย และการรองรับแคชอย่างกว้างขวาง
- gRPC สำหรับการเรียกใช้ระหว่างบริการภายในที่มีปริมาณสูงและเวลาแฝงต่ำ สัญญาที่กำหนดชนิดข้อมูลอย่างเข้มงวด และการสตรีมข้อมูล
หลายระบบใช้ทั้งสองแบบ: ใช้ gRPC หลังเกตเวย์ระหว่างบริการ และใช้ REST ที่ขอบระบบสำหรับโลกภายนอก อย่าบังคับให้เครื่องมือหนึ่งทำงานของอีกเครื่องมือ
ตรวจสอบอย่างรวดเร็ว
การจับคู่โพรโทคอลกับกรณีใช้งาน
สรุปทบทวน
การสื่อสารระหว่างบริการแบบทำงานพร้อมรอผล:
- REST/JSON — ใช้งานได้ทั่วไป แก้จุดบกพร่องได้ และใช้แคชได้ รหัสสถานะคือสัญญา ควรกำหนดระยะหมดเวลาเสมอ
- gRPC/Protobuf — เริ่มจากสัญญา ขนาดกะทัดรัด รวดเร็ว และรองรับการสตรีม สร้างสตับ PHP ที่มีชนิดข้อมูลกำกับ
- ตัดสิน ความสามารถในการลองใหม่จากรหัสสถานะ/รหัส gRPC และอย่าลองใหม่กับข้อผิดพลาดจากผู้เรียก
- พัฒนาสคีมาด้วยการเพิ่มเท่านั้น — ห้ามนำหมายเลขฟิลด์ Protobuf กลับมาใช้ซ้ำ
- การใช้ REST ที่ขอบระบบและ gRPC ระหว่างบริการภายในเป็นการแบ่งหน้าที่ที่พบได้บ่อยและเหมาะสม
ถัดไป: การกำหนดเส้นทางและค้นหาตำแหน่งบริการทั้งหมดด้วยเกตเวย์และการค้นหาบริการ
คำถามที่พบบ่อย
บทเรียน “การสื่อสารระหว่างบริการ: REST และ gRPC” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “การสื่อสารระหว่างบริการ: REST และ gRPC” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส PHP Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส PHP Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “การสื่อสารระหว่างบริการ: REST และ gRPC”
เชื่อมต่อบริการแบบทำงานพร้อมกันอย่างมีประสิทธิภาพ คุณปฏิบัติ PHP Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน PHP Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน PHP Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน
บทเรียน “การสื่อสารระหว่างบริการ: REST และ gRPC” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน PHP Academy นี้ได้ไหม
ได้ บทเรียน PHP Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- จากโมโนลิทสู่ไมโครเซอร์วิส
- การสื่อสารระหว่างบริการ: REST และ gRPC
- เกตเวย์ API และการค้นพบบริการ
- ความทนทาน: ตัวตัดวงจรและการลองใหม่