protobuf安裝


PHP7中Protobuf的安裝使用

寫這篇文章的緣由是最近在關注RPC框架序列化的一些原理。但是在安裝Protobuf的時候,發現網上的教程都太老了,加上目前Protobuf官方已經支持PHP了,不再需要使用第三方插件了。

關於序列化和反序列化

在PRC框架中,數據的傳輸發生在客戶端和服務端,而我們知道基於TCP協議最終傳輸的是二進制的0/1序列。所以,基於TCP傳輸協議的RPC服務自然也需要將數據結構轉換成二進制,和二進制轉換成數據結構的功能。所以,原則上,基於網絡的數據傳輸只能傳輸二進制表示的字符串

  1. 序列化:將數據結構或對象轉換成二進制串的過程
  2. 反序列化:將在序列化過程中所生成的二進制串轉換成數據結構或者對象的過程

但是,傳輸的二進制序列是完全沒有意義的,除非有一套解析二進制串的協議。沒錯,這個協議可以就是目前我們大家熟知的xml,json協議。當然。除了這兩者,還有其他的的序列化和反序列化協議。

幾種常見的序列化和反序列協議

XML

XML是一種常用的序列化和反序列化協議,具有跨機器,跨語言等優點。XML歷史悠久,其1.0版本早在1998年就形成標准,並被廣泛使用至今。XML的格式如下

  1. <note>
  2. <to>George</to>
  3. <from>John</from>
  4. <msg>Don't forget the meeting!</msg>
  5. </note>

可以看出這種序列化協議的優點是可讀性和易調試行。但是這種協議的缺點也很明顯:額外空間開銷大,序列化之后的數據量劇增。

JSON

JSON是一種輕量級的數據交換格式。采用完全獨立於編程語言的文本格式來存儲和表示數據。如果你跟瀏覽器Web應用打交道的話,那么JSON一定是應用最廣泛的,它的數據格式如下

  1. {
  2. "to":"George",
  3. "from":"John",
  4. "msg":"Don't forget the meeting!"
  5. }

這種序列化協議有很大的優勢: 
1. 這樣表示非常符合工程師對對象的理解,尤其是js工程師 
2. 和xml一樣,可讀性強 
3. 和xml相比,更加節省空間,解析速度更快

由於天生的Web友好型,JSON自然而然成了AJAX數據傳輸的標准協議。JSON目前的使用非常廣泛,但是,如果數據傳輸和響應時間有跟苛刻的要求,那么JSON可能性能還是差點。

Protobuf

Google Protocol Buffer( 簡稱 Protobuf) 是一種更輕便高效的結構化數據存儲格式,可以用於結構化數據串行化,或者說序列化。它很適合做數據存儲或 RPC數據交換格式。數據結構定義文件的格式如下:

  1. syntax = "proto3";
  2. package config;
  3. message MailConfig{
  4. string to = 1;
  5. string from = 2;
  6. string msg = 3;
  7. }

然后這個協議文件客戶端和服務端都需要用到。這樣,網絡發送字節就不需要發送和數據無關的字節了。針對上面的數據結構,序列化成json的長度是63,而按照Protobuf協議序列化之后的長度是41。如果數據更多,效果更明顯。

Thrift

和Protobuf類似,但是Protobuf只做數據序列化的工作,而Thrift是一套完整的RPC框架解決方案。由於Thrift的序列化被嵌入到Thrift框架里面,Thrift框架本身並沒有透出序列化和反序列化接口,所以如果你使用Thrift框架,那么其實就使用了Thrift的序列化協議。

Thrift是一套完整的RPC解決方案,里面的協議也是一種基於二進制串的序列化協議,如果想要了解更多,這篇文章寫得比較好:https://www.ibm.com/developerworks/cn/java/j-lo-apachethrift/

Protobuf的安裝使用

json和xml相信大家都比較熟悉,但是在RPC框架中很少使用這兩種協議。由於Thrift是一套RPC解決方案,太過龐大,所以我們分析專門解決序列化問題的Protobuf。由於筆者使用的是PHP,所以自然而然使用的是PHP版本的Protobuf。PHP有兩種安裝模式,第一是composer安裝php包的形式,第二種是安裝PHP擴展的形式。

PHP和protoc的安裝

要安裝PHP版本的Protobuf,首先你得有PHP,所以首先安裝PHP,筆者使用的PHP7,還需要一個工具protoc,你可以先不用管這個工具是干嘛的,先安裝。

工具包 版本 下載地址
PHP 7.1.8 http://php.net/get/php-7.1.8.tar.gz/from/a/mirror
proto 3.0.0 https://github.com/google/protobuf/releases/download/v3.3.0/protobuf-php-3.3.0.zip

最后,筆者安裝的PHP版本

  1. [xxx@controller app]$ /usr/bin/php -v
  2. PHP 7.1.8 (cli) (built: Aug 16 2017 03:10:49) ( NTS )
  3. Copyright (c) 1997-2017 The PHP Group
  4. Zend Engine v3.1.0, Copyright (c) 1998-2017 Zend Technologies

筆者安裝的protoc版本(注意,有可能安裝路徑不同)

  1. [xxxx@controller app]$ /usr/local/bin/protoc --version
  2. libprotoc 3.3.0

Protobuf的安裝

Protobuf的安裝我們采用Composer形式進行安裝。如果你還沒有安裝composer工具,運行下面的命令進行安裝:

  1. curl -sS https://getcomposer.org/installer | php
  2. mv composer.phar /usr/local/bin/composer

查看我們安裝的composer版本:

  1. [xxxx@controller app]$ /usr/local/bin/composer --version
  2. Composer version 1.5.1 2017-08-09 16:07:22

准備工作結束。接下來,正式安裝Protobuf。 
我們首先新建一個文件夾app。然后在app文件夾內新建composer.json文件,文件內容如下:

  1. {
  2. "require":{
  3. "google/protobuf": "^3.3"
  4. }
  5. }

保存之后,在app文件夾下執行composer install安裝命令

  1. [xxxx@controller app]$ /usr/local/bin/composer install
  2. Loading composer repositories with package information
  3. Updating dependencies (including require-dev)
  4. Package operations: 1 install, 0 updates, 0 removals
  5. - Installing google/protobuf (v3.4.0): Downloading (100%)
  6. ubuntu環境:sudo snap install protobuf --classic  #如果上一步執行composer install沒有安裝成功,按提示安裝

安裝完成之后,如果你看到的app文件夾包含下面文件,表示安裝成功

  1. [xxxx@controller app]$ ls
  2. composer.json composer.lock vendor
  3.  

     

Protobuf的簡單例子

上面的步驟安裝完之后,我們來看一下一個簡單的例子,這個例子很簡單,一個角色是Writer,一個角色是Reader。Writer向磁盤中寫二進制字符串,Reader要讀取二進制字符串中的信息。

書寫 .proto 文件

我們知道,二進制序列如果沒有協議,根本不知道它表示的是什么,首先我們需要編寫一個 proto 文件,定義我們程序中需要處理的結構化數據,在 protobuf的術語中,結構化數據被稱為 Message。我們這里定義一個mail的proto文件mail.proto,這個文件還是放在我們的app目錄下, 文件內容如下:

  1. syntax = "proto3";
  2. package mail;
  3. message MailConfig{
  4. string to = 1;
  5. string from = 2;
  6. string msg = 3;
  7. }

其中,syntax表示我們使用的是proto3語法規則。packge的名字叫做mail,然后定義了一個名字為MailConfig的消息。這個消息有3個成員,string類型的to,string類型的from,string類型的msg。

編譯 .proto 文件

還記得我們下載安裝的protoc工具嗎,這個玩意就是拿來編譯.proto文件的,它可以將.proto文件編譯成很多種目標語言,java,python,php等。這里我們需要使用這個工具,將.proto文件生成目標PHP語言。

  1. /usr/local/bin/protoc --php_out=. mail.proto

--php-out表示生成目標語言存放位置,我們就放在當前目錄下,也就是app文件夾下。如果生成目標語言成功,那么app文件夾下的目錄如下:

  1. [xxxx@controller app]# ls
  2. composer.json composer.lock GPBMetadata Mail mail.proto vendor

編寫測試

在app中編寫test.php,文件內容如下:

  1. <?php
  2. require_once('vendor/autoload.php');
  3. require_once('GPBMetadata/Mail.php');
  4. require_once('Mail/MailConfig.php');
  5. /**
  6. * Writer寫數據,Protobuf抽象成調用相關set函數即可
  7. */
  8. $foo = new \Mail\MailConfig();
  9. $foo->setTo("George");
  10. $foo->setFrom("John");
  11. $foo->setMsg("Don't forget the meeting!");
  12. $packed = $foo->serializeToString();//這里你也可以選擇serializeToJsonString序列化成JSON
  13. //Reader讀數據,Protobuf抽象成調用相關get函數即可
  14. $res = new \Mail\MailConfig();
  15. $res->mergeFromString($packed);
  16. $jsonArr = [
  17. "to"=> $res->getTo(),
  18. "from"=> $res->getFrom(),
  19. "msg"=> $res->getMsg(),
  20. ];
  21. var_dump($jsonArr);

最終程序的輸出:

  1. [xxxx@controller app]# php test.php
  2. array(3) {
  3. ["to"]=>
  4. string(6) "George"
  5. ["from"]=>
  6. string(4) "John"
  7. ["msg"]=>
  8. string(25) "Don't forget the meeting!"
  9. }

這就是一個典型的序列化和反序列化的例子,試想一下,如果我們將序列化好的二進制串通過網絡發送到另一端,而另一端再使用同樣的.proto文件生成的目標語言解析。這將變得比json更加的高效。因為我們可以傳輸更少的字節,反序列化速度也非常快。

后續

到這里,肯定有人覺得效率還是不夠高,那么沒關系,protobuf有C語言擴展版的實現,如果你對效率有極致的要求,那么強烈建議使用C語言擴展版的protobuf。可以參考官方安裝方式:https://github.com/google/protobuf/tree/master/php

參考安裝:http://blog.leanote.com/post/weibo-007/f40e8fee0dfb

http://www.hello1010.com/php-protobuf


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM