歡迎您光臨本站 註冊首頁

TarsPHP 新版本發布,支持 Protobuf 協議

←手機掃碼閱讀     admin @ 2019-08-07 , reply:0

Tars是騰訊從2008年到今天一直在使用的微服務開發框架,2018年成為Linux基金會開源項目,目前支持C++、Java、PHP、NodeJS與Go語言。該框架為用戶提供了涉及到開發、運維,以及測試的一整套解決方案,幫助一個產品或者服務快速開發、部署、測試、上線。它集可擴展協議編解碼、高性能RPC通信框架、名字路由與發現、發布監控、日誌統計、配置管理等於一體,通過它可以快速用微服務的方式構建自己的穩定可靠的分散式應用,並實現完整有效的服務治理。

 

TarsPHP作為Tars在PHP語言的解決方案,設計的時候主要考慮如下四個方面:

  • 功能完善:對標現有C++、Java與NodeJS體系功能
  • 靈活:論靈活,誰與PHP爭鋒?
  • 輕量:用最輕量的設計,點到即止,即插即用
  • 高效:插上Swoole協程的翅膀,不得不飛

Protobuf簡介

Protocol buffers (簡稱PB)是Google開源的語言中立,平台無關,可擴展的序列化數據的格式,可用於通信協議,數據存儲等。它和XML類似,但比XML更小,更快,更簡單。

PB是編碼協議,如果涉及到網路傳輸和RPC調用,就需要引入通訊協議。Google開源的RPC框架gRPC就使用Http2作為通訊協議,PB作為編碼協議。

使用TarsPHP 構建 PB Server

初始化環境

  • Protoc 安裝

  • php protobuf安裝

    • 之後需要安裝 php protobuf擴展,這個擴展主要用作php和protoc庫中間的一個橋樑。

      
      git clone https://github.com/protocolbuffers/protobuf.git
      cd ./php/ext/google/protobuf/
      phpize
      ./configure
      make
      make install
      (需要編輯php.ini文件,開啟protobuf擴展)
      

      如果 php –ri protobuf 有輸出,說明安裝正常。

  • Swoole 安裝

    • 建議使用4.4.0或以上版本,需要開啟http2 和 openssl支持。

編寫一個proto文件

參考TarsPHP中ActDemo中評論服務的tars文件,我們寫了一個actComment.proto的協議文件。

和tars協議文件不同,proto協議中規定輸入輸出參數必須也只能是一個message結構體,因此需要對輸入輸出參數單獨在封裝一個message。


syntax = "proto3";  
  
package protocol.QD.ActCommentPbServer;  //包名,會根據包名生成 php類路徑

service CommentObj {  
  rpc ping(PingRequest) returns (PingResponse) {};  
  
  rpc getCommentCount(CountRequest) returns (CountResponse) {};  
  
  rpc createComment(CreateRequest) returns (CreateResponse) {};  
  
  rpc getComment(GetRequest) returns (GetResponse) {};  
}  
  
//輸入參數通用結構體  
message CommonInParam {  
    int32 appId = 1;  
    int32 areaId = 2;  
    int64 userId = 3; //用戶信息  
    string userIp = 4; //來源名稱  
    string serverIp = 5; //調用方伺服器ip  
};  
  
//輸出參數通用結構體  
message CommonOutParam {  
    int32 code = 1;  //介面返回碼  
    string message = 2;  //介面返回提示信息  
};  
  
message SimpleComment {  
    int32 id = 1;  
    int64 activityId = 2;  
    int64 userId = 3;  
    string content = 4;  
    string title = 5;  
    string ext1 = 6;  
    int64 createTime = 7;  
};  
  
message QueryParam {  
    int64 activityId = 1;  
    int32 page = 2;  
    int32 size = 3;  
    int32 orderType = 4;  
};  
  
message CreateRequest {  
    CommonInParam inParam = 1;  
    SimpleComment comment = 2;  
};  
  
message CreateResponse {  
    CommonOutParam outParam = 1;  
};  
  
message GetRequest {  
    CommonInParam inParam = 1;  
    QueryParam queryParam = 2;  
};  
  
message GetResponse {  
    CommonOutParam outParam = 1;  
    repeated SimpleComment list = 2;  
};  
  
message PingRequest {  
};  
  
message PingResponse {  
};  
  
message CountRequest {  
};  
message CountResponse {  
    int32 count = 1;  
};

生成server端代碼

protoc可以根據proto文件生成對應的php類代碼,但是官方並不支持proto文件生成server端代碼,可以使用gRPC插件生成client代碼。如果需要使用生成的client代碼我們還需要安裝grpc庫和grpc php擴展。

因此我們的思路是,先使用protoc生成php需要的類,然後自己解析proto文件生成server 端interface,這個過程非常像現有的tars2php的過程,因此我們叫它proto2php。

由於使用兩個工具生成還比較麻煩,我們把調用proto的過程集成到proto2php中方便大家使用。

我們先構建一個tars.proto.php設置一些基本信息。


return array(
    'appName' => 'QD',
    'serverName' => 'ActCommentPbServer',
    'objName' => 'CommentObj',
    'withServant' => true, //決定是服務端,還是客戶端的自動生成
    'tarsFiles' => array(
        './actComment.proto',
    ),
    'dstPath' => '../src/protocol', //這裡指定的是 impl 基礎interface 生成的位置
    'protocDstPath' => '../src', //這裡指定的是 protoc 生成的問題
    'namespacePrefix' => 'Protocol',
);

然後執行 php …/src/vendor/phptars/tars2php/src/proto2php.php ./tars.proto.php
之後會生成GPBMetadata目錄和protocol目錄。其中protocol中就是proto文件生成的php類,另外CommentObjServant.php就是proto2php文件生成的server端interface類。構建TarsPHP pb server需要實現這個類。

部署TarsPHP PB server

按照Demo中 Readme部署tarsphp pb server即可。

幾點注意:

  1. 需要在impl目錄中實現interface邏輯。
  2. 在src下的services.php中指定home-api,home-class位置,protocolName是pb,serverType是grpc
  3. tars平台上協議類型是 tcp,非tars協議。
  4. 需要在composer.json中添加require 「google/protobuf」,autoload中需要配置 Protocol 和 GPBMetadata,範例如下:
    
    {
        "name" : "tars-tcp-server-demo",
        "description": "tars tcp server",
        "require": {
            "phptars/tars-server": "~0.3",
            "phptars/tars-deploy": "~0.1",
            "phptars/tars-log": "~0.1",
            "phptars/tars2php": "~0.1",
            "ext-zip" : ">=0.0.1",
            "google/protobuf": "^3.8"
        },
        "autoload": {
            "psr-4": {
                "Server\\" : "./",
                "Protocol\\" : "./protocol",
                "GPBMetadata\\" : "./GPBMetadata"
            }
        },
        "minimum-stability": "stable",
        "scripts" : {
            "deploy" : "\\Tars\\deploy\\Deploy::run"
        }
    }
    

最後執行 composer run-script deploy,生成代碼包,上傳到Tars平台上發布。

使用client訪問

可以使用gRPC生成的php客戶端訪問測試,也可以直接使用swoole 的http2客戶端構建一個grpc客戶端。


class TestGrpcClient
{
    public static function callGrpc($ip, $port, $path, $requestBuf)
    {
        $cli = new Swoole\Coroutine\Http2\Client($ip, $port, false);
        $cli->connect();
        $req = new swoole_http2_request;
        $req->method = 'POST';
        $req->path = $path;
        $req->headers = [
            "user-agent" => 'grpc-c/7.0.0 (linux; chttp2; gale)',
            "content-type" => "application/grpc",
            "grpc-accept-encoding" => "identity,deflate,gzip",
            "accept-encoding" => "identity,gzip",
            "te" => "trailers",
        ];
        $req->pipeline = false;
        $req->data = $requestBuf;
        $cli->send($req);
        $response = $cli->recv();
        return $response->data;
    }

    public static function main()
    {
        $commonIn = new CommonInParam();
        $commonIn->setUserId(0);
        $commonIn->setAppId(1);
        $commonIn->setAreaId(10);
        $commonIn->setServerIp('127.0.0.1');
        $commonIn->setUserIp('');

        $query = new QueryParam();
        $query->setActivityId(123);
        $query->setPage(1);
        $query->setSize(10);
        $query->setOrderType(1);

        $request = new GetRequest();
        $request->setInParam($commonIn);
        $request->setQueryParam($query);
        
        $requestBuf = $request->serializeToString();
        $packBuf = pack('CN', 0, strlen($requestBuf)) . $requestBuf;

        go(function () use ($packBuf){
            $path = "/protocol.QD.ActCommentServer.CommentObj/getComment";
            $ret = self::callGrpc('127.0.0.1', 10008, $path, $packBuf); //這裡注意要修改成你服務在tars上綁定的ip 127.0.0.1不一定可以
            $response = new GetResponse();
            $response->mergeFromString(substr($ret, 5));
            foreach ($response->getList() as $row) {
                var_dump($row->getContent());
            }
        });
    }
}

執行php client.php觀察返回。

生成client端代碼

前面提到的client,只是我們訪問PB server 的簡單demo,可以幫助我們測試PB server的狀態。如果需要在其他Tars服務中調用PB server應該如何使用呢?和Tars類似我們也提供了生成PB client端代碼的方式。

這裡使用TarsActDemo下的QD.ActHttpServer為範例演示如何生成Tars PB client代碼並調用PB服務。

  1. 拷貝actComment.proto文件到tars目錄
  2. 構建actCommentPb.proto.php 文件,內容和生成server代碼用的tars.proto.php內容一致,修改 withServant = false
  3. 執行 php …/src/vendor/phptars/tars2php/src/proto2php.php ./actCommentPb.proto.php
  4. 之後在protocol/QD/ActCommentPbServer 中可以看到相關生成代碼。(和Server 端代碼類似,CommentObjServant.php是 proto2php生成的,其他文件是proto2php 調用 protoc 插件生成的)
  5. 和Server端類似需要添加 GPBMetadata 和 Protocol 到composer.json 的psr-4中。
  6. 和Tars 調用類似,可以直接調用CommentObjServant類的相關方法和PB 服務通訊。需要注意的是 傳入的 CommunicatorConfig 中的socketModel 需要設置為 4 grpc 模式。

範例如下:


$inParam = new CountRequest();  
$outParam = new CountResponse();  
  
$conf = self::getConfig();  
$conf->setSocketMode(4);  
  
$servant = new CommentObjServant($conf);  
$servant->getCommentCount($inParam, $outParam);  
  
return $outParam->getCount();

和TarsGo中關於PB支持的不同

TarsGo中關於PB的支持,本質是對proto協議文件的支持,提供將proto協議文件轉換為tars協議的能力,在相互調用中實際使用的是tars協議。這個服務可以和其他Tars服務相互工作。

TarsPHP中關於PB的支持,是構建了一個gRPC服務,這個服務部署在Tars平台上,參與Tars平台定址,受Tars平台管理。這個服務使用gRPC on Http2作為網路通訊協議,使用Protobuf作為編碼協議,可以和其他PB client 相互工作。

兩者方向不同,不能混合使用,希望大家區分。

相關數據

我們使用相同Http服務,分別使用Tars和Pb協議和後端服務通訊並進行壓測。

  • 伺服器環境:2核 4G,php 7.2.16,swoole 4.4.0
  • 服務空跑指的是簡單的ping到後端服務,不進行任何業務處理直接返回;
  • 單次簡單RPC指的是向後端服務獲取彈幕數量返回一個int,數量值rand生成,並沒有使用mysql count;
  • 單次複雜PRC會實際向後端獲取彈幕列表結構體,包含多條彈幕對象完整結構。
QDPS PB TARS
服務空跑 3800 6200
單次簡單RPC 3600 6150
單次複雜RPC 1050 1150

從壓測數據來看,Tars性能比PB高出一截,但對比兩者打包解包性能發現PB打包解包性能略優於Tars,導致這樣結果的主要原因我認為是gRPC使用Http2作為通訊協議相比Tars的自定義通訊協議需要更多開銷。

歡迎給項目點 star 並參與貢獻。

https://github.com/TarsPHP/TarsPHP

https://github.com/TarsCloud/Tars

作者:張勇


[admin ]

來源:OsChina
連結:https://www.oschina.net/news/108869/tarsphp-support-protobuf
TarsPHP 新版本發布,支持 Protobuf 協議已經有144次圍觀

http://coctec.com/news/soft/show-post-211814.html