eiz / manageproto
Proto Files Manage
v1.0
2025-04-25 09:26 UTC
Requires
- php: >=7.0.0
- google/protobuf: ^4.28
- grpc/grpc: ^v1.57
Requires (Dev)
- ext-grpc: *
This package is auto-updated.
Last update: 2025-04-25 09:26:53 UTC
README
1. php 安装grpc & protobuf 扩展
以下按照 Alpine 容器为例
apk update
apk add --no-cache php-dev autoconf libtool make g++ grpc
# 安装 gRPC 扩展
pecl install grpc
# 安装 protobuf 扩展
pecl install protobuf
echo "extension=grpc.so" > /etc/php7/conf.d//grpc.ini
echo "extension=protobuf.so" > /etc/php7/conf.d/protobuf.ini
# 随后重启容器
# 查看扩展是否安装成
php -m
2.安装Consul服务
#去官网找需要下载的版本 直接替换 CONSUL_VERSION
wget https://releases.hashicorp.com/consul/${CONSUL_VERSION}/consul_${CONSUL_VERSION}_linux_amd64.zip
unzip consul_${CONSUL_VERSION}_linux_amd64.zip
3.服务项目中准备
composer require grpc/grpc --ignore-platform-reqs
composer require google/protobuf --ignore-platform-reqs
#eiz/manageproto 这个是所有服务的proto 以及 客户端服务端的统一管理
composer require eiz/manageproto --ignore-platform-reqs
#说明一下 咱们项目由于php版本偏低所以需要追加忽略版本的参数,否则代码运行会有检测版本的验证
CONSUL_URL=? //配置consul服务地址和端口 默认:127.0.0.1:8500
SERVICE_NAME=? //服务名称
SERVICE_ADDRESS=? //服务地址 默认:127.0.0.1
SERVICE_PORT=? //服务端口
4.新增grpc启动文件
<?php
require 'vendor/autoload.php';
use App\Grpc\FulfillmentGrpcService;
use App\Grpc\HealthGrpcService;
use Grpc\RpcServer;
$app = require __DIR__.'/../bootstrap/app.php';
$app->run();
$server = new RpcServer();
$server->addHttp2Port('0.0.0.0:10051');
$server->handle(new FulfillmentGrpcService()); //如果有多个服务可以增加 多个 handle
$server->handle(new HealthGrpcService());
echo "gRPC server running at 0.0.0.0:10051\n";
$server->run();
//在项目的public文件夹下创建启动文件 order_server.php
5.生成GRPC客户端&服务端代码
# --proto_path 指定了 proto 文件的查找路径,也就是当前目录(. 表示当前路径)。
# --php_out 这个参数指定了生成的 PHP 代码的输出目录。
# --grpc_out 这表示生成的 gRPC 代码(PHP 版)也会输出到指定目录中
# --plugin 用于指定 gRPC 插件的路径,生成 gRPC 代码时需要这个插件。
protoc --proto_path=. --php_out=../src --grpc_out=../src --plugin=protoc-gen-grpc=/d/works/demo_php_grpc/grpc_for_windows-master/grpc_for_windows-master/x64/grpc_php_plugin.exe ./Warehouse.proto
示例代码
//在bootstrap下的app.php新增一行代码
$app->register(Providers\ConsulServiceProvider::class);
//服务项目中创建 grpc.php 配置文件,配置该服务需要发现的客户端配置
// key-value 形式,key 指定的是 启动grpc服务注册到 consul中的服务,value指的是生成的grpc客户端类
return [
"services" => [
'catalog-service' => CatalogServiceClient::class,
'order-service' => OrderServiceClient::class,
'warehouse-service' => WarehouseServiceClient::class
]
];
//发现服务
/**
* 从 consul 中发现服务
*
* @param string $serviceName
* @return array|null
* @throws GuzzleException
*/
public function discoverService(string $serviceName): ?array
{
try {
$consulClient = new Client([
'base_uri' => env('CONSUL_HOST', 'http://127.0.0.1:8500'),
]);
$response = $consulClient->get("/v1/catalog/service/{$serviceName}");
$services = json_decode($response->getBody(), true);
if (count($services) > 0) {
// 返回第一个可用的服务实例
return $services[0];
} else {
writeLog('err', ['err' => "No services found for {$serviceName}"], 'etcd-err-log');
}
} catch (Exception $e) {
writeLog('err', ['err' => "Failed to discover service: " . $e->getMessage()], 'etcd-err-log');
}
return null;
}
public function getServices(): stdClass
{
$services = config('grpc.services');
$clients = new stdClass();
foreach ($services as $serviceKey => $serviceClient) {
$serviceConfig = $this->discoverService($serviceKey);
if ($serviceConfig) {
$serviceAddress = $serviceConfig['ServiceAddress'];
$servicePort = $serviceConfig['ServicePort'];
$serviceClientName = $this->ucFirst($serviceKey);
$clients->$serviceClientName = new $serviceClient("{$serviceAddress}:{$servicePort}", [
'credentials' => ChannelCredentials::createInsecure(),
]);
}
}
return $clients;
}
private function ucFirst($serviceName) {
$serviceName = str_replace('-', ' ', $serviceName);
$serviceName = ucwords($serviceName);
return str_replace(' ', 'Grpc', $serviceName);
}
调用示例:
$warehouseRequest = new \Warehouse\Request();
$_reqData = [
'warehouseId' => $fulfillment->warehouse_id,
'productMap' => array_column($shippingProducts, 'stock', 'product_id'),
'products' => $products,
'type' => !empty($adjustStock) ? Constant::DECREMENT_STOCK_LOCK : Constant::DECREMENT,
'extra' => [
'reduceStock' => $reduceStock,
'messageType' => Constant::DISPATCH_FULFILLMENT,
'fulfillmentId' => $fulfillmentId,
'salesRecordNumber' => $fulfillment->shipTo_ref ?? ''
]
];
$warehouseRequest->setJsonData(json_encode($reqData));
list($response, $status) = $this->clients->WarehouseGrpcService->reduceStock($warehouseRequest, $this->metadata)->wait();
$logRes = $this->baseService->grpcResponse($response, $status);