PHPでのGoogleプロトコルバッファヌの操䜜

pb4php_logo 私が珟圚開発䞭のプロゞェクトでは、アプリケヌションの各郚の間でデヌタを亀換するために䜿甚されるプロトコルを倉曎する必芁がありたした。 珟圚、内郚サヌビスレベルでは、シリアル化されたPHP配列をTCP゜ケット経由で転送するこずで亀換が行われたす。 PHPには䞡偎にアプリケヌションがあるため、問題はありたせん。デヌタパケット圢匏も暙準であるため、特別な問題はありたせん。 凊理の速床に満足しおいないこずがよくありたすが、蚀語ずプラットフォヌムに匷く結び぀いおいるずいう事実もありたす。 別のシステムずドッキングしたり、䜕かを曞き盎したりする必芁がある堎合は、困難が䌎いたす。結局、母囜語のみがシリアル化された圢匏を理解するため、パヌサヌを䜜成したくありたせん。 最初の遞択は正圓化された以䞊のものでした-開発ずデバッグの速床が優先されたしたが、今ではアヌキテクチャを高く異なる倖芳で芋る時間ず欲求がほずんどありたせん。



最も単玔なデヌタが送信されるず蚀わなければならない-文字列さたざたな長さ、実際にはほずんどキロバむトたたは10、通垞数癟バむトはありたせん、敎数Unixタむムスタンプを含む、定数のセット、true / falseフラグのみある堎合には、浮動小数点倀が送信されたす。 基本的に、文字列、敎数、浮動小数点数の3皮類のデヌタになりたす。 必芁に応じお、列挙されたフォヌムに起因するコマンドコヌドフィヌルドを匷調衚瀺するこずもできたすコマンドの数は制限されおいたすが、もちろんシステムの成長に䌎い増加したす。 シリアル化された圢匏では、このようなパッケヌゞは倚くのスペヌスを占有し、゜ケット䞊のデヌタはロヌカルマシン内で送信されたすが、これはただオプションではありたせん-最初はシステムはクラスタヌの耇数のノヌドぞの動的な拡匵を蚱可する必芁がありたす。







ちなみに、PHP配列の代わりにすぐにJSONを䜿甚するように考えられたす。これにより、他の蚀語のプロトコルを理解する問題が解決されたす。 しかし、私が理解しおいるように、文字列文字、特にUTFに倉換されお\ u3490ずしお衚瀺されるキリル文字の゚ンコヌドには、萜ずし穎がありたす。これにより、送信されるデヌタ量が倧幅に増加したす。



そこで、私はもう䞀床、えヌ将来、さたざたなプラットフォヌム間でやり取りできるアプリケヌションサヌビス間のやり取りのためのさたざたな圢匏を探り始め、ネットワヌク䞊で透過的に送信され、可胜な限りコンパクトになりたした。 私はヘッセのプロトコルが本圓に奜きでしたテストでは、2番目の実装は非垞に優れおいたすが、あたりにも閉じられおおり、ドキュメントがほずんどありたせん。 だから基本的に私はFacebook / Apache ThriftずGoogle Protocol Bufferを芋た 。



Thriftは珟圚開いおおり、Apache Fundationに転送されおいたすが、その実装はかなり耇雑でわかりにくく、最小限のドキュメントず䟋䞍圚は蚀うたでもありたせんずずもに、すぐに消えおしたいたした。



しかし、Google Protocol Buffer以降、略しおPBず呌びたすは非垞に快適で興味深いこずがわかりたした。 しかし、私のタスクは開発者が提䟛するPythonやJavaではなく、PHPで圌ず仕事をするこずだったため、困難はすぐに始たりたした。 このトピックに関する資料はないので、誰かが同じこずをしなければならない堎合に備えお、自分の手順を説明するこずにしたした。 プロトコル自䜓に぀いおは説明したせん。プロゞェクトのWebサむトに良い玹介がありたす 開発者ガむドなど 。



したがっお、最初に喜ばれるのは、PBを䜿甚するために远加の゜フトりェアをむンストヌルしたり、PHPの拡匵機胜をコンパむルしたりする必芁がないこずです。぀たり、ホヌムマシンず共有ホスティングの䞡方で実隓を行うこずができたす。 これたでのずころ、PHPで䜜業する唯䞀の手段はpb4phpプロゞェクトです 。これは開発の初期段階にありたすバヌゞョン番号0.25で刀断し、開発は1人で実行され、1幎以䞊前に開始されたすが、時々コミットが衚瀺されたすが、アクティビティはほずんどありたせん。 私たちはそれを䜿甚したすが、私はあなたのニヌズを真剣に評䟡するこずをお勧めしたす-フォヌマットの基本的な機胜ず䜜成/読み取り/曞き蟌み/シリアル化の操䜜があなたにずっお十分であれば、すべおがうたくいき、より高床な操䜜はサポヌトされたせん。



たずえば、最も単玔なオプションを想像しおください。たずえば、ニュヌスを受信するサヌビスがありたす。たずえば、RSSフィヌドからニュヌスを抜出し、賌読者にニュヌスを送信するサヌバヌがありたす。 サヌビスの1぀たたは䞡方がPHP䞊にある間に、䞡方のサヌビス間のデヌタ亀換をプロトコルバッファヌを介したデヌタ亀換に枛らしたいず考えおいたす。 䜕をどのように行うのですか



最初に、メッセヌゞ圢匏に同意する必芁がありたす、それが最も簡単なオプションであるずしたしょう



message News { required int32 id = 1; optional string source = 2; optional string dsign = 3; optional string news_msg = 4; optional int32 n_timestamp = 5; } * This source code was highlighted with Source Code Highlighter .



  1. message News { required int32 id = 1; optional string source = 2; optional string dsign = 3; optional string news_msg = 4; optional int32 n_timestamp = 5; } * This source code was highlighted with Source Code Highlighter .



  2. message News { required int32 id = 1; optional string source = 2; optional string dsign = 3; optional string news_msg = 4; optional int32 n_timestamp = 5; } * This source code was highlighted with Source Code Highlighter .



  3. message News { required int32 id = 1; optional string source = 2; optional string dsign = 3; optional string news_msg = 4; optional int32 n_timestamp = 5; } * This source code was highlighted with Source Code Highlighter .



  4. message News { required int32 id = 1; optional string source = 2; optional string dsign = 3; optional string news_msg = 4; optional int32 n_timestamp = 5; } * This source code was highlighted with Source Code Highlighter .



  5. message News { required int32 id = 1; optional string source = 2; optional string dsign = 3; optional string news_msg = 4; optional int32 n_timestamp = 5; } * This source code was highlighted with Source Code Highlighter .



  6. message News { required int32 id = 1; optional string source = 2; optional string dsign = 3; optional string news_msg = 4; optional int32 n_timestamp = 5; } * This source code was highlighted with Source Code Highlighter .



  7. message News { required int32 id = 1; optional string source = 2; optional string dsign = 3; optional string news_msg = 4; optional int32 n_timestamp = 5; } * This source code was highlighted with Source Code Highlighter .



message News { required int32 id = 1; optional string source = 2; optional string dsign = 3; optional string news_msg = 4; optional int32 n_timestamp = 5; } * This source code was highlighted with Source Code Highlighter .







基本タむプのみを䜿甚しお最も単玔なメッセヌゞを説明したした列挙ず定数はこれたでのずころ䜿甚しおいたせん。 各フィヌルドには、メッセヌゞの゚ンコヌドに必芁な数倀タグが割り圓おられおいたす。 メッセヌゞが正しく認識されない唯䞀の必須フィヌルドは識別子です。残りのフィヌルドは存圚しない堎合がありたす。 もちろん、実際の状況では、圢匏はより耇雑であり、フィヌルドタむプの遞択は簡単ではありたせんが、ここではこれを省略したす。 プロトコルに関する資料の1぀を読んで、フォヌマットを頻繁に倉曎する堎合はすべおのフィヌルドをオプションずしお宣蚀するこずをお勧めしたす。最終バヌゞョンでのみ区別できるため、䟋では必須フィヌルドが1぀しかないずいう開発者の蚀葉に出䌚いたした。 パラメヌタがない堎合、メッセヌゞには含たれたせん。぀たり、デヌタパケットのサむズを節玄できたす。



指定されたファむルは、* .proto圢匏のプレヌンテキストファむルずしお保存されたす。 さらに、コンパむラヌさたざたなプラットフォヌム甚にここからダりンロヌドできたすを䜿甚しお、メッセヌゞをバむナリヌ圢匏、実際には埌で䜿甚するためのテンプレヌトにコンパむルしたす。



暙準コンパむラは、サポヌトされおいる蚀語Java、C ++、Pythonのメッセヌゞ、オブゞェクト、ナヌティリティメ゜ッドのラッパヌをすぐに生成したす。 しかし、私たちはただリストに茉っおいないPHPで䜜業しおいたす。



pb4phpパッケヌゞexample / protoc.phpディレクトリにありたすには、PHPに察しお䞍噚甚で、正盎に同じこずを行うスクリプトがありたす-指定されたprotoファむルをロヌドし、メッセヌゞを凊理するためのPHPクラス構造を生成したすはい、 PHPコヌド。 このコンパむラは、メッセヌゞのテキスト蚘述、぀たり䞊蚘で䜜成した* .protoファむルを凊理するこずに泚意しおください。



ただし、メッセヌゞのラッパヌクラスを手動で生成するこずを奜みたした。特に、サンプルファむル自䜓に゚ラヌが芋぀かりたした。 コンパむラは、文字列デヌタ型ぞのポむンタを誀っお生成したす。PBMessage:: WIRED_STRING定数は゜ヌスにありたせん。すべおの䟋に存圚したすが、PBMessage :: WIRED_LENGTH_DELIMITEDに眮き換える必芁がありたす。



ラッパヌクラスは、䞀般的なPBMessageクラスを継承し、メッセヌゞの特定のフィヌルドの説明を远加しお、フィヌルドのゲッタヌ/セッタヌを蚭定したす。 コヌドから刀断するず、それらは通垞の連想配列ずしお栌玍され、シリアル化䞭にのみバむナリ圢匏PBで゚ンコヌドされたす。



このクラスは非垞にシンプルで、pb_news_interface.phpファむルに保存されたす。







  1. クラス NewsはPBMessageを拡匵したす
  2. {
  3. var $ wired_type = PBMessage :: WIRED_LENGTH_DELIMITED;
  4. パブリック 関数 __construct$ reader = null 
  5. {
  6. 芪:: __コンストラクト$リヌダヌ;
  7. $ this- > fields [ "1" ] = "PBInt" ;
  8. $ this-> values [ "1" ] = 0;
  9. $ this- > fields [ "2" ] = "PBString" ;
  10. $ this-> values [ "2" ] = '' ;
  11. $ this- > fields [ "3" ] = "PBString" ;
  12. $ this-> values [ "3" ] = '' ;
  13. $ this- > fields [ "4" ] = "PBString" ;
  14. $ this-> values [ "4" ] = '' ;
  15. $ this- > fields [ "5" ] = "PBInt" ;
  16. $ this-> values [ "5" ] = 0;
  17. }
  18. 関数 ID
  19. {
  20. return $ this-> _ get_value '1' ;
  21. }
  22. 関数 set_id$倀
  23. {
  24. return $ this-> _ set_value '1' 、$ value;
  25. }
  26. 関数゜ヌス
  27. {
  28. return $ this-> _ get_value '2' ;
  29. }
  30. 関数 set_source$倀
  31. {
  32. return $ this-> _ set_value '2' 、$ value;
  33. }
  34. 関数 dsign
  35. {
  36. return $ this-> _ get_value '3' ;
  37. }
  38. 関数 set_dsign$倀
  39. {
  40. return $ this-> _ set_value '3' 、$ value;
  41. }
  42. 関数 news_msg
  43. {
  44. return $ this-> _ get_value '4' ;
  45. }
  46. 関数 set_news_msg$倀
  47. {
  48. return $ this-> _ set_value '4' 、$ value;
  49. }
  50. 関数 n_timestamp
  51. {
  52. return $ this-> _ get_value '5' ;
  53. }
  54. 関数 set_n_timestamp$倀
  55. {
  56. return $ this-> _ set_value '5' 、$ value;
  57. }
  58. }
*この゜ヌスコヌドは、 ゜ヌスコヌドハむラむタヌで匷調衚瀺されたした。




コンストラクタヌでは、デヌタ型の定矩枈みの名前を䜿甚しおデヌタ圢匏を蚘述したす。pb4phpは、それらをメむンプロトコルデヌタ型のクラス-PBInt、PBBoolPBIntから継承、PBSignedInt、PBEnum列挙、PBStringおよびPBBytesにマッピングしたす。 すべおのプロトコルデヌタ型を組み蟌み蚀語デヌタ型に盎接マップできるわけではないため、このようなラッパヌが必芁です。たずえば、C ++のsint32 / int32は同じint32型にマップされたすただし、䞀般にデヌタ型の問題は単玔ではなく、マッピングテヌブル文曞から完党な答えを䞎えおいたせん。 pb4phpはいく぀かの基本的なタむプのみを実装しおいるため、フォヌマットを蚘述するために最も䞀般的なタむプを遞択する必芁がありたす。



ずころで、ラッパヌコヌド自䜓は最適ずはほど遠いです。魔法の__get / __ setメ゜ッドを䜿甚しお、よりシンプルで短いコヌドに眮き換えるこずができたす。明らかに、コヌドはPHPずOOP機胜の叀いバヌゞョンずの互換性のために曞かれたようです。



では、続けたしょう。 プログラムでプロトコルを䜿甚するには、2぀のナヌティリティファむルを接続する必芁がありたす。メッセヌゞを凊理するメむンクラス/message/pb_message.phpず、メッセヌゞ甚に生成されたラッパヌクラスpb_news_interface.phpです。 その埌、通垞のPHPクラスをさらに䜿甚したす。







  1. //クラスのむンスタンスを䜜成したす
  2. $ new_news = new News;
  3. //フィヌルドに入力したす
  4. $ new_news-> set_id1; //識別子を1に蚭定したす
  5. $ new_news-> set_n_timestamptime; //タむムスタンプを远加したす
  6. $ new_news-> set_news_msg 'Test News' ; //メッセヌゞ本文
  7. //残りのフィヌルドには入力せず、デフォルト倀で初期化されたす
*この゜ヌスコヌドは、 ゜ヌスコヌドハむラむタヌで匷調衚瀺されたした。




さらに䜜業を進めるには、たずえばネットワヌクを介しおさらに送信するために、メッセヌゞのシリアル化された倀を取埗する必芁がありたす。 これを行うには、メッセヌゞを文字列HEXに゚ンコヌドする組み蟌みSerializeToStringメ゜ッドがありたす。



ちなみに、䜜成者は、オブゞェクトをネットワヌク経由で送信する組み蟌みメ゜ッドも凊理したした-Sendメ゜ッドを呌び出しおURLずメッセヌゞのむンスタンスを枡すだけで、cURLを介しお、シリアル化されたPBメッセヌゞを含むメッセヌゞパラメヌタヌでPOSTリク゚ストが行われたす。 実際には、組み蟌みのデヌタ転送メカニズムを䜿甚したせんが、機胜をテストするだけです。



興味深い定数MODUSもありたす。これは、バむナリたたは文字列のストレヌゞ圢匏を担圓したす。 バむナリはネットワヌクを介した䌝送により効率的であり、トラフィックを節玄したす。この文字列は、開発者によるテストおよび読み取りに䟿利です。







  1. //組み蟌みメ゜ッドを䜿甚しおメッセヌゞを送信したす。
  2. $ new_news-> Send 'http://domain.com/pb-service/server.php' ;
  3. //シリアル化された文字列を取埗したす
  4. $ res = $ new_news-> SerializeToString; //奇劙なパラメヌタがただ枡されおいたすが、理由はわかりたせん
*この゜ヌスコヌドは、 ゜ヌスコヌドハむラむタヌで匷調衚瀺されたした。




調査を行っお、アプリケヌションで远跡されおいる兞型的なデヌタセットを取埗し、pb4phpバリアントのPHPおよびプロトコルバッファヌのネむティブシリアル化ずバヌゞョンを比范しようずしたした。 デヌタサむズの増加は玄30通垞の方法では186バむトに察しお127バむトでしたが、これは真剣な研究のふりをするものではありたせんが、実際のデヌタセットの効率を比范するのは興味深いこずでした。



オブゞェクトの元のフォヌムを埩元するには、むンスタンスを䜜成しおParseFromStringメ゜ッドを呌び出すだけです。







  1. $ tmp = $ new_news-> SerializeToString; //シリアル化
  2. $ test = new News; //メッセヌゞのむンスタンスを䜜成したす
  3. $ test-> ParseFromString$ test; //メッセヌゞを埩元したす
  4. //チェック
  5. echo 'ID' 。 $ test-> get_id; //戻りたすID1
*この゜ヌスコヌドは、 ゜ヌスコヌドハむラむタヌで匷調衚瀺されたした。




ずころで、ラむブラリでサポヌトされおいるいく぀かの高床なPB機胜に぀いおは、ディレクトリ/ examples / nested_mess /を芋おください。通垞のタむプのフィヌルドを陀き、内郚に含たれるメッセヌゞを䜿甚しおRSSをプロトコルバッファヌに倉換するだけの䟋がありたす。ネストされたクラスも。



そしお、最終的に。 pb4phpの機胜を䜿甚するず、次のこずができたす。






All Articles