swoole方案 基于 gRPC 与 Protobuf 的跨语言微服务
·
gRPC + Protobuf 跨语言微服务
大白话先说清楚
PHP(Swoole) ←──gRPC──→ Go服务
PHP(Swoole) ←──gRPC──→ Java服务
PHP(Swoole) ←──gRPC──→ Python服务
说白了就是:
各种语言的服务之间打电话,
Protobuf是"电话语言"(都听得懂),
gRPC是"电话线"(HTTP/2传输)
为什么不用HTTP+JSON?
JSON: {"name":"张三","age":18} → 字符串,慢,包大
Protobuf: 二进制压缩 → 快,包小3-10倍
第一步:装东西
# 装protobuf扩展
pecl install protobuf
# 装grpc扩展
pecl install grpc
# 装composer包
composer require grpc/grpc google/protobuf
第二步:写 .proto 文件(定义接口)
// user.proto
syntax = "proto3";
package user;
// 定义服务:有个查用户的方法
service UserService {
rpc GetUser (UserRequest) returns (UserResponse);
}
// 入参
message UserRequest {
int32 id = 1;
}
// 出参
message UserResponse {
int32 id = 1;
string name = 2;
int32 age = 3;
}
第三步:生成PHP代码
# 用protoc生成PHP文件
protoc --php_out=./gen --grpc_out=./gen \
--plugin=protoc-gen-grpc=`which grpc_php_plugin` \
user.proto
# 生成后目录长这样:
# gen/User/UserRequest.php
# gen/User/UserResponse.php
# gen/User/UserServiceClient.php
第四步:PHP gRPC 服务端(Swoole驱动)
<?php
// server.php
require __DIR__ . '/vendor/autoload.php';
use User\UserRequest;
use User\UserResponse;
// 假数据库
$users = [
1 => ['name' => '张三', 'age' => 18],
2 => ['name' => '李四', 'age' => 25],
];
$server = new Swoole\Http\Server('0.0.0.0', 9503, SWOOLE_BASE);
$server->set([
'open_http2_protocol' => true, // 开HTTP/2,gRPC必须
'ssl_cert_file' => null,
'ssl_key_file' => null,
]);
$server->on('request', function ($req, $resp) use ($users) {
// gRPC路径格式:/包名.服务名/方法名
if ($req->server['request_uri'] !== '/user.UserService/GetUser') {
$resp->status(404);
$resp->end();
return;
}
// 解析Protobuf二进制body(前5字节是gRPC帧头)
$body = substr($req->rawContent(), 5);
$request = new UserRequest();
$request->mergeFromString($body);
$id = $request->getId();
$info = $users[$id] ?? ['name' => '未知', 'age' => 0];
// 构建响应
$response = new UserResponse();
$response->setId($id);
$response->setName($info['name']);
$response->setAge($info['age']);
// 序列化 + 加5字节gRPC帧头
$payload = $response->serializeToString();
$body = pack('CN', 0, strlen($payload)) . $payload;
$resp->header('content-type', 'application/grpc');
$resp->header('grpc-status', '0');
$resp->end($body);
});
echo "gRPC服务跑在 9503\n";
$server->start();
第五步:PHP gRPC 客户端(调Go/Java的服务)
<?php
// client.php
require __DIR__ . '/vendor/autoload.php';
use User\UserServiceClient;
use User\UserRequest;
// 连Go或Java写的gRPC服务
$client = new UserServiceClient('go服务的IP:9504', [
'credentials' => Grpc\ChannelCredentials::createInsecure(),
]);
$request = new UserRequest();
$request->setId(1);
// 发请求
[$response, $status] = $client->GetUser($request)->wait();
if ($status->code === Grpc\STATUS_OK) {
echo "名字:" . $response->getName() . "\n";
echo "年龄:" . $response->getAge() . "\n";
} else {
echo "出错了:" . $status->details . "\n";
}
Go那边长什么样(对照理解)
// go_server.go
// Go实现同一个proto的服务端,PHP可以直接调它
type server struct{}
func (s *server) GetUser(ctx context.Context, req *pb.UserRequest) (*pb.UserResponse, error) {
return &pb.UserResponse{Id: req.Id, Name: "张三", Age: 18}, nil
}
// 启动
grpcServer := grpc.NewServer()
pb.RegisterUserServiceServer(grpcServer, &server{})
grpcServer.Serve(listener) // 监听9504
整体通信矩阵
┌─────────────────────────────────────┐
│ .proto 文件 │
│ (所有语言共同遵守的接口协议) │
└──────────┬──────────────────────────┘
│ protoc 生成各语言代码
┌──────┴───────┐
↓ ↓
PHP+Swoole Go/Java/Python
(服务端/客户端) (服务端/客户端)
↕ HTTP/2+Protobuf二进制 ↕
└──────────────────────────┘
核心三句话
1. .proto → 定好接口,所有语言照着实现
2. protoc → 自动生成各语言的代码,不用手写
3. Swoole → 开 open_http2_protocol=true 支撑gRPC传输
更多推荐

所有评论(0)